@cleocode/cleo 2026.4.2 → 2026.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +259 -158
- package/dist/cli/index.js.map +4 -4
- package/package.json +7 -7
package/dist/cli/index.js
CHANGED
|
@@ -25334,7 +25334,7 @@ async function endSession(options = {}, cwd, accessor) {
|
|
|
25334
25334
|
session.endedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
25335
25335
|
const duration3 = Math.floor((Date.now() - new Date(session.startedAt).getTime()) / 1e3);
|
|
25336
25336
|
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
25337
|
-
hooks2.dispatch("SessionEnd", cwd ?? process.cwd(), {
|
|
25337
|
+
await hooks2.dispatch("SessionEnd", cwd ?? process.cwd(), {
|
|
25338
25338
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
25339
25339
|
sessionId: session.id,
|
|
25340
25340
|
duration: duration3,
|
|
@@ -25343,7 +25343,7 @@ async function endSession(options = {}, cwd, accessor) {
|
|
|
25343
25343
|
}).catch(() => {
|
|
25344
25344
|
});
|
|
25345
25345
|
const { bridgeSessionToMemory: bridgeSessionToMemory2 } = await Promise.resolve().then(() => (init_session_memory_bridge(), session_memory_bridge_exports));
|
|
25346
|
-
bridgeSessionToMemory2(cwd ?? process.cwd(), {
|
|
25346
|
+
await bridgeSessionToMemory2(cwd ?? process.cwd(), {
|
|
25347
25347
|
sessionId: session.id,
|
|
25348
25348
|
scope: options.sessionId ? session.scope.type : session.scope.epicId ? `epic:${session.scope.epicId}` : session.scope.type,
|
|
25349
25349
|
tasksCompleted: session.tasksCompleted || [],
|
|
@@ -25356,6 +25356,11 @@ async function endSession(options = {}, cwd, accessor) {
|
|
|
25356
25356
|
}
|
|
25357
25357
|
const acc = accessor ?? await getAccessor(cwd);
|
|
25358
25358
|
await acc.upsertSingleSession(session);
|
|
25359
|
+
try {
|
|
25360
|
+
const { refreshMemoryBridge: refreshMemoryBridge2 } = await Promise.resolve().then(() => (init_memory_bridge(), memory_bridge_exports));
|
|
25361
|
+
await refreshMemoryBridge2(cwd ?? process.cwd());
|
|
25362
|
+
} catch {
|
|
25363
|
+
}
|
|
25359
25364
|
return session;
|
|
25360
25365
|
}
|
|
25361
25366
|
async function sessionStatus(cwd, accessor) {
|
|
@@ -51528,6 +51533,208 @@ var init_complete = __esm({
|
|
|
51528
51533
|
}
|
|
51529
51534
|
});
|
|
51530
51535
|
|
|
51536
|
+
// packages/core/src/validation/validation-rules.ts
|
|
51537
|
+
var validation_rules_exports = {};
|
|
51538
|
+
__export(validation_rules_exports, {
|
|
51539
|
+
hasErrors: () => hasErrors,
|
|
51540
|
+
validateHierarchy: () => validateHierarchy,
|
|
51541
|
+
validateIdUniqueness: () => validateIdUniqueness,
|
|
51542
|
+
validateNewTask: () => validateNewTask,
|
|
51543
|
+
validateNoDuplicateDescription: () => validateNoDuplicateDescription,
|
|
51544
|
+
validateStatusTransition: () => validateStatusTransition,
|
|
51545
|
+
validateTimestamps: () => validateTimestamps,
|
|
51546
|
+
validateTitleDescription: () => validateTitleDescription
|
|
51547
|
+
});
|
|
51548
|
+
function validateTitleDescription(title, description) {
|
|
51549
|
+
const violations = [];
|
|
51550
|
+
if (!title || title.trim().length === 0) {
|
|
51551
|
+
violations.push({
|
|
51552
|
+
rule: "title-required",
|
|
51553
|
+
field: "title",
|
|
51554
|
+
message: "Title is required and cannot be empty",
|
|
51555
|
+
severity: "error"
|
|
51556
|
+
});
|
|
51557
|
+
}
|
|
51558
|
+
if (!description || description.trim().length === 0) {
|
|
51559
|
+
violations.push({
|
|
51560
|
+
rule: "description-required",
|
|
51561
|
+
field: "description",
|
|
51562
|
+
message: "Description is required and cannot be empty",
|
|
51563
|
+
severity: "error"
|
|
51564
|
+
});
|
|
51565
|
+
}
|
|
51566
|
+
if (title && description && title.trim().toLowerCase() === description.trim().toLowerCase()) {
|
|
51567
|
+
violations.push({
|
|
51568
|
+
rule: "title-description-different",
|
|
51569
|
+
field: "description",
|
|
51570
|
+
message: "Title and description must be different",
|
|
51571
|
+
severity: "error"
|
|
51572
|
+
});
|
|
51573
|
+
}
|
|
51574
|
+
return violations;
|
|
51575
|
+
}
|
|
51576
|
+
function validateTimestamps(task) {
|
|
51577
|
+
const violations = [];
|
|
51578
|
+
const now2 = /* @__PURE__ */ new Date();
|
|
51579
|
+
const threshold = new Date(now2.getTime() + 5 * 60 * 1e3);
|
|
51580
|
+
const timestampFields = [
|
|
51581
|
+
["createdAt", task.createdAt],
|
|
51582
|
+
["updatedAt", task.updatedAt],
|
|
51583
|
+
["completedAt", task.completedAt],
|
|
51584
|
+
["cancelledAt", task.cancelledAt]
|
|
51585
|
+
];
|
|
51586
|
+
for (const [field, value] of timestampFields) {
|
|
51587
|
+
if (value) {
|
|
51588
|
+
const date6 = new Date(value);
|
|
51589
|
+
if (Number.isNaN(date6.getTime())) {
|
|
51590
|
+
violations.push({
|
|
51591
|
+
rule: "valid-timestamp",
|
|
51592
|
+
field,
|
|
51593
|
+
message: `Invalid timestamp format: ${value}`,
|
|
51594
|
+
severity: "error"
|
|
51595
|
+
});
|
|
51596
|
+
} else if (date6 > threshold) {
|
|
51597
|
+
violations.push({
|
|
51598
|
+
rule: "no-future-timestamps",
|
|
51599
|
+
field,
|
|
51600
|
+
message: `Timestamp ${value} is in the future`,
|
|
51601
|
+
severity: "error"
|
|
51602
|
+
});
|
|
51603
|
+
}
|
|
51604
|
+
}
|
|
51605
|
+
}
|
|
51606
|
+
return violations;
|
|
51607
|
+
}
|
|
51608
|
+
function validateIdUniqueness(taskId, existingIds) {
|
|
51609
|
+
if (existingIds.has(taskId)) {
|
|
51610
|
+
return [
|
|
51611
|
+
{
|
|
51612
|
+
rule: "unique-id",
|
|
51613
|
+
field: "id",
|
|
51614
|
+
message: `Task ID '${taskId}' already exists`,
|
|
51615
|
+
severity: "error"
|
|
51616
|
+
}
|
|
51617
|
+
];
|
|
51618
|
+
}
|
|
51619
|
+
return [];
|
|
51620
|
+
}
|
|
51621
|
+
function validateNoDuplicateDescription(description, existingDescriptions, _excludeTaskId) {
|
|
51622
|
+
const normalizedNew = description.trim().toLowerCase();
|
|
51623
|
+
for (const existing of existingDescriptions) {
|
|
51624
|
+
if (existing.trim().toLowerCase() === normalizedNew) {
|
|
51625
|
+
return [
|
|
51626
|
+
{
|
|
51627
|
+
rule: "no-duplicate-description",
|
|
51628
|
+
field: "description",
|
|
51629
|
+
message: "A task with this exact description already exists",
|
|
51630
|
+
severity: "warning"
|
|
51631
|
+
}
|
|
51632
|
+
];
|
|
51633
|
+
}
|
|
51634
|
+
}
|
|
51635
|
+
return [];
|
|
51636
|
+
}
|
|
51637
|
+
function validateHierarchy(parentId, tasks2, _taskType, limits) {
|
|
51638
|
+
const violations = [];
|
|
51639
|
+
if (!parentId) {
|
|
51640
|
+
return violations;
|
|
51641
|
+
}
|
|
51642
|
+
const maxDepth = limits?.maxDepth ?? 3;
|
|
51643
|
+
const maxSiblings = limits?.maxSiblings ?? 0;
|
|
51644
|
+
const parent = tasks2.find((t) => t.id === parentId);
|
|
51645
|
+
if (!parent) {
|
|
51646
|
+
violations.push({
|
|
51647
|
+
rule: "parent-exists",
|
|
51648
|
+
field: "parentId",
|
|
51649
|
+
message: `Parent task '${parentId}' not found`,
|
|
51650
|
+
severity: "error"
|
|
51651
|
+
});
|
|
51652
|
+
return violations;
|
|
51653
|
+
}
|
|
51654
|
+
let depth = 1;
|
|
51655
|
+
let current = parent;
|
|
51656
|
+
while (current.parentId) {
|
|
51657
|
+
depth++;
|
|
51658
|
+
const nextParent = tasks2.find((t) => t.id === current.parentId);
|
|
51659
|
+
if (!nextParent) break;
|
|
51660
|
+
current = nextParent;
|
|
51661
|
+
}
|
|
51662
|
+
if (depth > maxDepth - 1) {
|
|
51663
|
+
violations.push({
|
|
51664
|
+
rule: "max-depth",
|
|
51665
|
+
field: "parentId",
|
|
51666
|
+
message: `Maximum hierarchy depth of ${maxDepth} exceeded (epic -> task -> subtask)`,
|
|
51667
|
+
severity: "error"
|
|
51668
|
+
});
|
|
51669
|
+
}
|
|
51670
|
+
const siblingCount = tasks2.filter((t) => t.parentId === parentId).length;
|
|
51671
|
+
if (maxSiblings > 0 && siblingCount >= maxSiblings) {
|
|
51672
|
+
violations.push({
|
|
51673
|
+
rule: "max-siblings",
|
|
51674
|
+
field: "parentId",
|
|
51675
|
+
message: `Parent '${parentId}' already has ${siblingCount} children (max ${maxSiblings})`,
|
|
51676
|
+
severity: "error"
|
|
51677
|
+
});
|
|
51678
|
+
}
|
|
51679
|
+
return violations;
|
|
51680
|
+
}
|
|
51681
|
+
function validateStatusTransition(currentStatus, newStatus) {
|
|
51682
|
+
const validTransitions = {
|
|
51683
|
+
pending: ["active", "blocked", "done", "cancelled"],
|
|
51684
|
+
active: ["pending", "blocked", "done", "cancelled"],
|
|
51685
|
+
blocked: ["pending", "active", "done", "cancelled"],
|
|
51686
|
+
done: ["pending", "active"],
|
|
51687
|
+
// restore (alias: reopen)
|
|
51688
|
+
cancelled: ["pending"]
|
|
51689
|
+
// restore (alias: uncancel)
|
|
51690
|
+
};
|
|
51691
|
+
const allowed = validTransitions[currentStatus];
|
|
51692
|
+
if (!allowed) {
|
|
51693
|
+
return [
|
|
51694
|
+
{
|
|
51695
|
+
rule: "valid-status-transition",
|
|
51696
|
+
field: "status",
|
|
51697
|
+
message: `Unknown current status: '${currentStatus}'`,
|
|
51698
|
+
severity: "error"
|
|
51699
|
+
}
|
|
51700
|
+
];
|
|
51701
|
+
}
|
|
51702
|
+
if (!allowed.includes(newStatus)) {
|
|
51703
|
+
return [
|
|
51704
|
+
{
|
|
51705
|
+
rule: "valid-status-transition",
|
|
51706
|
+
field: "status",
|
|
51707
|
+
message: `Cannot transition from '${currentStatus}' to '${newStatus}'. Valid: ${allowed.join(", ")}`,
|
|
51708
|
+
severity: "error"
|
|
51709
|
+
}
|
|
51710
|
+
];
|
|
51711
|
+
}
|
|
51712
|
+
return [];
|
|
51713
|
+
}
|
|
51714
|
+
function validateNewTask(task, existingIds, existingDescriptions, existingTasks, limits) {
|
|
51715
|
+
const violations = [];
|
|
51716
|
+
violations.push(...validateTitleDescription(task.title, task.description));
|
|
51717
|
+
violations.push(...validateTimestamps(task));
|
|
51718
|
+
if (task.id) {
|
|
51719
|
+
violations.push(...validateIdUniqueness(task.id, existingIds));
|
|
51720
|
+
}
|
|
51721
|
+
if (task.description) {
|
|
51722
|
+
violations.push(...validateNoDuplicateDescription(task.description, existingDescriptions));
|
|
51723
|
+
}
|
|
51724
|
+
if (task.parentId) {
|
|
51725
|
+
violations.push(...validateHierarchy(task.parentId, existingTasks, task.type, limits));
|
|
51726
|
+
}
|
|
51727
|
+
return violations;
|
|
51728
|
+
}
|
|
51729
|
+
function hasErrors(violations) {
|
|
51730
|
+
return violations.some((v) => v.severity === "error");
|
|
51731
|
+
}
|
|
51732
|
+
var init_validation_rules = __esm({
|
|
51733
|
+
"packages/core/src/validation/validation-rules.ts"() {
|
|
51734
|
+
"use strict";
|
|
51735
|
+
}
|
|
51736
|
+
});
|
|
51737
|
+
|
|
51531
51738
|
// packages/core/src/tasks/update.ts
|
|
51532
51739
|
var update_exports = {};
|
|
51533
51740
|
__export(update_exports, {
|
|
@@ -51577,6 +51784,11 @@ async function updateTask(options, cwd, accessor) {
|
|
|
51577
51784
|
}
|
|
51578
51785
|
if (options.status !== void 0) {
|
|
51579
51786
|
validateStatus(options.status);
|
|
51787
|
+
const { validateStatusTransition: validateStatusTransition3 } = await Promise.resolve().then(() => (init_validation_rules(), validation_rules_exports));
|
|
51788
|
+
const transitionViolations = validateStatusTransition3(task.status, options.status);
|
|
51789
|
+
if (transitionViolations.length > 0) {
|
|
51790
|
+
throw new CleoError(6 /* VALIDATION_ERROR */, transitionViolations[0].message);
|
|
51791
|
+
}
|
|
51580
51792
|
const oldStatus = task.status;
|
|
51581
51793
|
task.status = options.status;
|
|
51582
51794
|
changes.push("status");
|
|
@@ -68579,7 +68791,7 @@ function validateCancelReason(reason) {
|
|
|
68579
68791
|
}
|
|
68580
68792
|
return { valid: errors.length === 0, errors, warnings: [] };
|
|
68581
68793
|
}
|
|
68582
|
-
function
|
|
68794
|
+
function validateStatusTransition2(oldStatus, newStatus) {
|
|
68583
68795
|
if (oldStatus === newStatus) {
|
|
68584
68796
|
return { valid: true, errors: [], warnings: [] };
|
|
68585
68797
|
}
|
|
@@ -70038,7 +70250,7 @@ __export(validation_exports, {
|
|
|
70038
70250
|
validatePhaseTimestamps: () => validatePhaseTimestamps,
|
|
70039
70251
|
validateSessionNote: () => validateSessionNote,
|
|
70040
70252
|
validateSingleActivePhase: () => validateSingleActivePhase,
|
|
70041
|
-
validateStatusTransition: () =>
|
|
70253
|
+
validateStatusTransition: () => validateStatusTransition2,
|
|
70042
70254
|
validateTask: () => validateTask,
|
|
70043
70255
|
validateTitle: () => validateTitle2
|
|
70044
70256
|
});
|
|
@@ -72085,6 +72297,7 @@ __export(src_exports, {
|
|
|
72085
72297
|
});
|
|
72086
72298
|
var init_src2 = __esm({
|
|
72087
72299
|
"packages/core/src/index.ts"() {
|
|
72300
|
+
"use strict";
|
|
72088
72301
|
init_src();
|
|
72089
72302
|
init_adapters();
|
|
72090
72303
|
init_admin();
|
|
@@ -81574,149 +81787,6 @@ var init_schema_validator = __esm({
|
|
|
81574
81787
|
}
|
|
81575
81788
|
});
|
|
81576
81789
|
|
|
81577
|
-
// packages/core/src/validation/validation-rules.ts
|
|
81578
|
-
function validateTitleDescription(title, description) {
|
|
81579
|
-
const violations = [];
|
|
81580
|
-
if (!title || title.trim().length === 0) {
|
|
81581
|
-
violations.push({
|
|
81582
|
-
rule: "title-required",
|
|
81583
|
-
field: "title",
|
|
81584
|
-
message: "Title is required and cannot be empty",
|
|
81585
|
-
severity: "error"
|
|
81586
|
-
});
|
|
81587
|
-
}
|
|
81588
|
-
if (!description || description.trim().length === 0) {
|
|
81589
|
-
violations.push({
|
|
81590
|
-
rule: "description-required",
|
|
81591
|
-
field: "description",
|
|
81592
|
-
message: "Description is required and cannot be empty",
|
|
81593
|
-
severity: "error"
|
|
81594
|
-
});
|
|
81595
|
-
}
|
|
81596
|
-
if (title && description && title.trim().toLowerCase() === description.trim().toLowerCase()) {
|
|
81597
|
-
violations.push({
|
|
81598
|
-
rule: "title-description-different",
|
|
81599
|
-
field: "description",
|
|
81600
|
-
message: "Title and description must be different",
|
|
81601
|
-
severity: "error"
|
|
81602
|
-
});
|
|
81603
|
-
}
|
|
81604
|
-
return violations;
|
|
81605
|
-
}
|
|
81606
|
-
function validateTimestamps(task) {
|
|
81607
|
-
const violations = [];
|
|
81608
|
-
const now2 = /* @__PURE__ */ new Date();
|
|
81609
|
-
const threshold = new Date(now2.getTime() + 5 * 60 * 1e3);
|
|
81610
|
-
const timestampFields = [
|
|
81611
|
-
["createdAt", task.createdAt],
|
|
81612
|
-
["updatedAt", task.updatedAt],
|
|
81613
|
-
["completedAt", task.completedAt],
|
|
81614
|
-
["cancelledAt", task.cancelledAt]
|
|
81615
|
-
];
|
|
81616
|
-
for (const [field, value] of timestampFields) {
|
|
81617
|
-
if (value) {
|
|
81618
|
-
const date6 = new Date(value);
|
|
81619
|
-
if (Number.isNaN(date6.getTime())) {
|
|
81620
|
-
violations.push({
|
|
81621
|
-
rule: "valid-timestamp",
|
|
81622
|
-
field,
|
|
81623
|
-
message: `Invalid timestamp format: ${value}`,
|
|
81624
|
-
severity: "error"
|
|
81625
|
-
});
|
|
81626
|
-
} else if (date6 > threshold) {
|
|
81627
|
-
violations.push({
|
|
81628
|
-
rule: "no-future-timestamps",
|
|
81629
|
-
field,
|
|
81630
|
-
message: `Timestamp ${value} is in the future`,
|
|
81631
|
-
severity: "error"
|
|
81632
|
-
});
|
|
81633
|
-
}
|
|
81634
|
-
}
|
|
81635
|
-
}
|
|
81636
|
-
return violations;
|
|
81637
|
-
}
|
|
81638
|
-
function validateIdUniqueness(taskId, existingIds) {
|
|
81639
|
-
if (existingIds.has(taskId)) {
|
|
81640
|
-
return [
|
|
81641
|
-
{
|
|
81642
|
-
rule: "unique-id",
|
|
81643
|
-
field: "id",
|
|
81644
|
-
message: `Task ID '${taskId}' already exists`,
|
|
81645
|
-
severity: "error"
|
|
81646
|
-
}
|
|
81647
|
-
];
|
|
81648
|
-
}
|
|
81649
|
-
return [];
|
|
81650
|
-
}
|
|
81651
|
-
function validateNoDuplicateDescription(description, existingDescriptions, _excludeTaskId) {
|
|
81652
|
-
const normalizedNew = description.trim().toLowerCase();
|
|
81653
|
-
for (const existing of existingDescriptions) {
|
|
81654
|
-
if (existing.trim().toLowerCase() === normalizedNew) {
|
|
81655
|
-
return [
|
|
81656
|
-
{
|
|
81657
|
-
rule: "no-duplicate-description",
|
|
81658
|
-
field: "description",
|
|
81659
|
-
message: "A task with this exact description already exists",
|
|
81660
|
-
severity: "warning"
|
|
81661
|
-
}
|
|
81662
|
-
];
|
|
81663
|
-
}
|
|
81664
|
-
}
|
|
81665
|
-
return [];
|
|
81666
|
-
}
|
|
81667
|
-
function validateHierarchy(parentId, tasks2, _taskType, limits) {
|
|
81668
|
-
const violations = [];
|
|
81669
|
-
if (!parentId) {
|
|
81670
|
-
return violations;
|
|
81671
|
-
}
|
|
81672
|
-
const maxDepth = limits?.maxDepth ?? 3;
|
|
81673
|
-
const maxSiblings = limits?.maxSiblings ?? 0;
|
|
81674
|
-
const parent = tasks2.find((t) => t.id === parentId);
|
|
81675
|
-
if (!parent) {
|
|
81676
|
-
violations.push({
|
|
81677
|
-
rule: "parent-exists",
|
|
81678
|
-
field: "parentId",
|
|
81679
|
-
message: `Parent task '${parentId}' not found`,
|
|
81680
|
-
severity: "error"
|
|
81681
|
-
});
|
|
81682
|
-
return violations;
|
|
81683
|
-
}
|
|
81684
|
-
let depth = 1;
|
|
81685
|
-
let current = parent;
|
|
81686
|
-
while (current.parentId) {
|
|
81687
|
-
depth++;
|
|
81688
|
-
const nextParent = tasks2.find((t) => t.id === current.parentId);
|
|
81689
|
-
if (!nextParent) break;
|
|
81690
|
-
current = nextParent;
|
|
81691
|
-
}
|
|
81692
|
-
if (depth > maxDepth - 1) {
|
|
81693
|
-
violations.push({
|
|
81694
|
-
rule: "max-depth",
|
|
81695
|
-
field: "parentId",
|
|
81696
|
-
message: `Maximum hierarchy depth of ${maxDepth} exceeded (epic -> task -> subtask)`,
|
|
81697
|
-
severity: "error"
|
|
81698
|
-
});
|
|
81699
|
-
}
|
|
81700
|
-
const siblingCount = tasks2.filter((t) => t.parentId === parentId).length;
|
|
81701
|
-
if (maxSiblings > 0 && siblingCount >= maxSiblings) {
|
|
81702
|
-
violations.push({
|
|
81703
|
-
rule: "max-siblings",
|
|
81704
|
-
field: "parentId",
|
|
81705
|
-
message: `Parent '${parentId}' already has ${siblingCount} children (max ${maxSiblings})`,
|
|
81706
|
-
severity: "error"
|
|
81707
|
-
});
|
|
81708
|
-
}
|
|
81709
|
-
return violations;
|
|
81710
|
-
}
|
|
81711
|
-
function hasErrors(violations) {
|
|
81712
|
-
return violations.some((v) => v.severity === "error");
|
|
81713
|
-
}
|
|
81714
|
-
var init_validation_rules = __esm({
|
|
81715
|
-
"packages/core/src/validation/validation-rules.ts"() {
|
|
81716
|
-
"use strict";
|
|
81717
|
-
}
|
|
81718
|
-
});
|
|
81719
|
-
|
|
81720
81790
|
// packages/core/src/validation/validate-ops.ts
|
|
81721
81791
|
import { execFileSync as execFileSync12 } from "node:child_process";
|
|
81722
81792
|
import { appendFileSync as appendFileSync10, existsSync as existsSync120, mkdirSync as mkdirSync25, readFileSync as readFileSync91 } from "node:fs";
|
|
@@ -83588,6 +83658,7 @@ __export(internal_exports, {
|
|
|
83588
83658
|
getOtelSummary: () => getOtelSummary,
|
|
83589
83659
|
getPackageRoot: () => getPackageRoot,
|
|
83590
83660
|
getParallelStatus: () => getParallelStatus,
|
|
83661
|
+
getPipelineStageOrder: () => getPipelineStageOrder,
|
|
83591
83662
|
getProjectInfo: () => getProjectInfo,
|
|
83592
83663
|
getProjectInfoSync: () => getProjectInfoSync,
|
|
83593
83664
|
getProjectRoot: () => getProjectRoot,
|
|
@@ -83667,6 +83738,7 @@ __export(internal_exports, {
|
|
|
83667
83738
|
isLafsSuccess: () => isLafsSuccess,
|
|
83668
83739
|
isNoChangeCode: () => isNoChangeCode,
|
|
83669
83740
|
isOverloaded: () => isOverloaded,
|
|
83741
|
+
isPipelineTransitionForward: () => isPipelineTransitionForward,
|
|
83670
83742
|
isProjectInitialized: () => isProjectInitialized,
|
|
83671
83743
|
isProviderHookEvent: () => isProviderHookEvent,
|
|
83672
83744
|
isRecoverableCode: () => isRecoverableCode,
|
|
@@ -84064,6 +84136,7 @@ var init_internal = __esm({
|
|
|
84064
84136
|
init_add();
|
|
84065
84137
|
init_graph_ops();
|
|
84066
84138
|
init_list3();
|
|
84139
|
+
init_pipeline_stage();
|
|
84067
84140
|
init_relates();
|
|
84068
84141
|
init_task_ops();
|
|
84069
84142
|
init_parser2();
|
|
@@ -88670,6 +88743,19 @@ async function lifecycleProgress(taskId, stage, status, notes, projectRoot) {
|
|
|
88670
88743
|
}
|
|
88671
88744
|
try {
|
|
88672
88745
|
if (status === "in_progress" || status === "completed") {
|
|
88746
|
+
const { getLifecycleStatus: getLifecycleStatus2 } = await Promise.resolve().then(() => (init_internal(), internal_exports));
|
|
88747
|
+
const current = await getLifecycleStatus2(taskId, projectRoot);
|
|
88748
|
+
if (current.currentStage) {
|
|
88749
|
+
const { isPipelineTransitionForward: isPipelineTransitionForward2, getPipelineStageOrder: getPipelineStageOrder2 } = await Promise.resolve().then(() => (init_internal(), internal_exports));
|
|
88750
|
+
if (!isPipelineTransitionForward2(current.currentStage, stage)) {
|
|
88751
|
+
const currentOrder = getPipelineStageOrder2(current.currentStage);
|
|
88752
|
+
const newOrder = getPipelineStageOrder2(stage);
|
|
88753
|
+
return engineError(
|
|
88754
|
+
"E_LIFECYCLE_BACKWARD",
|
|
88755
|
+
`Cannot move backward from "${current.currentStage}" (stage ${currentOrder}) to "${stage}" (stage ${newOrder}). Pipeline stages are forward-only.`
|
|
88756
|
+
);
|
|
88757
|
+
}
|
|
88758
|
+
}
|
|
88673
88759
|
const gateResult = await checkGate(taskId, stage, projectRoot);
|
|
88674
88760
|
if (!gateResult.allowed) {
|
|
88675
88761
|
return engineError("E_LIFECYCLE_GATE_FAILED", gateResult.message);
|
|
@@ -92088,14 +92174,28 @@ function initVerification2() {
|
|
|
92088
92174
|
failureLog: []
|
|
92089
92175
|
};
|
|
92090
92176
|
}
|
|
92091
|
-
function computePassed2(verification) {
|
|
92092
|
-
for (const gate of
|
|
92177
|
+
function computePassed2(verification, requiredGates = DEFAULT_REQUIRED_GATES2) {
|
|
92178
|
+
for (const gate of requiredGates) {
|
|
92093
92179
|
if (verification.gates[gate] !== true) return false;
|
|
92094
92180
|
}
|
|
92095
92181
|
return true;
|
|
92096
92182
|
}
|
|
92097
|
-
function getMissingGates2(verification) {
|
|
92098
|
-
return
|
|
92183
|
+
function getMissingGates2(verification, requiredGates = DEFAULT_REQUIRED_GATES2) {
|
|
92184
|
+
return requiredGates.filter((g) => verification.gates[g] !== true);
|
|
92185
|
+
}
|
|
92186
|
+
async function loadRequiredGates(projectRoot) {
|
|
92187
|
+
try {
|
|
92188
|
+
const { loadConfig: loadConfig4 } = await Promise.resolve().then(() => (init_internal(), internal_exports));
|
|
92189
|
+
const config2 = await loadConfig4(projectRoot);
|
|
92190
|
+
const cfgGates = config2.verification?.requiredGates;
|
|
92191
|
+
if (Array.isArray(cfgGates) && cfgGates.length > 0) {
|
|
92192
|
+
return cfgGates.filter(
|
|
92193
|
+
(g) => DEFAULT_REQUIRED_GATES2.includes(g)
|
|
92194
|
+
);
|
|
92195
|
+
}
|
|
92196
|
+
} catch {
|
|
92197
|
+
}
|
|
92198
|
+
return [...DEFAULT_REQUIRED_GATES2];
|
|
92099
92199
|
}
|
|
92100
92200
|
async function validateGateVerify(params, projectRoot) {
|
|
92101
92201
|
try {
|
|
@@ -92110,9 +92210,10 @@ async function validateGateVerify(params, projectRoot) {
|
|
|
92110
92210
|
if (!task) {
|
|
92111
92211
|
return engineError("E_NOT_FOUND", `Task ${taskId} not found`);
|
|
92112
92212
|
}
|
|
92213
|
+
const configGates = await loadRequiredGates(root);
|
|
92113
92214
|
if (!gate && !all && !reset) {
|
|
92114
92215
|
const verification2 = task.verification ?? initVerification2();
|
|
92115
|
-
const missing2 = getMissingGates2(verification2);
|
|
92216
|
+
const missing2 = getMissingGates2(verification2, configGates);
|
|
92116
92217
|
return {
|
|
92117
92218
|
success: true,
|
|
92118
92219
|
data: {
|
|
@@ -92124,7 +92225,7 @@ async function validateGateVerify(params, projectRoot) {
|
|
|
92124
92225
|
verificationStatus: verification2.passed ? "passed" : "pending",
|
|
92125
92226
|
passed: verification2.passed,
|
|
92126
92227
|
round: verification2.round,
|
|
92127
|
-
requiredGates:
|
|
92228
|
+
requiredGates: configGates,
|
|
92128
92229
|
missingGates: missing2,
|
|
92129
92230
|
action: "view"
|
|
92130
92231
|
}
|
|
@@ -92137,7 +92238,7 @@ async function validateGateVerify(params, projectRoot) {
|
|
|
92137
92238
|
verification = initVerification2();
|
|
92138
92239
|
action = "reset";
|
|
92139
92240
|
} else if (all) {
|
|
92140
|
-
for (const g of
|
|
92241
|
+
for (const g of configGates) {
|
|
92141
92242
|
verification.gates[g] = true;
|
|
92142
92243
|
}
|
|
92143
92244
|
if (agent) {
|
|
@@ -92168,11 +92269,11 @@ async function validateGateVerify(params, projectRoot) {
|
|
|
92168
92269
|
}
|
|
92169
92270
|
action = "set_gate";
|
|
92170
92271
|
}
|
|
92171
|
-
verification.passed = computePassed2(verification);
|
|
92272
|
+
verification.passed = computePassed2(verification, configGates);
|
|
92172
92273
|
task.verification = verification;
|
|
92173
92274
|
task.updatedAt = now2;
|
|
92174
92275
|
await accessor.upsertSingleTask(task);
|
|
92175
|
-
const missing = getMissingGates2(verification);
|
|
92276
|
+
const missing = getMissingGates2(verification, configGates);
|
|
92176
92277
|
const result = {
|
|
92177
92278
|
taskId,
|
|
92178
92279
|
title: task.title,
|
|
@@ -92182,14 +92283,14 @@ async function validateGateVerify(params, projectRoot) {
|
|
|
92182
92283
|
verificationStatus: verification.passed ? "passed" : "pending",
|
|
92183
92284
|
passed: verification.passed,
|
|
92184
92285
|
round: verification.round,
|
|
92185
|
-
requiredGates:
|
|
92286
|
+
requiredGates: configGates,
|
|
92186
92287
|
missingGates: missing,
|
|
92187
92288
|
action
|
|
92188
92289
|
};
|
|
92189
92290
|
if (action === "set_gate") {
|
|
92190
92291
|
result.gateSet = gate;
|
|
92191
92292
|
} else if (action === "set_all") {
|
|
92192
|
-
result.gatesSet =
|
|
92293
|
+
result.gatesSet = configGates;
|
|
92193
92294
|
}
|
|
92194
92295
|
return { success: true, data: result };
|
|
92195
92296
|
} catch (err) {
|