@cleocode/cleo 2026.3.73 → 2026.3.74
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 +1181 -829
- package/dist/cli/index.js.map +4 -4
- package/dist/mcp/index.js +2244 -1945
- package/dist/mcp/index.js.map +4 -4
- package/package.json +3 -3
package/dist/cli/index.js
CHANGED
|
@@ -9,6 +9,55 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name2, { get: all[name2], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
// packages/cleo/src/cli/field-context.ts
|
|
13
|
+
import {
|
|
14
|
+
resolveFieldExtraction
|
|
15
|
+
} from "@cleocode/lafs-protocol";
|
|
16
|
+
function setFieldContext(ctx) {
|
|
17
|
+
currentContext = ctx;
|
|
18
|
+
}
|
|
19
|
+
function getFieldContext() {
|
|
20
|
+
return currentContext;
|
|
21
|
+
}
|
|
22
|
+
function resolveFieldContext(opts) {
|
|
23
|
+
const input = {
|
|
24
|
+
fieldFlag: typeof opts["field"] === "string" ? opts["field"] : void 0,
|
|
25
|
+
fieldsFlag: typeof opts["fields"] === "string" ? opts["fields"] : void 0,
|
|
26
|
+
mviFlag: typeof opts["mvi"] === "string" ? opts["mvi"] : void 0
|
|
27
|
+
};
|
|
28
|
+
return resolveFieldExtraction(input);
|
|
29
|
+
}
|
|
30
|
+
var currentContext;
|
|
31
|
+
var init_field_context = __esm({
|
|
32
|
+
"packages/cleo/src/cli/field-context.ts"() {
|
|
33
|
+
"use strict";
|
|
34
|
+
currentContext = {
|
|
35
|
+
mvi: "standard",
|
|
36
|
+
mviSource: "default",
|
|
37
|
+
expectsCustomMvi: false
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// packages/cleo/src/cli/format-context.ts
|
|
43
|
+
function setFormatContext(resolution) {
|
|
44
|
+
currentResolution = resolution;
|
|
45
|
+
}
|
|
46
|
+
function getFormatContext() {
|
|
47
|
+
return currentResolution;
|
|
48
|
+
}
|
|
49
|
+
var currentResolution;
|
|
50
|
+
var init_format_context = __esm({
|
|
51
|
+
"packages/cleo/src/cli/format-context.ts"() {
|
|
52
|
+
"use strict";
|
|
53
|
+
currentResolution = {
|
|
54
|
+
format: "json",
|
|
55
|
+
source: "default",
|
|
56
|
+
quiet: false
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
12
61
|
// packages/contracts/src/errors.ts
|
|
13
62
|
function normalizeError(error40, fallbackMessage = "An unexpected error occurred") {
|
|
14
63
|
if (error40 instanceof Error) {
|
|
@@ -632,6 +681,13 @@ var init_discovery = __esm({
|
|
|
632
681
|
});
|
|
633
682
|
|
|
634
683
|
// packages/core/src/logger.ts
|
|
684
|
+
var logger_exports = {};
|
|
685
|
+
__export(logger_exports, {
|
|
686
|
+
closeLogger: () => closeLogger,
|
|
687
|
+
getLogDir: () => getLogDir,
|
|
688
|
+
getLogger: () => getLogger,
|
|
689
|
+
initLogger: () => initLogger
|
|
690
|
+
});
|
|
635
691
|
import { existsSync as existsSync2 } from "node:fs";
|
|
636
692
|
import { dirname, join as join3 } from "node:path";
|
|
637
693
|
import pino from "pino";
|
|
@@ -45251,8 +45307,8 @@ var init_checksum = __esm({
|
|
|
45251
45307
|
});
|
|
45252
45308
|
|
|
45253
45309
|
// packages/core/src/migration/logger.ts
|
|
45254
|
-
var
|
|
45255
|
-
__export(
|
|
45310
|
+
var logger_exports2 = {};
|
|
45311
|
+
__export(logger_exports2, {
|
|
45256
45312
|
MigrationLogger: () => MigrationLogger,
|
|
45257
45313
|
createMigrationLogger: () => createMigrationLogger,
|
|
45258
45314
|
getLatestMigrationLog: () => getLatestMigrationLog,
|
|
@@ -48205,6 +48261,903 @@ var init_transfer = __esm({
|
|
|
48205
48261
|
}
|
|
48206
48262
|
});
|
|
48207
48263
|
|
|
48264
|
+
// packages/core/src/task-work/index.ts
|
|
48265
|
+
var task_work_exports = {};
|
|
48266
|
+
__export(task_work_exports, {
|
|
48267
|
+
currentTask: () => currentTask,
|
|
48268
|
+
getTaskHistory: () => getTaskHistory,
|
|
48269
|
+
getWorkHistory: () => getWorkHistory,
|
|
48270
|
+
startTask: () => startTask,
|
|
48271
|
+
stopTask: () => stopTask
|
|
48272
|
+
});
|
|
48273
|
+
async function currentTask(cwd, accessor) {
|
|
48274
|
+
const acc = accessor ?? await getAccessor(cwd);
|
|
48275
|
+
const focus = await acc.getMetaValue("focus_state");
|
|
48276
|
+
return {
|
|
48277
|
+
currentTask: focus?.currentTask ?? null,
|
|
48278
|
+
currentPhase: focus?.currentPhase ?? null,
|
|
48279
|
+
sessionNote: focus?.sessionNote ?? null,
|
|
48280
|
+
nextAction: focus?.nextAction ?? null
|
|
48281
|
+
};
|
|
48282
|
+
}
|
|
48283
|
+
async function startTask(taskId, cwd, accessor) {
|
|
48284
|
+
if (!taskId) {
|
|
48285
|
+
throw new CleoError(2 /* INVALID_INPUT */, "Task ID is required");
|
|
48286
|
+
}
|
|
48287
|
+
const acc = accessor ?? await getAccessor(cwd);
|
|
48288
|
+
const task = await acc.loadSingleTask(taskId);
|
|
48289
|
+
if (!task) {
|
|
48290
|
+
throw new CleoError(4 /* NOT_FOUND */, `Task not found: ${taskId}`, {
|
|
48291
|
+
fix: `Use 'cleo find "${taskId}"' to search`
|
|
48292
|
+
});
|
|
48293
|
+
}
|
|
48294
|
+
const { tasks: allTasks } = await acc.queryTasks({});
|
|
48295
|
+
const unresolvedDeps = getUnresolvedDeps(taskId, allTasks);
|
|
48296
|
+
if (unresolvedDeps.length > 0) {
|
|
48297
|
+
throw new CleoError(
|
|
48298
|
+
5 /* DEPENDENCY_ERROR */,
|
|
48299
|
+
`Task ${taskId} is blocked by unresolved dependencies: ${unresolvedDeps.join(", ")}`,
|
|
48300
|
+
{
|
|
48301
|
+
fix: `Complete blockers first: ${unresolvedDeps.map((d) => `cleo complete ${d}`).join(", ")}`
|
|
48302
|
+
}
|
|
48303
|
+
);
|
|
48304
|
+
}
|
|
48305
|
+
const focus = await acc.getMetaValue("focus_state") ?? {};
|
|
48306
|
+
const previousTask = focus.currentTask ?? null;
|
|
48307
|
+
focus.currentTask = taskId;
|
|
48308
|
+
focus.currentPhase = task.phase ?? null;
|
|
48309
|
+
const noteEntry = {
|
|
48310
|
+
note: `Started work on ${taskId}: ${task.title}`,
|
|
48311
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
48312
|
+
};
|
|
48313
|
+
if (!focus.sessionNotes) {
|
|
48314
|
+
focus.sessionNotes = [];
|
|
48315
|
+
}
|
|
48316
|
+
focus.sessionNotes.push(noteEntry);
|
|
48317
|
+
await acc.setMetaValue("focus_state", focus);
|
|
48318
|
+
await logOperation(
|
|
48319
|
+
"task_start",
|
|
48320
|
+
taskId,
|
|
48321
|
+
{
|
|
48322
|
+
previousTask,
|
|
48323
|
+
title: task.title
|
|
48324
|
+
},
|
|
48325
|
+
accessor
|
|
48326
|
+
);
|
|
48327
|
+
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
48328
|
+
hooks2.dispatch("PreToolUse", cwd ?? process.cwd(), {
|
|
48329
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
48330
|
+
taskId,
|
|
48331
|
+
taskTitle: task.title
|
|
48332
|
+
}).catch(() => {
|
|
48333
|
+
});
|
|
48334
|
+
return {
|
|
48335
|
+
taskId,
|
|
48336
|
+
taskTitle: task.title,
|
|
48337
|
+
previousTask
|
|
48338
|
+
};
|
|
48339
|
+
}
|
|
48340
|
+
async function stopTask(cwd, accessor) {
|
|
48341
|
+
const acc = accessor ?? await getAccessor(cwd);
|
|
48342
|
+
const focus = await acc.getMetaValue("focus_state");
|
|
48343
|
+
const previousTask = focus?.currentTask ?? null;
|
|
48344
|
+
if (!focus) {
|
|
48345
|
+
return { previousTask: null };
|
|
48346
|
+
}
|
|
48347
|
+
const taskId = focus.currentTask;
|
|
48348
|
+
const task = taskId ? await acc.loadSingleTask(taskId) : void 0;
|
|
48349
|
+
focus.currentTask = null;
|
|
48350
|
+
focus.nextAction = null;
|
|
48351
|
+
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
48352
|
+
if (taskId && task) {
|
|
48353
|
+
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
48354
|
+
hooks2.dispatch("PostToolUse", cwd ?? process.cwd(), {
|
|
48355
|
+
timestamp: now2,
|
|
48356
|
+
taskId,
|
|
48357
|
+
taskTitle: task.title,
|
|
48358
|
+
status: "done"
|
|
48359
|
+
}).catch(() => {
|
|
48360
|
+
});
|
|
48361
|
+
}
|
|
48362
|
+
await acc.setMetaValue("focus_state", focus);
|
|
48363
|
+
await logOperation(
|
|
48364
|
+
"task_stop",
|
|
48365
|
+
previousTask ?? "none",
|
|
48366
|
+
{
|
|
48367
|
+
previousTask
|
|
48368
|
+
},
|
|
48369
|
+
accessor
|
|
48370
|
+
);
|
|
48371
|
+
return { previousTask };
|
|
48372
|
+
}
|
|
48373
|
+
async function getWorkHistory(cwd, accessor) {
|
|
48374
|
+
const acc = accessor ?? await getAccessor(cwd);
|
|
48375
|
+
const focus = await acc.getMetaValue("focus_state");
|
|
48376
|
+
const notes = focus?.sessionNotes ?? [];
|
|
48377
|
+
const history = [];
|
|
48378
|
+
for (const note of notes) {
|
|
48379
|
+
const match = note.note.match(/^(?:Focus set to|Started work on) (T\d+)/);
|
|
48380
|
+
if (match) {
|
|
48381
|
+
history.push({
|
|
48382
|
+
taskId: match[1],
|
|
48383
|
+
timestamp: note.timestamp
|
|
48384
|
+
});
|
|
48385
|
+
}
|
|
48386
|
+
}
|
|
48387
|
+
return history.reverse();
|
|
48388
|
+
}
|
|
48389
|
+
var getTaskHistory;
|
|
48390
|
+
var init_task_work = __esm({
|
|
48391
|
+
"packages/core/src/task-work/index.ts"() {
|
|
48392
|
+
"use strict";
|
|
48393
|
+
init_src();
|
|
48394
|
+
init_errors3();
|
|
48395
|
+
init_data_accessor();
|
|
48396
|
+
init_add();
|
|
48397
|
+
init_dependency_check();
|
|
48398
|
+
init_handlers();
|
|
48399
|
+
getTaskHistory = getWorkHistory;
|
|
48400
|
+
}
|
|
48401
|
+
});
|
|
48402
|
+
|
|
48403
|
+
// packages/core/src/tasks/complete.ts
|
|
48404
|
+
var complete_exports = {};
|
|
48405
|
+
__export(complete_exports, {
|
|
48406
|
+
completeTask: () => completeTask
|
|
48407
|
+
});
|
|
48408
|
+
function isVerificationGate(value) {
|
|
48409
|
+
return VERIFICATION_GATES.has(value);
|
|
48410
|
+
}
|
|
48411
|
+
async function loadCompletionEnforcement(cwd) {
|
|
48412
|
+
const isTest = !!process.env.VITEST;
|
|
48413
|
+
const config2 = await loadConfig(cwd);
|
|
48414
|
+
const acceptance = config2.enforcement?.acceptance;
|
|
48415
|
+
const verificationCfg = config2.verification;
|
|
48416
|
+
const acceptanceMode = acceptance?.mode ?? (isTest ? "off" : "block");
|
|
48417
|
+
const acceptanceRequiredForPriorities = acceptance?.requiredForPriorities ?? (isTest ? [] : ["critical", "high", "medium", "low"]);
|
|
48418
|
+
const rawVerificationEnabled = await getRawConfigValue("verification.enabled", cwd);
|
|
48419
|
+
const verificationEnabled = rawVerificationEnabled !== void 0 ? rawVerificationEnabled : !isTest;
|
|
48420
|
+
const verificationRequiredGates = (verificationCfg?.requiredGates ?? []).filter(isVerificationGate).length > 0 ? (verificationCfg?.requiredGates ?? []).filter(isVerificationGate) : DEFAULT_VERIFICATION_REQUIRED_GATES;
|
|
48421
|
+
const verificationMaxRounds = verificationCfg?.maxRounds ?? 5;
|
|
48422
|
+
const lifecycleMode = config2.lifecycle?.mode ?? (isTest ? "off" : "strict");
|
|
48423
|
+
return {
|
|
48424
|
+
acceptanceMode,
|
|
48425
|
+
acceptanceRequiredForPriorities,
|
|
48426
|
+
verificationEnabled,
|
|
48427
|
+
verificationRequiredGates,
|
|
48428
|
+
verificationMaxRounds,
|
|
48429
|
+
lifecycleMode
|
|
48430
|
+
};
|
|
48431
|
+
}
|
|
48432
|
+
async function completeTask(options, cwd, accessor) {
|
|
48433
|
+
const acc = accessor ?? await getAccessor(cwd);
|
|
48434
|
+
const task = await acc.loadSingleTask(options.taskId);
|
|
48435
|
+
if (!task) {
|
|
48436
|
+
throw new CleoError(4 /* NOT_FOUND */, `Task not found: ${options.taskId}`, {
|
|
48437
|
+
fix: `Use 'cleo find "${options.taskId}"' to search`
|
|
48438
|
+
});
|
|
48439
|
+
}
|
|
48440
|
+
await requireActiveSession("tasks.complete", cwd);
|
|
48441
|
+
const enforcement = await loadCompletionEnforcement(cwd);
|
|
48442
|
+
if (task.status === "done") {
|
|
48443
|
+
throw new CleoError(17 /* TASK_COMPLETED */, `Task ${options.taskId} is already completed`);
|
|
48444
|
+
}
|
|
48445
|
+
if (task.depends?.length) {
|
|
48446
|
+
const deps = await acc.loadTasks(task.depends);
|
|
48447
|
+
const incompleteDeps = deps.filter((d) => d.status !== "done" && d.status !== "cancelled").map((d) => d.id);
|
|
48448
|
+
if (incompleteDeps.length > 0) {
|
|
48449
|
+
throw new CleoError(
|
|
48450
|
+
5 /* DEPENDENCY_ERROR */,
|
|
48451
|
+
`Task ${options.taskId} has incomplete dependencies: ${incompleteDeps.join(", ")}`,
|
|
48452
|
+
{
|
|
48453
|
+
fix: `Complete dependencies first: ${incompleteDeps.map((d) => `cleo complete ${d}`).join(", ")}`
|
|
48454
|
+
}
|
|
48455
|
+
);
|
|
48456
|
+
}
|
|
48457
|
+
}
|
|
48458
|
+
const acceptanceEnforcement = await createAcceptanceEnforcement(cwd);
|
|
48459
|
+
const completionValidation = acceptanceEnforcement.validateCompletion(task);
|
|
48460
|
+
if (!completionValidation.valid) {
|
|
48461
|
+
throw new CleoError(
|
|
48462
|
+
completionValidation.exitCode ?? 6 /* VALIDATION_ERROR */,
|
|
48463
|
+
completionValidation.error,
|
|
48464
|
+
{ fix: completionValidation.fix }
|
|
48465
|
+
);
|
|
48466
|
+
}
|
|
48467
|
+
if (enforcement.verificationEnabled && task.type !== "epic") {
|
|
48468
|
+
if (!task.verification) {
|
|
48469
|
+
throw new CleoError(
|
|
48470
|
+
40 /* VERIFICATION_INIT_FAILED */,
|
|
48471
|
+
`Task ${options.taskId} is missing verification metadata`,
|
|
48472
|
+
{
|
|
48473
|
+
fix: `Initialize verification for ${options.taskId} before completion`
|
|
48474
|
+
}
|
|
48475
|
+
);
|
|
48476
|
+
}
|
|
48477
|
+
if (task.verification.round > enforcement.verificationMaxRounds) {
|
|
48478
|
+
throw new CleoError(
|
|
48479
|
+
44 /* MAX_ROUNDS_EXCEEDED */,
|
|
48480
|
+
`Task ${options.taskId} exceeded verification max rounds (${enforcement.verificationMaxRounds})`,
|
|
48481
|
+
{
|
|
48482
|
+
fix: `Review failure log and resolve blockers before retrying completion`
|
|
48483
|
+
}
|
|
48484
|
+
);
|
|
48485
|
+
}
|
|
48486
|
+
const missingRequiredGates = enforcement.verificationRequiredGates.filter(
|
|
48487
|
+
(gate) => task.verification?.gates?.[gate] !== true
|
|
48488
|
+
);
|
|
48489
|
+
if (missingRequiredGates.length > 0 || task.verification.passed !== true) {
|
|
48490
|
+
const exitCode = enforcement.lifecycleMode === "strict" ? 80 /* LIFECYCLE_GATE_FAILED */ : 45 /* GATE_DEPENDENCY */;
|
|
48491
|
+
throw new CleoError(
|
|
48492
|
+
exitCode,
|
|
48493
|
+
`Task ${options.taskId} failed verification gates: ${missingRequiredGates.join(", ") || "verification.passed=false"}`,
|
|
48494
|
+
{
|
|
48495
|
+
fix: `Set required verification gates before completion: ${enforcement.verificationRequiredGates.join(", ")}`
|
|
48496
|
+
}
|
|
48497
|
+
);
|
|
48498
|
+
}
|
|
48499
|
+
}
|
|
48500
|
+
const children = await acc.getChildren(options.taskId);
|
|
48501
|
+
const incompleteChildren = children.filter(
|
|
48502
|
+
(c) => c.status !== "done" && c.status !== "cancelled"
|
|
48503
|
+
);
|
|
48504
|
+
if (incompleteChildren.length > 0 && task.type === "epic") {
|
|
48505
|
+
if (!task.noAutoComplete) {
|
|
48506
|
+
throw new CleoError(
|
|
48507
|
+
16 /* HAS_CHILDREN */,
|
|
48508
|
+
`Epic ${options.taskId} has ${incompleteChildren.length} incomplete children: ${incompleteChildren.map((c) => c.id).join(", ")}`,
|
|
48509
|
+
{
|
|
48510
|
+
fix: `Complete children first or use 'cleo update ${options.taskId} --no-auto-complete'`
|
|
48511
|
+
}
|
|
48512
|
+
);
|
|
48513
|
+
}
|
|
48514
|
+
}
|
|
48515
|
+
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
48516
|
+
const before = { ...task };
|
|
48517
|
+
task.status = "done";
|
|
48518
|
+
task.completedAt = now2;
|
|
48519
|
+
task.updatedAt = now2;
|
|
48520
|
+
if (options.notes) {
|
|
48521
|
+
const timestampedNote = `${(/* @__PURE__ */ new Date()).toISOString().replace("T", " ").replace(/\.\d+Z$/, " UTC")}: ${options.notes}`;
|
|
48522
|
+
if (!task.notes) task.notes = [];
|
|
48523
|
+
task.notes.push(timestampedNote);
|
|
48524
|
+
}
|
|
48525
|
+
if (options.changeset) {
|
|
48526
|
+
if (!task.notes) task.notes = [];
|
|
48527
|
+
task.notes.push(`Changeset: ${options.changeset}`);
|
|
48528
|
+
}
|
|
48529
|
+
const autoCompleted = [];
|
|
48530
|
+
const autoCompletedTasks = [];
|
|
48531
|
+
if (task.parentId) {
|
|
48532
|
+
const parent = await acc.loadSingleTask(task.parentId);
|
|
48533
|
+
if (parent && parent.type === "epic" && !parent.noAutoComplete) {
|
|
48534
|
+
const siblings = await acc.getChildren(parent.id);
|
|
48535
|
+
const allDone = siblings.every(
|
|
48536
|
+
(c) => c.id === task.id || c.status === "done" || c.status === "cancelled"
|
|
48537
|
+
);
|
|
48538
|
+
if (allDone) {
|
|
48539
|
+
parent.status = "done";
|
|
48540
|
+
parent.completedAt = now2;
|
|
48541
|
+
parent.updatedAt = now2;
|
|
48542
|
+
autoCompleted.push(parent.id);
|
|
48543
|
+
autoCompletedTasks.push(parent);
|
|
48544
|
+
}
|
|
48545
|
+
}
|
|
48546
|
+
}
|
|
48547
|
+
await acc.transaction(async (tx) => {
|
|
48548
|
+
await tx.upsertSingleTask(task);
|
|
48549
|
+
for (const parentTask of autoCompletedTasks) {
|
|
48550
|
+
await tx.upsertSingleTask(parentTask);
|
|
48551
|
+
}
|
|
48552
|
+
await tx.appendLog({
|
|
48553
|
+
id: `log-${Math.floor(Date.now() / 1e3)}-${(await import("node:crypto")).randomBytes(3).toString("hex")}`,
|
|
48554
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
48555
|
+
action: "task_completed",
|
|
48556
|
+
taskId: options.taskId,
|
|
48557
|
+
actor: "system",
|
|
48558
|
+
details: { title: task.title, previousStatus: before.status },
|
|
48559
|
+
before: null,
|
|
48560
|
+
after: { title: task.title, previousStatus: before.status }
|
|
48561
|
+
});
|
|
48562
|
+
});
|
|
48563
|
+
const dependents = await acc.getDependents(options.taskId);
|
|
48564
|
+
const unblockedTasks = [];
|
|
48565
|
+
for (const dep of dependents) {
|
|
48566
|
+
if (dep.status === "done" || dep.status === "cancelled") continue;
|
|
48567
|
+
if (dep.depends?.length) {
|
|
48568
|
+
const depDeps = await acc.loadTasks(dep.depends);
|
|
48569
|
+
const stillUnresolved = depDeps.filter(
|
|
48570
|
+
(d) => d.id !== options.taskId && d.status !== "done" && d.status !== "cancelled"
|
|
48571
|
+
);
|
|
48572
|
+
if (stillUnresolved.length === 0) {
|
|
48573
|
+
unblockedTasks.push({ id: dep.id, title: dep.title });
|
|
48574
|
+
}
|
|
48575
|
+
} else {
|
|
48576
|
+
unblockedTasks.push({ id: dep.id, title: dep.title });
|
|
48577
|
+
}
|
|
48578
|
+
}
|
|
48579
|
+
Promise.resolve().then(() => (init_auto_extract(), auto_extract_exports)).then(
|
|
48580
|
+
({ extractTaskCompletionMemory: extractTaskCompletionMemory2 }) => extractTaskCompletionMemory2(cwd ?? process.cwd(), task)
|
|
48581
|
+
).catch(() => {
|
|
48582
|
+
});
|
|
48583
|
+
return {
|
|
48584
|
+
task,
|
|
48585
|
+
...autoCompleted.length > 0 && { autoCompleted },
|
|
48586
|
+
...unblockedTasks.length > 0 && { unblockedTasks }
|
|
48587
|
+
};
|
|
48588
|
+
}
|
|
48589
|
+
var DEFAULT_VERIFICATION_REQUIRED_GATES, VERIFICATION_GATES;
|
|
48590
|
+
var init_complete = __esm({
|
|
48591
|
+
"packages/core/src/tasks/complete.ts"() {
|
|
48592
|
+
"use strict";
|
|
48593
|
+
init_src();
|
|
48594
|
+
init_config();
|
|
48595
|
+
init_errors3();
|
|
48596
|
+
init_session_enforcement();
|
|
48597
|
+
init_data_accessor();
|
|
48598
|
+
init_enforcement();
|
|
48599
|
+
DEFAULT_VERIFICATION_REQUIRED_GATES = [
|
|
48600
|
+
"implemented",
|
|
48601
|
+
"testsPassed",
|
|
48602
|
+
"qaPassed",
|
|
48603
|
+
"securityPassed",
|
|
48604
|
+
"documented"
|
|
48605
|
+
];
|
|
48606
|
+
VERIFICATION_GATES = /* @__PURE__ */ new Set([
|
|
48607
|
+
"implemented",
|
|
48608
|
+
"testsPassed",
|
|
48609
|
+
"qaPassed",
|
|
48610
|
+
"cleanupDone",
|
|
48611
|
+
"securityPassed",
|
|
48612
|
+
"documented"
|
|
48613
|
+
]);
|
|
48614
|
+
}
|
|
48615
|
+
});
|
|
48616
|
+
|
|
48617
|
+
// packages/core/src/tasks/update.ts
|
|
48618
|
+
var update_exports = {};
|
|
48619
|
+
__export(update_exports, {
|
|
48620
|
+
updateTask: () => updateTask
|
|
48621
|
+
});
|
|
48622
|
+
function hasNonStatusDoneFields(options) {
|
|
48623
|
+
return NON_STATUS_DONE_FIELDS.some((field) => options[field] !== void 0);
|
|
48624
|
+
}
|
|
48625
|
+
async function updateTask(options, cwd, accessor) {
|
|
48626
|
+
const acc = accessor ?? await getAccessor(cwd);
|
|
48627
|
+
const task = await acc.loadSingleTask(options.taskId);
|
|
48628
|
+
if (!task) {
|
|
48629
|
+
throw new CleoError(4 /* NOT_FOUND */, `Task not found: ${options.taskId}`, {
|
|
48630
|
+
fix: `Use 'cleo find "${options.taskId}"' to search`
|
|
48631
|
+
});
|
|
48632
|
+
}
|
|
48633
|
+
await requireActiveSession("tasks.update", cwd);
|
|
48634
|
+
const changes = [];
|
|
48635
|
+
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
48636
|
+
const isStatusOnlyDoneTransition = options.status === "done" && task.status !== "done" && !hasNonStatusDoneFields(options);
|
|
48637
|
+
if (isStatusOnlyDoneTransition) {
|
|
48638
|
+
const result = await completeTask({ taskId: options.taskId }, cwd, accessor);
|
|
48639
|
+
return { task: result.task, changes: ["status"] };
|
|
48640
|
+
}
|
|
48641
|
+
if (options.status === "done" && task.status !== "done") {
|
|
48642
|
+
throw new CleoError(
|
|
48643
|
+
6 /* VALIDATION_ERROR */,
|
|
48644
|
+
"status=done must use complete flow; do not combine with other update fields",
|
|
48645
|
+
{
|
|
48646
|
+
fix: `Run 'cleo complete ${options.taskId}' first, then apply additional updates with 'cleo update ${options.taskId} ...'`
|
|
48647
|
+
}
|
|
48648
|
+
);
|
|
48649
|
+
}
|
|
48650
|
+
const enforcement = await createAcceptanceEnforcement(cwd);
|
|
48651
|
+
const updateValidation = enforcement.validateUpdate(task, { acceptance: options.acceptance });
|
|
48652
|
+
if (!updateValidation.valid) {
|
|
48653
|
+
throw new CleoError(
|
|
48654
|
+
updateValidation.exitCode ?? 6 /* VALIDATION_ERROR */,
|
|
48655
|
+
updateValidation.error,
|
|
48656
|
+
{ fix: updateValidation.fix }
|
|
48657
|
+
);
|
|
48658
|
+
}
|
|
48659
|
+
if (options.title !== void 0) {
|
|
48660
|
+
validateTitle(options.title);
|
|
48661
|
+
task.title = options.title;
|
|
48662
|
+
changes.push("title");
|
|
48663
|
+
}
|
|
48664
|
+
if (options.status !== void 0) {
|
|
48665
|
+
validateStatus(options.status);
|
|
48666
|
+
const oldStatus = task.status;
|
|
48667
|
+
task.status = options.status;
|
|
48668
|
+
changes.push("status");
|
|
48669
|
+
if (options.status === "done" && oldStatus !== "done") {
|
|
48670
|
+
task.completedAt = now2;
|
|
48671
|
+
}
|
|
48672
|
+
if (options.status === "cancelled" && oldStatus !== "cancelled") {
|
|
48673
|
+
task.cancelledAt = now2;
|
|
48674
|
+
}
|
|
48675
|
+
}
|
|
48676
|
+
if (options.priority !== void 0) {
|
|
48677
|
+
const normalizedPriority = normalizePriority(options.priority);
|
|
48678
|
+
task.priority = normalizedPriority;
|
|
48679
|
+
changes.push("priority");
|
|
48680
|
+
}
|
|
48681
|
+
if (options.type !== void 0) {
|
|
48682
|
+
validateTaskType(options.type);
|
|
48683
|
+
task.type = options.type;
|
|
48684
|
+
changes.push("type");
|
|
48685
|
+
}
|
|
48686
|
+
if (options.size !== void 0) {
|
|
48687
|
+
validateSize(options.size);
|
|
48688
|
+
task.size = options.size;
|
|
48689
|
+
changes.push("size");
|
|
48690
|
+
}
|
|
48691
|
+
if (options.phase !== void 0) {
|
|
48692
|
+
task.phase = options.phase;
|
|
48693
|
+
changes.push("phase");
|
|
48694
|
+
}
|
|
48695
|
+
if (options.description !== void 0) {
|
|
48696
|
+
task.description = options.description;
|
|
48697
|
+
changes.push("description");
|
|
48698
|
+
}
|
|
48699
|
+
if (options.labels !== void 0) {
|
|
48700
|
+
if (options.labels.length) validateLabels(options.labels);
|
|
48701
|
+
task.labels = options.labels;
|
|
48702
|
+
changes.push("labels");
|
|
48703
|
+
}
|
|
48704
|
+
if (options.addLabels?.length) {
|
|
48705
|
+
validateLabels(options.addLabels);
|
|
48706
|
+
const existing = new Set(task.labels ?? []);
|
|
48707
|
+
for (const l of options.addLabels) existing.add(l.trim());
|
|
48708
|
+
task.labels = [...existing];
|
|
48709
|
+
changes.push("labels");
|
|
48710
|
+
}
|
|
48711
|
+
if (options.removeLabels?.length) {
|
|
48712
|
+
const toRemove = new Set(options.removeLabels.map((l) => l.trim()));
|
|
48713
|
+
task.labels = (task.labels ?? []).filter((l) => !toRemove.has(l));
|
|
48714
|
+
changes.push("labels");
|
|
48715
|
+
}
|
|
48716
|
+
if (options.depends !== void 0) {
|
|
48717
|
+
task.depends = options.depends;
|
|
48718
|
+
changes.push("depends");
|
|
48719
|
+
}
|
|
48720
|
+
if (options.addDepends?.length) {
|
|
48721
|
+
const existing = new Set(task.depends ?? []);
|
|
48722
|
+
for (const d of options.addDepends) existing.add(d.trim());
|
|
48723
|
+
task.depends = [...existing];
|
|
48724
|
+
changes.push("depends");
|
|
48725
|
+
}
|
|
48726
|
+
if (options.removeDepends?.length) {
|
|
48727
|
+
const toRemove = new Set(options.removeDepends.map((d) => d.trim()));
|
|
48728
|
+
task.depends = (task.depends ?? []).filter((d) => !toRemove.has(d));
|
|
48729
|
+
changes.push("depends");
|
|
48730
|
+
}
|
|
48731
|
+
if (options.notes !== void 0) {
|
|
48732
|
+
const timestampedNote = `${(/* @__PURE__ */ new Date()).toISOString().replace("T", " ").replace(/\.\d+Z$/, " UTC")}: ${options.notes}`;
|
|
48733
|
+
if (!task.notes) task.notes = [];
|
|
48734
|
+
task.notes.push(timestampedNote);
|
|
48735
|
+
changes.push("notes");
|
|
48736
|
+
}
|
|
48737
|
+
if (options.acceptance !== void 0) {
|
|
48738
|
+
task.acceptance = options.acceptance;
|
|
48739
|
+
changes.push("acceptance");
|
|
48740
|
+
}
|
|
48741
|
+
if (options.files !== void 0) {
|
|
48742
|
+
task.files = options.files;
|
|
48743
|
+
changes.push("files");
|
|
48744
|
+
}
|
|
48745
|
+
if (options.blockedBy !== void 0) {
|
|
48746
|
+
task.blockedBy = options.blockedBy;
|
|
48747
|
+
changes.push("blockedBy");
|
|
48748
|
+
}
|
|
48749
|
+
if (options.noAutoComplete !== void 0) {
|
|
48750
|
+
task.noAutoComplete = options.noAutoComplete;
|
|
48751
|
+
changes.push("noAutoComplete");
|
|
48752
|
+
}
|
|
48753
|
+
if (options.pipelineStage !== void 0) {
|
|
48754
|
+
validatePipelineTransition(task.pipelineStage, options.pipelineStage);
|
|
48755
|
+
if (task.type === "epic" && task.pipelineStage) {
|
|
48756
|
+
await validateEpicStageAdvancement(
|
|
48757
|
+
{
|
|
48758
|
+
epicId: task.id,
|
|
48759
|
+
currentStage: task.pipelineStage,
|
|
48760
|
+
newStage: options.pipelineStage
|
|
48761
|
+
},
|
|
48762
|
+
acc,
|
|
48763
|
+
cwd
|
|
48764
|
+
);
|
|
48765
|
+
}
|
|
48766
|
+
if (task.type !== "epic") {
|
|
48767
|
+
const epicAncestor = task.parentId ? await findEpicAncestor(task.parentId, acc) : null;
|
|
48768
|
+
const directParent = task.parentId ? await acc.loadSingleTask(task.parentId) : null;
|
|
48769
|
+
const epicToCheck = directParent?.type === "epic" ? directParent : epicAncestor;
|
|
48770
|
+
if (epicToCheck) {
|
|
48771
|
+
await validateChildStageCeiling(
|
|
48772
|
+
{ childStage: options.pipelineStage, epicId: epicToCheck.id },
|
|
48773
|
+
acc,
|
|
48774
|
+
cwd
|
|
48775
|
+
);
|
|
48776
|
+
}
|
|
48777
|
+
}
|
|
48778
|
+
task.pipelineStage = options.pipelineStage;
|
|
48779
|
+
changes.push("pipelineStage");
|
|
48780
|
+
}
|
|
48781
|
+
if (options.parentId !== void 0) {
|
|
48782
|
+
const newParentId = options.parentId || null;
|
|
48783
|
+
const currentParentId = task.parentId ?? null;
|
|
48784
|
+
if (newParentId !== currentParentId) {
|
|
48785
|
+
const originalType = task.type;
|
|
48786
|
+
if (!newParentId) {
|
|
48787
|
+
task.parentId = null;
|
|
48788
|
+
if (task.type === "subtask") task.type = "task";
|
|
48789
|
+
changes.push("parentId");
|
|
48790
|
+
if (task.type !== originalType) changes.push("type");
|
|
48791
|
+
} else {
|
|
48792
|
+
const newParent = await acc.loadSingleTask(newParentId);
|
|
48793
|
+
if (!newParent) {
|
|
48794
|
+
throw new CleoError(10 /* PARENT_NOT_FOUND */, `Parent task ${newParentId} not found`);
|
|
48795
|
+
}
|
|
48796
|
+
if (newParent.type === "subtask") {
|
|
48797
|
+
throw new CleoError(
|
|
48798
|
+
13 /* INVALID_PARENT_TYPE */,
|
|
48799
|
+
`Cannot parent under subtask '${newParentId}'`
|
|
48800
|
+
);
|
|
48801
|
+
}
|
|
48802
|
+
const subtree = await acc.getSubtree(options.taskId);
|
|
48803
|
+
if (subtree.some((t) => t.id === newParentId)) {
|
|
48804
|
+
throw new CleoError(
|
|
48805
|
+
14 /* CIRCULAR_REFERENCE */,
|
|
48806
|
+
`Moving '${options.taskId}' under '${newParentId}' would create a circular reference`
|
|
48807
|
+
);
|
|
48808
|
+
}
|
|
48809
|
+
const ancestors = await acc.getAncestorChain(newParentId);
|
|
48810
|
+
const parentDepth = ancestors.length;
|
|
48811
|
+
const config2 = await loadConfig(cwd);
|
|
48812
|
+
const policy = resolveHierarchyPolicy(config2);
|
|
48813
|
+
if (parentDepth + 1 >= policy.maxDepth) {
|
|
48814
|
+
throw new CleoError(
|
|
48815
|
+
11 /* DEPTH_EXCEEDED */,
|
|
48816
|
+
`Maximum nesting depth ${policy.maxDepth} would be exceeded`
|
|
48817
|
+
);
|
|
48818
|
+
}
|
|
48819
|
+
task.parentId = newParentId;
|
|
48820
|
+
const newDepth = parentDepth + 1;
|
|
48821
|
+
if (newDepth === 1) task.type = "task";
|
|
48822
|
+
else if (newDepth >= 2) task.type = "subtask";
|
|
48823
|
+
changes.push("parentId");
|
|
48824
|
+
if (task.type !== originalType) changes.push("type");
|
|
48825
|
+
}
|
|
48826
|
+
}
|
|
48827
|
+
}
|
|
48828
|
+
if (changes.length === 0) {
|
|
48829
|
+
throw new CleoError(102 /* NO_CHANGE */, "No changes specified");
|
|
48830
|
+
}
|
|
48831
|
+
task.updatedAt = now2;
|
|
48832
|
+
await acc.transaction(async (tx) => {
|
|
48833
|
+
await tx.upsertSingleTask(task);
|
|
48834
|
+
await tx.appendLog({
|
|
48835
|
+
id: `log-${Math.floor(Date.now() / 1e3)}-${(await import("node:crypto")).randomBytes(3).toString("hex")}`,
|
|
48836
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
48837
|
+
action: "task_updated",
|
|
48838
|
+
taskId: options.taskId,
|
|
48839
|
+
actor: "system",
|
|
48840
|
+
details: { changes, title: task.title },
|
|
48841
|
+
before: null,
|
|
48842
|
+
after: { changes, title: task.title }
|
|
48843
|
+
});
|
|
48844
|
+
});
|
|
48845
|
+
return { task, changes };
|
|
48846
|
+
}
|
|
48847
|
+
var NON_STATUS_DONE_FIELDS;
|
|
48848
|
+
var init_update2 = __esm({
|
|
48849
|
+
"packages/core/src/tasks/update.ts"() {
|
|
48850
|
+
"use strict";
|
|
48851
|
+
init_src();
|
|
48852
|
+
init_config();
|
|
48853
|
+
init_errors3();
|
|
48854
|
+
init_session_enforcement();
|
|
48855
|
+
init_data_accessor();
|
|
48856
|
+
init_add();
|
|
48857
|
+
init_complete();
|
|
48858
|
+
init_enforcement();
|
|
48859
|
+
init_epic_enforcement();
|
|
48860
|
+
init_hierarchy_policy();
|
|
48861
|
+
init_pipeline_stage();
|
|
48862
|
+
NON_STATUS_DONE_FIELDS = [
|
|
48863
|
+
"title",
|
|
48864
|
+
"priority",
|
|
48865
|
+
"type",
|
|
48866
|
+
"size",
|
|
48867
|
+
"phase",
|
|
48868
|
+
"description",
|
|
48869
|
+
"labels",
|
|
48870
|
+
"addLabels",
|
|
48871
|
+
"removeLabels",
|
|
48872
|
+
"depends",
|
|
48873
|
+
"addDepends",
|
|
48874
|
+
"removeDepends",
|
|
48875
|
+
"notes",
|
|
48876
|
+
"acceptance",
|
|
48877
|
+
"files",
|
|
48878
|
+
"blockedBy",
|
|
48879
|
+
"parentId",
|
|
48880
|
+
"noAutoComplete",
|
|
48881
|
+
"pipelineStage"
|
|
48882
|
+
];
|
|
48883
|
+
}
|
|
48884
|
+
});
|
|
48885
|
+
|
|
48886
|
+
// packages/core/src/nexus/workspace.ts
|
|
48887
|
+
function checkRateLimit(agentId) {
|
|
48888
|
+
const now2 = Date.now();
|
|
48889
|
+
const entry = rateLimitCounters.get(agentId);
|
|
48890
|
+
if (!entry || now2 - entry.windowStart > RATE_LIMIT_WINDOW_MS) {
|
|
48891
|
+
rateLimitCounters.set(agentId, { count: 1, windowStart: now2 });
|
|
48892
|
+
return;
|
|
48893
|
+
}
|
|
48894
|
+
entry.count++;
|
|
48895
|
+
if (entry.count > RATE_LIMIT_MAX_OPS) {
|
|
48896
|
+
throw new CleoError(
|
|
48897
|
+
1 /* GENERAL_ERROR */,
|
|
48898
|
+
`Agent '${agentId}' exceeded rate limit: ${RATE_LIMIT_MAX_OPS} routing ops per ${RATE_LIMIT_WINDOW_MS / 1e3}s`
|
|
48899
|
+
);
|
|
48900
|
+
}
|
|
48901
|
+
}
|
|
48902
|
+
async function loadProjectACL(projectPath) {
|
|
48903
|
+
try {
|
|
48904
|
+
const { loadConfig: loadConfig4 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
48905
|
+
const config2 = await loadConfig4(projectPath);
|
|
48906
|
+
const agents = config2?.authorizedAgents;
|
|
48907
|
+
if (Array.isArray(agents) && agents.length > 0) {
|
|
48908
|
+
return { authorizedAgents: agents };
|
|
48909
|
+
}
|
|
48910
|
+
} catch {
|
|
48911
|
+
}
|
|
48912
|
+
return DEFAULT_ACL;
|
|
48913
|
+
}
|
|
48914
|
+
function isAuthorized(acl, agentId) {
|
|
48915
|
+
if (acl.authorizedAgents.includes("*")) return true;
|
|
48916
|
+
return acl.authorizedAgents.includes(agentId);
|
|
48917
|
+
}
|
|
48918
|
+
function parseDirective(message) {
|
|
48919
|
+
const content = message.content;
|
|
48920
|
+
const verbMatch = content.match(/^\/(\w+)/);
|
|
48921
|
+
if (!verbMatch) return null;
|
|
48922
|
+
const verb = verbMatch[1];
|
|
48923
|
+
const taskRefs = [];
|
|
48924
|
+
const pattern = new RegExp(TASK_REF_PATTERN.source, "g");
|
|
48925
|
+
for (const m of content.matchAll(pattern)) {
|
|
48926
|
+
taskRefs.push(`T${m[1]}`);
|
|
48927
|
+
}
|
|
48928
|
+
const metaRefs = message.metadata?.taskRefs;
|
|
48929
|
+
if (Array.isArray(metaRefs)) {
|
|
48930
|
+
for (const ref of metaRefs) {
|
|
48931
|
+
if (typeof ref === "string" && !taskRefs.includes(ref)) {
|
|
48932
|
+
taskRefs.push(ref);
|
|
48933
|
+
}
|
|
48934
|
+
}
|
|
48935
|
+
}
|
|
48936
|
+
if (taskRefs.length === 0) return null;
|
|
48937
|
+
return {
|
|
48938
|
+
verb,
|
|
48939
|
+
taskRefs,
|
|
48940
|
+
agentId: message.from,
|
|
48941
|
+
messageId: message.id,
|
|
48942
|
+
timestamp: message.timestamp
|
|
48943
|
+
};
|
|
48944
|
+
}
|
|
48945
|
+
async function routeDirective(directive) {
|
|
48946
|
+
checkRateLimit(directive.agentId);
|
|
48947
|
+
const results = [];
|
|
48948
|
+
const operation = VERB_TO_OPERATION[directive.verb];
|
|
48949
|
+
if (!operation) {
|
|
48950
|
+
return results;
|
|
48951
|
+
}
|
|
48952
|
+
const projects = await nexusList();
|
|
48953
|
+
for (const taskRef of directive.taskRefs) {
|
|
48954
|
+
const result = await routeSingleTask(taskRef, directive, operation, projects);
|
|
48955
|
+
results.push(result);
|
|
48956
|
+
}
|
|
48957
|
+
return results;
|
|
48958
|
+
}
|
|
48959
|
+
async function routeSingleTask(taskId, directive, operation, projects) {
|
|
48960
|
+
let targetProject = null;
|
|
48961
|
+
let targetAccessor = null;
|
|
48962
|
+
for (const project of projects) {
|
|
48963
|
+
try {
|
|
48964
|
+
const acc = await getAccessor(project.path);
|
|
48965
|
+
const { tasks: tasks2 } = await acc.queryTasks({});
|
|
48966
|
+
const task = tasks2.find((t) => t.id === taskId);
|
|
48967
|
+
if (task) {
|
|
48968
|
+
targetProject = project;
|
|
48969
|
+
targetAccessor = acc;
|
|
48970
|
+
break;
|
|
48971
|
+
}
|
|
48972
|
+
} catch {
|
|
48973
|
+
}
|
|
48974
|
+
}
|
|
48975
|
+
if (!targetProject || !targetAccessor) {
|
|
48976
|
+
return {
|
|
48977
|
+
success: false,
|
|
48978
|
+
project: "unknown",
|
|
48979
|
+
projectPath: "",
|
|
48980
|
+
taskId,
|
|
48981
|
+
operation,
|
|
48982
|
+
error: `Task ${taskId} not found in any registered project`
|
|
48983
|
+
};
|
|
48984
|
+
}
|
|
48985
|
+
const acl = await loadProjectACL(targetProject.path);
|
|
48986
|
+
if (!isAuthorized(acl, directive.agentId)) {
|
|
48987
|
+
return {
|
|
48988
|
+
success: false,
|
|
48989
|
+
project: targetProject.name,
|
|
48990
|
+
projectPath: targetProject.path,
|
|
48991
|
+
taskId,
|
|
48992
|
+
operation,
|
|
48993
|
+
error: `Agent '${directive.agentId}' not authorized to mutate project '${targetProject.name}'`
|
|
48994
|
+
};
|
|
48995
|
+
}
|
|
48996
|
+
try {
|
|
48997
|
+
await executeOperation(operation, taskId, targetProject.path, targetAccessor, directive);
|
|
48998
|
+
await logRouteAudit(directive, targetProject.name, taskId, operation, true);
|
|
48999
|
+
return {
|
|
49000
|
+
success: true,
|
|
49001
|
+
project: targetProject.name,
|
|
49002
|
+
projectPath: targetProject.path,
|
|
49003
|
+
taskId,
|
|
49004
|
+
operation
|
|
49005
|
+
};
|
|
49006
|
+
} catch (err) {
|
|
49007
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
49008
|
+
await logRouteAudit(directive, targetProject.name, taskId, operation, false, errorMsg);
|
|
49009
|
+
return {
|
|
49010
|
+
success: false,
|
|
49011
|
+
project: targetProject.name,
|
|
49012
|
+
projectPath: targetProject.path,
|
|
49013
|
+
taskId,
|
|
49014
|
+
operation,
|
|
49015
|
+
error: errorMsg
|
|
49016
|
+
};
|
|
49017
|
+
}
|
|
49018
|
+
}
|
|
49019
|
+
async function executeOperation(operation, taskId, projectPath, accessor, directive) {
|
|
49020
|
+
switch (operation) {
|
|
49021
|
+
case "tasks.start": {
|
|
49022
|
+
const { startTask: startTask3 } = await Promise.resolve().then(() => (init_task_work(), task_work_exports));
|
|
49023
|
+
await startTask3(taskId, projectPath, accessor);
|
|
49024
|
+
break;
|
|
49025
|
+
}
|
|
49026
|
+
case "tasks.complete": {
|
|
49027
|
+
const { completeTask: completeTask2 } = await Promise.resolve().then(() => (init_complete(), complete_exports));
|
|
49028
|
+
await completeTask2(
|
|
49029
|
+
{ taskId, notes: `Completed via Conduit directive from ${directive.agentId}` },
|
|
49030
|
+
projectPath,
|
|
49031
|
+
accessor
|
|
49032
|
+
);
|
|
49033
|
+
break;
|
|
49034
|
+
}
|
|
49035
|
+
case "tasks.stop": {
|
|
49036
|
+
const { stopTask: stopTask3 } = await Promise.resolve().then(() => (init_task_work(), task_work_exports));
|
|
49037
|
+
await stopTask3(projectPath, accessor);
|
|
49038
|
+
break;
|
|
49039
|
+
}
|
|
49040
|
+
case "tasks.update": {
|
|
49041
|
+
const { updateTask: updateTask3 } = await Promise.resolve().then(() => (init_update2(), update_exports));
|
|
49042
|
+
await updateTask3(
|
|
49043
|
+
{ taskId, notes: `Marked blocked via Conduit directive from ${directive.agentId}` },
|
|
49044
|
+
projectPath,
|
|
49045
|
+
accessor
|
|
49046
|
+
);
|
|
49047
|
+
break;
|
|
49048
|
+
}
|
|
49049
|
+
}
|
|
49050
|
+
}
|
|
49051
|
+
async function logRouteAudit(directive, projectName, taskId, operation, success2, error40) {
|
|
49052
|
+
try {
|
|
49053
|
+
const { getLogger: getLogger2 } = await Promise.resolve().then(() => (init_logger(), logger_exports));
|
|
49054
|
+
const log11 = getLogger2("nexus.route");
|
|
49055
|
+
const level = success2 ? "info" : "warn";
|
|
49056
|
+
log11[level](
|
|
49057
|
+
{
|
|
49058
|
+
directive: directive.verb,
|
|
49059
|
+
agentId: directive.agentId,
|
|
49060
|
+
messageId: directive.messageId,
|
|
49061
|
+
project: projectName,
|
|
49062
|
+
taskId,
|
|
49063
|
+
operation,
|
|
49064
|
+
success: success2,
|
|
49065
|
+
error: error40
|
|
49066
|
+
},
|
|
49067
|
+
`Conduit directive routed: ${directive.verb} ${taskId} \u2192 ${projectName} (${success2 ? "OK" : "FAILED"})`
|
|
49068
|
+
);
|
|
49069
|
+
} catch {
|
|
49070
|
+
}
|
|
49071
|
+
}
|
|
49072
|
+
async function workspaceStatus() {
|
|
49073
|
+
const projects = await nexusList();
|
|
49074
|
+
const summaries = [];
|
|
49075
|
+
const totals = { pending: 0, active: 0, done: 0, total: 0 };
|
|
49076
|
+
for (const project of projects) {
|
|
49077
|
+
try {
|
|
49078
|
+
const acc = await getAccessor(project.path);
|
|
49079
|
+
const { tasks: tasks2 } = await acc.queryTasks({});
|
|
49080
|
+
const counts2 = {
|
|
49081
|
+
pending: tasks2.filter((t) => t.status === "pending").length,
|
|
49082
|
+
active: tasks2.filter((t) => t.status === "active").length,
|
|
49083
|
+
done: tasks2.filter((t) => t.status === "done").length,
|
|
49084
|
+
total: tasks2.length
|
|
49085
|
+
};
|
|
49086
|
+
summaries.push({
|
|
49087
|
+
name: project.name,
|
|
49088
|
+
path: project.path,
|
|
49089
|
+
counts: counts2,
|
|
49090
|
+
health: project.healthStatus,
|
|
49091
|
+
lastSync: project.lastSync
|
|
49092
|
+
});
|
|
49093
|
+
totals.pending += counts2.pending;
|
|
49094
|
+
totals.active += counts2.active;
|
|
49095
|
+
totals.done += counts2.done;
|
|
49096
|
+
totals.total += counts2.total;
|
|
49097
|
+
} catch {
|
|
49098
|
+
summaries.push({
|
|
49099
|
+
name: project.name,
|
|
49100
|
+
path: project.path,
|
|
49101
|
+
counts: { pending: 0, active: 0, done: 0, total: 0 },
|
|
49102
|
+
health: "unreachable",
|
|
49103
|
+
lastSync: project.lastSync
|
|
49104
|
+
});
|
|
49105
|
+
}
|
|
49106
|
+
}
|
|
49107
|
+
return {
|
|
49108
|
+
projectCount: projects.length,
|
|
49109
|
+
projects: summaries,
|
|
49110
|
+
totals,
|
|
49111
|
+
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
49112
|
+
};
|
|
49113
|
+
}
|
|
49114
|
+
async function workspaceAgents() {
|
|
49115
|
+
const projects = await nexusList();
|
|
49116
|
+
const agents = [];
|
|
49117
|
+
for (const project of projects) {
|
|
49118
|
+
try {
|
|
49119
|
+
const { listAgentInstances: listAgentInstances2 } = await Promise.resolve().then(() => (init_registry2(), registry_exports2));
|
|
49120
|
+
const instances = await listAgentInstances2(void 0, project.path);
|
|
49121
|
+
for (const inst of instances) {
|
|
49122
|
+
agents.push({
|
|
49123
|
+
agentId: inst.id,
|
|
49124
|
+
agentType: inst.agentType,
|
|
49125
|
+
status: inst.status,
|
|
49126
|
+
project: project.name,
|
|
49127
|
+
taskId: inst.taskId ?? null,
|
|
49128
|
+
lastHeartbeat: inst.lastHeartbeat
|
|
49129
|
+
});
|
|
49130
|
+
}
|
|
49131
|
+
} catch {
|
|
49132
|
+
}
|
|
49133
|
+
}
|
|
49134
|
+
return agents;
|
|
49135
|
+
}
|
|
49136
|
+
var RATE_LIMIT_WINDOW_MS, RATE_LIMIT_MAX_OPS, rateLimitCounters, DEFAULT_ACL, TASK_REF_PATTERN, VERB_TO_OPERATION;
|
|
49137
|
+
var init_workspace = __esm({
|
|
49138
|
+
"packages/core/src/nexus/workspace.ts"() {
|
|
49139
|
+
"use strict";
|
|
49140
|
+
init_src();
|
|
49141
|
+
init_errors3();
|
|
49142
|
+
init_data_accessor();
|
|
49143
|
+
init_registry3();
|
|
49144
|
+
RATE_LIMIT_WINDOW_MS = 6e4;
|
|
49145
|
+
RATE_LIMIT_MAX_OPS = 100;
|
|
49146
|
+
rateLimitCounters = /* @__PURE__ */ new Map();
|
|
49147
|
+
DEFAULT_ACL = { authorizedAgents: ["*"] };
|
|
49148
|
+
TASK_REF_PATTERN = /\bT(\d+)\b/g;
|
|
49149
|
+
VERB_TO_OPERATION = {
|
|
49150
|
+
claim: "tasks.start",
|
|
49151
|
+
done: "tasks.complete",
|
|
49152
|
+
complete: "tasks.complete",
|
|
49153
|
+
blocked: "tasks.update",
|
|
49154
|
+
// Update status to blocked
|
|
49155
|
+
start: "tasks.start",
|
|
49156
|
+
stop: "tasks.stop"
|
|
49157
|
+
};
|
|
49158
|
+
}
|
|
49159
|
+
});
|
|
49160
|
+
|
|
48208
49161
|
// packages/core/src/nexus/index.ts
|
|
48209
49162
|
var nexus_exports = {};
|
|
48210
49163
|
__export(nexus_exports, {
|
|
@@ -48239,6 +49192,7 @@ __export(nexus_exports, {
|
|
|
48239
49192
|
nexusSyncAll: () => nexusSyncAll,
|
|
48240
49193
|
nexusUnregister: () => nexusUnregister,
|
|
48241
49194
|
orphanDetection: () => orphanDetection,
|
|
49195
|
+
parseDirective: () => parseDirective,
|
|
48242
49196
|
parseQuery: () => parseQuery,
|
|
48243
49197
|
permissionLevel: () => permissionLevel,
|
|
48244
49198
|
previewTransfer: () => previewTransfer,
|
|
@@ -48249,10 +49203,13 @@ __export(nexus_exports, {
|
|
|
48249
49203
|
resolveCrossDeps: () => resolveCrossDeps,
|
|
48250
49204
|
resolveProjectPath: () => resolveProjectPath2,
|
|
48251
49205
|
resolveTask: () => resolveTask,
|
|
49206
|
+
routeDirective: () => routeDirective,
|
|
48252
49207
|
searchAcrossProjects: () => searchAcrossProjects,
|
|
48253
49208
|
setPermission: () => setPermission,
|
|
48254
49209
|
syncGitignore: () => syncGitignore,
|
|
48255
|
-
validateSyntax: () => validateSyntax
|
|
49210
|
+
validateSyntax: () => validateSyntax,
|
|
49211
|
+
workspaceAgents: () => workspaceAgents,
|
|
49212
|
+
workspaceStatus: () => workspaceStatus
|
|
48256
49213
|
});
|
|
48257
49214
|
var init_nexus = __esm({
|
|
48258
49215
|
"packages/core/src/nexus/index.ts"() {
|
|
@@ -48265,6 +49222,7 @@ var init_nexus = __esm({
|
|
|
48265
49222
|
init_registry3();
|
|
48266
49223
|
init_sharing();
|
|
48267
49224
|
init_transfer();
|
|
49225
|
+
init_workspace();
|
|
48268
49226
|
}
|
|
48269
49227
|
});
|
|
48270
49228
|
|
|
@@ -49606,676 +50564,197 @@ async function advancePhase(force = false, _cwd, accessor) {
|
|
|
49606
50564
|
6 /* VALIDATION_ERROR */,
|
|
49607
50565
|
`Cannot advance - ${criticalTasks.length} critical task(s) remain in phase '${currentSlug}'`
|
|
49608
50566
|
);
|
|
49609
|
-
}
|
|
49610
|
-
const totalTasks = phaseTasks.length;
|
|
49611
|
-
const completionPercent = totalTasks > 0 ? Math.floor((totalTasks - incompleteTasks.length) * 100 / totalTasks) : 0;
|
|
49612
|
-
const threshold = 90;
|
|
49613
|
-
if (completionPercent < threshold && !force) {
|
|
49614
|
-
throw new CleoError(
|
|
49615
|
-
6 /* VALIDATION_ERROR */,
|
|
49616
|
-
`Cannot advance - ${incompleteTasks.length} incomplete task(s) in phase '${currentSlug}' (${completionPercent}% complete, threshold: ${threshold}%)`,
|
|
49617
|
-
{ fix: "Use --force to override" }
|
|
49618
|
-
);
|
|
49619
|
-
}
|
|
49620
|
-
}
|
|
49621
|
-
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
49622
|
-
currentPhase.status = "completed";
|
|
49623
|
-
currentPhase.completedAt = now2;
|
|
49624
|
-
const nextPhase = phases[nextSlug];
|
|
49625
|
-
nextPhase.status = "active";
|
|
49626
|
-
nextPhase.startedAt = now2;
|
|
49627
|
-
const updatedMeta = meta;
|
|
49628
|
-
updatedMeta.currentPhase = nextSlug;
|
|
49629
|
-
const currentPhaseTaskCount = phaseTasks.length;
|
|
49630
|
-
const { tasks: nextPhaseTasks } = await accessor.queryTasks({ phase: nextSlug });
|
|
49631
|
-
const nextPhaseTaskCount = nextPhaseTasks.length;
|
|
49632
|
-
addPhaseHistoryEntryToMeta(
|
|
49633
|
-
updatedMeta,
|
|
49634
|
-
currentSlug,
|
|
49635
|
-
"completed",
|
|
49636
|
-
null,
|
|
49637
|
-
"Phase completed via advance",
|
|
49638
|
-
currentPhaseTaskCount
|
|
49639
|
-
);
|
|
49640
|
-
addPhaseHistoryEntryToMeta(
|
|
49641
|
-
updatedMeta,
|
|
49642
|
-
nextSlug,
|
|
49643
|
-
"started",
|
|
49644
|
-
currentSlug,
|
|
49645
|
-
`Phase started via advance from ${currentSlug}`,
|
|
49646
|
-
nextPhaseTaskCount
|
|
49647
|
-
);
|
|
49648
|
-
await accessor.setMetaValue("project_meta", updatedMeta);
|
|
49649
|
-
return {
|
|
49650
|
-
previousPhase: currentSlug,
|
|
49651
|
-
currentPhase: nextSlug,
|
|
49652
|
-
forced: force
|
|
49653
|
-
};
|
|
49654
|
-
}
|
|
49655
|
-
async function renamePhase(oldName, newName, _cwd, accessor) {
|
|
49656
|
-
const meta = await accessor.getMetaValue("project_meta");
|
|
49657
|
-
const phases = meta?.phases ?? {};
|
|
49658
|
-
if (!phases[oldName]) {
|
|
49659
|
-
throw new CleoError(4 /* NOT_FOUND */, `Phase '${oldName}' does not exist`);
|
|
49660
|
-
}
|
|
49661
|
-
if (phases[newName]) {
|
|
49662
|
-
throw new CleoError(101 /* ALREADY_EXISTS */, `Phase '${newName}' already exists`);
|
|
49663
|
-
}
|
|
49664
|
-
if (!/^[a-z][a-z0-9-]*$/.test(newName)) {
|
|
49665
|
-
throw new CleoError(2 /* INVALID_INPUT */, `Invalid phase name '${newName}'`);
|
|
49666
|
-
}
|
|
49667
|
-
phases[newName] = phases[oldName];
|
|
49668
|
-
delete phases[oldName];
|
|
49669
|
-
const { tasks: oldPhaseTasks } = await accessor.queryTasks({ phase: oldName });
|
|
49670
|
-
let tasksUpdated = 0;
|
|
49671
|
-
for (const task of oldPhaseTasks) {
|
|
49672
|
-
task.phase = newName;
|
|
49673
|
-
await accessor.upsertSingleTask(task);
|
|
49674
|
-
tasksUpdated++;
|
|
49675
|
-
}
|
|
49676
|
-
const updatedMeta = meta;
|
|
49677
|
-
let currentPhaseUpdated = false;
|
|
49678
|
-
if (updatedMeta.currentPhase === oldName) {
|
|
49679
|
-
updatedMeta.currentPhase = newName;
|
|
49680
|
-
currentPhaseUpdated = true;
|
|
49681
|
-
}
|
|
49682
|
-
await accessor.setMetaValue("project_meta", updatedMeta);
|
|
49683
|
-
const focus = await accessor.getMetaValue("focus_state");
|
|
49684
|
-
if (focus?.currentPhase === oldName) {
|
|
49685
|
-
focus.currentPhase = newName;
|
|
49686
|
-
await accessor.setMetaValue("focus_state", focus);
|
|
49687
|
-
}
|
|
49688
|
-
return { oldName, newName, tasksUpdated, currentPhaseUpdated };
|
|
49689
|
-
}
|
|
49690
|
-
async function deletePhase(slug, options = {}, _cwd, accessor) {
|
|
49691
|
-
const meta = await accessor.getMetaValue("project_meta");
|
|
49692
|
-
const phases = meta?.phases ?? {};
|
|
49693
|
-
if (!phases[slug]) {
|
|
49694
|
-
throw new CleoError(4 /* NOT_FOUND */, `Phase '${slug}' does not exist`);
|
|
49695
|
-
}
|
|
49696
|
-
if (meta?.currentPhase === slug) {
|
|
49697
|
-
throw new CleoError(
|
|
49698
|
-
6 /* VALIDATION_ERROR */,
|
|
49699
|
-
`Cannot delete current project phase '${slug}'. Use 'phase set' to change phase first`
|
|
49700
|
-
);
|
|
49701
|
-
}
|
|
49702
|
-
const { tasks: phaseTasks } = await accessor.queryTasks({ phase: slug });
|
|
49703
|
-
if (phaseTasks.length > 0 && !options.reassignTo) {
|
|
49704
|
-
throw new CleoError(
|
|
49705
|
-
6 /* VALIDATION_ERROR */,
|
|
49706
|
-
`Cannot delete '${slug}': ${phaseTasks.length} tasks would be orphaned. Use --reassign-to <phase>`
|
|
49707
|
-
);
|
|
49708
|
-
}
|
|
49709
|
-
if (!options.force) {
|
|
49710
|
-
throw new CleoError(2 /* INVALID_INPUT */, "Phase deletion requires --force flag for safety");
|
|
49711
|
-
}
|
|
49712
|
-
if (options.reassignTo) {
|
|
49713
|
-
if (!phases[options.reassignTo]) {
|
|
49714
|
-
throw new CleoError(
|
|
49715
|
-
4 /* NOT_FOUND */,
|
|
49716
|
-
`Reassignment target phase '${options.reassignTo}' does not exist`
|
|
49717
|
-
);
|
|
49718
|
-
}
|
|
49719
|
-
}
|
|
49720
|
-
let tasksReassigned = 0;
|
|
49721
|
-
if (options.reassignTo) {
|
|
49722
|
-
for (const task of phaseTasks) {
|
|
49723
|
-
task.phase = options.reassignTo;
|
|
49724
|
-
await accessor.upsertSingleTask(task);
|
|
49725
|
-
tasksReassigned++;
|
|
49726
|
-
}
|
|
49727
|
-
}
|
|
49728
|
-
delete phases[slug];
|
|
49729
|
-
await accessor.setMetaValue("project_meta", meta);
|
|
49730
|
-
return {
|
|
49731
|
-
deletedPhase: slug,
|
|
49732
|
-
tasksReassigned,
|
|
49733
|
-
reassignedTo: options.reassignTo ?? null
|
|
49734
|
-
};
|
|
49735
|
-
}
|
|
49736
|
-
function addPhaseHistoryEntryToMeta(meta, phase, transitionType, fromPhase, reason, taskCount) {
|
|
49737
|
-
if (!meta.phaseHistory) {
|
|
49738
|
-
meta.phaseHistory = [];
|
|
49739
|
-
}
|
|
49740
|
-
meta.phaseHistory.push({
|
|
49741
|
-
phase,
|
|
49742
|
-
transitionType,
|
|
49743
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
49744
|
-
taskCount,
|
|
49745
|
-
fromPhase,
|
|
49746
|
-
reason
|
|
49747
|
-
});
|
|
49748
|
-
}
|
|
49749
|
-
var init_phases = __esm({
|
|
49750
|
-
"packages/core/src/phases/index.ts"() {
|
|
49751
|
-
"use strict";
|
|
49752
|
-
init_src();
|
|
49753
|
-
init_errors3();
|
|
49754
|
-
init_add();
|
|
49755
|
-
}
|
|
49756
|
-
});
|
|
49757
|
-
|
|
49758
|
-
// packages/core/src/pipeline/phase.ts
|
|
49759
|
-
async function listPhases2(projectRoot, accessor) {
|
|
49760
|
-
try {
|
|
49761
|
-
const result = await listPhases(projectRoot, accessor);
|
|
49762
|
-
return { success: true, data: result };
|
|
49763
|
-
} catch (err) {
|
|
49764
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
49765
|
-
return {
|
|
49766
|
-
success: false,
|
|
49767
|
-
error: { code: "E_PHASE_LIST_FAILED", message }
|
|
49768
|
-
};
|
|
49769
|
-
}
|
|
49770
|
-
}
|
|
49771
|
-
async function showPhase2(projectRoot, phaseId, accessor) {
|
|
49772
|
-
try {
|
|
49773
|
-
const result = await showPhase(phaseId, projectRoot, accessor);
|
|
49774
|
-
return { success: true, data: result };
|
|
49775
|
-
} catch (err) {
|
|
49776
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
49777
|
-
return {
|
|
49778
|
-
success: false,
|
|
49779
|
-
error: { code: "E_PHASE_SHOW_FAILED", message }
|
|
49780
|
-
};
|
|
49781
|
-
}
|
|
49782
|
-
}
|
|
49783
|
-
var init_phase = __esm({
|
|
49784
|
-
"packages/core/src/pipeline/phase.ts"() {
|
|
49785
|
-
"use strict";
|
|
49786
|
-
init_phases();
|
|
49787
|
-
}
|
|
49788
|
-
});
|
|
49789
|
-
|
|
49790
|
-
// packages/core/src/pipeline/index.ts
|
|
49791
|
-
var pipeline_exports2 = {};
|
|
49792
|
-
__export(pipeline_exports2, {
|
|
49793
|
-
listPhases: () => listPhases2,
|
|
49794
|
-
showPhase: () => showPhase2
|
|
49795
|
-
});
|
|
49796
|
-
var init_pipeline2 = __esm({
|
|
49797
|
-
"packages/core/src/pipeline/index.ts"() {
|
|
49798
|
-
"use strict";
|
|
49799
|
-
init_phase();
|
|
49800
|
-
}
|
|
49801
|
-
});
|
|
49802
|
-
|
|
49803
|
-
// packages/core/src/tasks/complete.ts
|
|
49804
|
-
function isVerificationGate(value) {
|
|
49805
|
-
return VERIFICATION_GATES.has(value);
|
|
49806
|
-
}
|
|
49807
|
-
async function loadCompletionEnforcement(cwd) {
|
|
49808
|
-
const isTest = !!process.env.VITEST;
|
|
49809
|
-
const config2 = await loadConfig(cwd);
|
|
49810
|
-
const acceptance = config2.enforcement?.acceptance;
|
|
49811
|
-
const verificationCfg = config2.verification;
|
|
49812
|
-
const acceptanceMode = acceptance?.mode ?? (isTest ? "off" : "block");
|
|
49813
|
-
const acceptanceRequiredForPriorities = acceptance?.requiredForPriorities ?? (isTest ? [] : ["critical", "high", "medium", "low"]);
|
|
49814
|
-
const rawVerificationEnabled = await getRawConfigValue("verification.enabled", cwd);
|
|
49815
|
-
const verificationEnabled = rawVerificationEnabled !== void 0 ? rawVerificationEnabled : !isTest;
|
|
49816
|
-
const verificationRequiredGates = (verificationCfg?.requiredGates ?? []).filter(isVerificationGate).length > 0 ? (verificationCfg?.requiredGates ?? []).filter(isVerificationGate) : DEFAULT_VERIFICATION_REQUIRED_GATES;
|
|
49817
|
-
const verificationMaxRounds = verificationCfg?.maxRounds ?? 5;
|
|
49818
|
-
const lifecycleMode = config2.lifecycle?.mode ?? (isTest ? "off" : "strict");
|
|
49819
|
-
return {
|
|
49820
|
-
acceptanceMode,
|
|
49821
|
-
acceptanceRequiredForPriorities,
|
|
49822
|
-
verificationEnabled,
|
|
49823
|
-
verificationRequiredGates,
|
|
49824
|
-
verificationMaxRounds,
|
|
49825
|
-
lifecycleMode
|
|
49826
|
-
};
|
|
49827
|
-
}
|
|
49828
|
-
async function completeTask(options, cwd, accessor) {
|
|
49829
|
-
const acc = accessor ?? await getAccessor(cwd);
|
|
49830
|
-
const task = await acc.loadSingleTask(options.taskId);
|
|
49831
|
-
if (!task) {
|
|
49832
|
-
throw new CleoError(4 /* NOT_FOUND */, `Task not found: ${options.taskId}`, {
|
|
49833
|
-
fix: `Use 'cleo find "${options.taskId}"' to search`
|
|
49834
|
-
});
|
|
49835
|
-
}
|
|
49836
|
-
await requireActiveSession("tasks.complete", cwd);
|
|
49837
|
-
const enforcement = await loadCompletionEnforcement(cwd);
|
|
49838
|
-
if (task.status === "done") {
|
|
49839
|
-
throw new CleoError(17 /* TASK_COMPLETED */, `Task ${options.taskId} is already completed`);
|
|
49840
|
-
}
|
|
49841
|
-
if (task.depends?.length) {
|
|
49842
|
-
const deps = await acc.loadTasks(task.depends);
|
|
49843
|
-
const incompleteDeps = deps.filter((d) => d.status !== "done" && d.status !== "cancelled").map((d) => d.id);
|
|
49844
|
-
if (incompleteDeps.length > 0) {
|
|
49845
|
-
throw new CleoError(
|
|
49846
|
-
5 /* DEPENDENCY_ERROR */,
|
|
49847
|
-
`Task ${options.taskId} has incomplete dependencies: ${incompleteDeps.join(", ")}`,
|
|
49848
|
-
{
|
|
49849
|
-
fix: `Complete dependencies first: ${incompleteDeps.map((d) => `cleo complete ${d}`).join(", ")}`
|
|
49850
|
-
}
|
|
49851
|
-
);
|
|
49852
|
-
}
|
|
49853
|
-
}
|
|
49854
|
-
const acceptanceEnforcement = await createAcceptanceEnforcement(cwd);
|
|
49855
|
-
const completionValidation = acceptanceEnforcement.validateCompletion(task);
|
|
49856
|
-
if (!completionValidation.valid) {
|
|
49857
|
-
throw new CleoError(
|
|
49858
|
-
completionValidation.exitCode ?? 6 /* VALIDATION_ERROR */,
|
|
49859
|
-
completionValidation.error,
|
|
49860
|
-
{ fix: completionValidation.fix }
|
|
49861
|
-
);
|
|
49862
|
-
}
|
|
49863
|
-
if (enforcement.verificationEnabled && task.type !== "epic") {
|
|
49864
|
-
if (!task.verification) {
|
|
49865
|
-
throw new CleoError(
|
|
49866
|
-
40 /* VERIFICATION_INIT_FAILED */,
|
|
49867
|
-
`Task ${options.taskId} is missing verification metadata`,
|
|
49868
|
-
{
|
|
49869
|
-
fix: `Initialize verification for ${options.taskId} before completion`
|
|
49870
|
-
}
|
|
49871
|
-
);
|
|
49872
|
-
}
|
|
49873
|
-
if (task.verification.round > enforcement.verificationMaxRounds) {
|
|
49874
|
-
throw new CleoError(
|
|
49875
|
-
44 /* MAX_ROUNDS_EXCEEDED */,
|
|
49876
|
-
`Task ${options.taskId} exceeded verification max rounds (${enforcement.verificationMaxRounds})`,
|
|
49877
|
-
{
|
|
49878
|
-
fix: `Review failure log and resolve blockers before retrying completion`
|
|
49879
|
-
}
|
|
49880
|
-
);
|
|
49881
|
-
}
|
|
49882
|
-
const missingRequiredGates = enforcement.verificationRequiredGates.filter(
|
|
49883
|
-
(gate) => task.verification?.gates?.[gate] !== true
|
|
49884
|
-
);
|
|
49885
|
-
if (missingRequiredGates.length > 0 || task.verification.passed !== true) {
|
|
49886
|
-
const exitCode = enforcement.lifecycleMode === "strict" ? 80 /* LIFECYCLE_GATE_FAILED */ : 45 /* GATE_DEPENDENCY */;
|
|
49887
|
-
throw new CleoError(
|
|
49888
|
-
exitCode,
|
|
49889
|
-
`Task ${options.taskId} failed verification gates: ${missingRequiredGates.join(", ") || "verification.passed=false"}`,
|
|
49890
|
-
{
|
|
49891
|
-
fix: `Set required verification gates before completion: ${enforcement.verificationRequiredGates.join(", ")}`
|
|
49892
|
-
}
|
|
49893
|
-
);
|
|
49894
|
-
}
|
|
49895
|
-
}
|
|
49896
|
-
const children = await acc.getChildren(options.taskId);
|
|
49897
|
-
const incompleteChildren = children.filter(
|
|
49898
|
-
(c) => c.status !== "done" && c.status !== "cancelled"
|
|
49899
|
-
);
|
|
49900
|
-
if (incompleteChildren.length > 0 && task.type === "epic") {
|
|
49901
|
-
if (!task.noAutoComplete) {
|
|
49902
|
-
throw new CleoError(
|
|
49903
|
-
16 /* HAS_CHILDREN */,
|
|
49904
|
-
`Epic ${options.taskId} has ${incompleteChildren.length} incomplete children: ${incompleteChildren.map((c) => c.id).join(", ")}`,
|
|
49905
|
-
{
|
|
49906
|
-
fix: `Complete children first or use 'cleo update ${options.taskId} --no-auto-complete'`
|
|
49907
|
-
}
|
|
49908
|
-
);
|
|
49909
|
-
}
|
|
49910
|
-
}
|
|
49911
|
-
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
49912
|
-
const before = { ...task };
|
|
49913
|
-
task.status = "done";
|
|
49914
|
-
task.completedAt = now2;
|
|
49915
|
-
task.updatedAt = now2;
|
|
49916
|
-
if (options.notes) {
|
|
49917
|
-
const timestampedNote = `${(/* @__PURE__ */ new Date()).toISOString().replace("T", " ").replace(/\.\d+Z$/, " UTC")}: ${options.notes}`;
|
|
49918
|
-
if (!task.notes) task.notes = [];
|
|
49919
|
-
task.notes.push(timestampedNote);
|
|
49920
|
-
}
|
|
49921
|
-
if (options.changeset) {
|
|
49922
|
-
if (!task.notes) task.notes = [];
|
|
49923
|
-
task.notes.push(`Changeset: ${options.changeset}`);
|
|
49924
|
-
}
|
|
49925
|
-
const autoCompleted = [];
|
|
49926
|
-
const autoCompletedTasks = [];
|
|
49927
|
-
if (task.parentId) {
|
|
49928
|
-
const parent = await acc.loadSingleTask(task.parentId);
|
|
49929
|
-
if (parent && parent.type === "epic" && !parent.noAutoComplete) {
|
|
49930
|
-
const siblings = await acc.getChildren(parent.id);
|
|
49931
|
-
const allDone = siblings.every(
|
|
49932
|
-
(c) => c.id === task.id || c.status === "done" || c.status === "cancelled"
|
|
49933
|
-
);
|
|
49934
|
-
if (allDone) {
|
|
49935
|
-
parent.status = "done";
|
|
49936
|
-
parent.completedAt = now2;
|
|
49937
|
-
parent.updatedAt = now2;
|
|
49938
|
-
autoCompleted.push(parent.id);
|
|
49939
|
-
autoCompletedTasks.push(parent);
|
|
49940
|
-
}
|
|
49941
|
-
}
|
|
49942
|
-
}
|
|
49943
|
-
await acc.transaction(async (tx) => {
|
|
49944
|
-
await tx.upsertSingleTask(task);
|
|
49945
|
-
for (const parentTask of autoCompletedTasks) {
|
|
49946
|
-
await tx.upsertSingleTask(parentTask);
|
|
49947
|
-
}
|
|
49948
|
-
await tx.appendLog({
|
|
49949
|
-
id: `log-${Math.floor(Date.now() / 1e3)}-${(await import("node:crypto")).randomBytes(3).toString("hex")}`,
|
|
49950
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
49951
|
-
action: "task_completed",
|
|
49952
|
-
taskId: options.taskId,
|
|
49953
|
-
actor: "system",
|
|
49954
|
-
details: { title: task.title, previousStatus: before.status },
|
|
49955
|
-
before: null,
|
|
49956
|
-
after: { title: task.title, previousStatus: before.status }
|
|
49957
|
-
});
|
|
49958
|
-
});
|
|
49959
|
-
const dependents = await acc.getDependents(options.taskId);
|
|
49960
|
-
const unblockedTasks = [];
|
|
49961
|
-
for (const dep of dependents) {
|
|
49962
|
-
if (dep.status === "done" || dep.status === "cancelled") continue;
|
|
49963
|
-
if (dep.depends?.length) {
|
|
49964
|
-
const depDeps = await acc.loadTasks(dep.depends);
|
|
49965
|
-
const stillUnresolved = depDeps.filter(
|
|
49966
|
-
(d) => d.id !== options.taskId && d.status !== "done" && d.status !== "cancelled"
|
|
49967
|
-
);
|
|
49968
|
-
if (stillUnresolved.length === 0) {
|
|
49969
|
-
unblockedTasks.push({ id: dep.id, title: dep.title });
|
|
49970
|
-
}
|
|
49971
|
-
} else {
|
|
49972
|
-
unblockedTasks.push({ id: dep.id, title: dep.title });
|
|
49973
|
-
}
|
|
49974
|
-
}
|
|
49975
|
-
Promise.resolve().then(() => (init_auto_extract(), auto_extract_exports)).then(
|
|
49976
|
-
({ extractTaskCompletionMemory: extractTaskCompletionMemory2 }) => extractTaskCompletionMemory2(cwd ?? process.cwd(), task)
|
|
49977
|
-
).catch(() => {
|
|
49978
|
-
});
|
|
49979
|
-
return {
|
|
49980
|
-
task,
|
|
49981
|
-
...autoCompleted.length > 0 && { autoCompleted },
|
|
49982
|
-
...unblockedTasks.length > 0 && { unblockedTasks }
|
|
49983
|
-
};
|
|
49984
|
-
}
|
|
49985
|
-
var DEFAULT_VERIFICATION_REQUIRED_GATES, VERIFICATION_GATES;
|
|
49986
|
-
var init_complete = __esm({
|
|
49987
|
-
"packages/core/src/tasks/complete.ts"() {
|
|
49988
|
-
"use strict";
|
|
49989
|
-
init_src();
|
|
49990
|
-
init_config();
|
|
49991
|
-
init_errors3();
|
|
49992
|
-
init_session_enforcement();
|
|
49993
|
-
init_data_accessor();
|
|
49994
|
-
init_enforcement();
|
|
49995
|
-
DEFAULT_VERIFICATION_REQUIRED_GATES = [
|
|
49996
|
-
"implemented",
|
|
49997
|
-
"testsPassed",
|
|
49998
|
-
"qaPassed",
|
|
49999
|
-
"securityPassed",
|
|
50000
|
-
"documented"
|
|
50001
|
-
];
|
|
50002
|
-
VERIFICATION_GATES = /* @__PURE__ */ new Set([
|
|
50003
|
-
"implemented",
|
|
50004
|
-
"testsPassed",
|
|
50005
|
-
"qaPassed",
|
|
50006
|
-
"cleanupDone",
|
|
50007
|
-
"securityPassed",
|
|
50008
|
-
"documented"
|
|
50009
|
-
]);
|
|
50010
|
-
}
|
|
50011
|
-
});
|
|
50012
|
-
|
|
50013
|
-
// packages/core/src/tasks/update.ts
|
|
50014
|
-
var update_exports = {};
|
|
50015
|
-
__export(update_exports, {
|
|
50016
|
-
updateTask: () => updateTask
|
|
50017
|
-
});
|
|
50018
|
-
function hasNonStatusDoneFields(options) {
|
|
50019
|
-
return NON_STATUS_DONE_FIELDS.some((field) => options[field] !== void 0);
|
|
50020
|
-
}
|
|
50021
|
-
async function updateTask(options, cwd, accessor) {
|
|
50022
|
-
const acc = accessor ?? await getAccessor(cwd);
|
|
50023
|
-
const task = await acc.loadSingleTask(options.taskId);
|
|
50024
|
-
if (!task) {
|
|
50025
|
-
throw new CleoError(4 /* NOT_FOUND */, `Task not found: ${options.taskId}`, {
|
|
50026
|
-
fix: `Use 'cleo find "${options.taskId}"' to search`
|
|
50027
|
-
});
|
|
50028
|
-
}
|
|
50029
|
-
await requireActiveSession("tasks.update", cwd);
|
|
50030
|
-
const changes = [];
|
|
50031
|
-
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
50032
|
-
const isStatusOnlyDoneTransition = options.status === "done" && task.status !== "done" && !hasNonStatusDoneFields(options);
|
|
50033
|
-
if (isStatusOnlyDoneTransition) {
|
|
50034
|
-
const result = await completeTask({ taskId: options.taskId }, cwd, accessor);
|
|
50035
|
-
return { task: result.task, changes: ["status"] };
|
|
50036
|
-
}
|
|
50037
|
-
if (options.status === "done" && task.status !== "done") {
|
|
50038
|
-
throw new CleoError(
|
|
50039
|
-
6 /* VALIDATION_ERROR */,
|
|
50040
|
-
"status=done must use complete flow; do not combine with other update fields",
|
|
50041
|
-
{
|
|
50042
|
-
fix: `Run 'cleo complete ${options.taskId}' first, then apply additional updates with 'cleo update ${options.taskId} ...'`
|
|
50043
|
-
}
|
|
50044
|
-
);
|
|
50045
|
-
}
|
|
50046
|
-
const enforcement = await createAcceptanceEnforcement(cwd);
|
|
50047
|
-
const updateValidation = enforcement.validateUpdate(task, { acceptance: options.acceptance });
|
|
50048
|
-
if (!updateValidation.valid) {
|
|
50049
|
-
throw new CleoError(
|
|
50050
|
-
updateValidation.exitCode ?? 6 /* VALIDATION_ERROR */,
|
|
50051
|
-
updateValidation.error,
|
|
50052
|
-
{ fix: updateValidation.fix }
|
|
50053
|
-
);
|
|
50054
|
-
}
|
|
50055
|
-
if (options.title !== void 0) {
|
|
50056
|
-
validateTitle(options.title);
|
|
50057
|
-
task.title = options.title;
|
|
50058
|
-
changes.push("title");
|
|
50059
|
-
}
|
|
50060
|
-
if (options.status !== void 0) {
|
|
50061
|
-
validateStatus(options.status);
|
|
50062
|
-
const oldStatus = task.status;
|
|
50063
|
-
task.status = options.status;
|
|
50064
|
-
changes.push("status");
|
|
50065
|
-
if (options.status === "done" && oldStatus !== "done") {
|
|
50066
|
-
task.completedAt = now2;
|
|
50067
|
-
}
|
|
50068
|
-
if (options.status === "cancelled" && oldStatus !== "cancelled") {
|
|
50069
|
-
task.cancelledAt = now2;
|
|
50070
|
-
}
|
|
50071
|
-
}
|
|
50072
|
-
if (options.priority !== void 0) {
|
|
50073
|
-
const normalizedPriority = normalizePriority(options.priority);
|
|
50074
|
-
task.priority = normalizedPriority;
|
|
50075
|
-
changes.push("priority");
|
|
50076
|
-
}
|
|
50077
|
-
if (options.type !== void 0) {
|
|
50078
|
-
validateTaskType(options.type);
|
|
50079
|
-
task.type = options.type;
|
|
50080
|
-
changes.push("type");
|
|
50081
|
-
}
|
|
50082
|
-
if (options.size !== void 0) {
|
|
50083
|
-
validateSize(options.size);
|
|
50084
|
-
task.size = options.size;
|
|
50085
|
-
changes.push("size");
|
|
50086
|
-
}
|
|
50087
|
-
if (options.phase !== void 0) {
|
|
50088
|
-
task.phase = options.phase;
|
|
50089
|
-
changes.push("phase");
|
|
50090
|
-
}
|
|
50091
|
-
if (options.description !== void 0) {
|
|
50092
|
-
task.description = options.description;
|
|
50093
|
-
changes.push("description");
|
|
50094
|
-
}
|
|
50095
|
-
if (options.labels !== void 0) {
|
|
50096
|
-
if (options.labels.length) validateLabels(options.labels);
|
|
50097
|
-
task.labels = options.labels;
|
|
50098
|
-
changes.push("labels");
|
|
50567
|
+
}
|
|
50568
|
+
const totalTasks = phaseTasks.length;
|
|
50569
|
+
const completionPercent = totalTasks > 0 ? Math.floor((totalTasks - incompleteTasks.length) * 100 / totalTasks) : 0;
|
|
50570
|
+
const threshold = 90;
|
|
50571
|
+
if (completionPercent < threshold && !force) {
|
|
50572
|
+
throw new CleoError(
|
|
50573
|
+
6 /* VALIDATION_ERROR */,
|
|
50574
|
+
`Cannot advance - ${incompleteTasks.length} incomplete task(s) in phase '${currentSlug}' (${completionPercent}% complete, threshold: ${threshold}%)`,
|
|
50575
|
+
{ fix: "Use --force to override" }
|
|
50576
|
+
);
|
|
50577
|
+
}
|
|
50099
50578
|
}
|
|
50100
|
-
|
|
50101
|
-
|
|
50102
|
-
|
|
50103
|
-
|
|
50104
|
-
|
|
50105
|
-
|
|
50579
|
+
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
50580
|
+
currentPhase.status = "completed";
|
|
50581
|
+
currentPhase.completedAt = now2;
|
|
50582
|
+
const nextPhase = phases[nextSlug];
|
|
50583
|
+
nextPhase.status = "active";
|
|
50584
|
+
nextPhase.startedAt = now2;
|
|
50585
|
+
const updatedMeta = meta;
|
|
50586
|
+
updatedMeta.currentPhase = nextSlug;
|
|
50587
|
+
const currentPhaseTaskCount = phaseTasks.length;
|
|
50588
|
+
const { tasks: nextPhaseTasks } = await accessor.queryTasks({ phase: nextSlug });
|
|
50589
|
+
const nextPhaseTaskCount = nextPhaseTasks.length;
|
|
50590
|
+
addPhaseHistoryEntryToMeta(
|
|
50591
|
+
updatedMeta,
|
|
50592
|
+
currentSlug,
|
|
50593
|
+
"completed",
|
|
50594
|
+
null,
|
|
50595
|
+
"Phase completed via advance",
|
|
50596
|
+
currentPhaseTaskCount
|
|
50597
|
+
);
|
|
50598
|
+
addPhaseHistoryEntryToMeta(
|
|
50599
|
+
updatedMeta,
|
|
50600
|
+
nextSlug,
|
|
50601
|
+
"started",
|
|
50602
|
+
currentSlug,
|
|
50603
|
+
`Phase started via advance from ${currentSlug}`,
|
|
50604
|
+
nextPhaseTaskCount
|
|
50605
|
+
);
|
|
50606
|
+
await accessor.setMetaValue("project_meta", updatedMeta);
|
|
50607
|
+
return {
|
|
50608
|
+
previousPhase: currentSlug,
|
|
50609
|
+
currentPhase: nextSlug,
|
|
50610
|
+
forced: force
|
|
50611
|
+
};
|
|
50612
|
+
}
|
|
50613
|
+
async function renamePhase(oldName, newName, _cwd, accessor) {
|
|
50614
|
+
const meta = await accessor.getMetaValue("project_meta");
|
|
50615
|
+
const phases = meta?.phases ?? {};
|
|
50616
|
+
if (!phases[oldName]) {
|
|
50617
|
+
throw new CleoError(4 /* NOT_FOUND */, `Phase '${oldName}' does not exist`);
|
|
50106
50618
|
}
|
|
50107
|
-
if (
|
|
50108
|
-
|
|
50109
|
-
task.labels = (task.labels ?? []).filter((l) => !toRemove.has(l));
|
|
50110
|
-
changes.push("labels");
|
|
50619
|
+
if (phases[newName]) {
|
|
50620
|
+
throw new CleoError(101 /* ALREADY_EXISTS */, `Phase '${newName}' already exists`);
|
|
50111
50621
|
}
|
|
50112
|
-
if (
|
|
50113
|
-
|
|
50114
|
-
changes.push("depends");
|
|
50622
|
+
if (!/^[a-z][a-z0-9-]*$/.test(newName)) {
|
|
50623
|
+
throw new CleoError(2 /* INVALID_INPUT */, `Invalid phase name '${newName}'`);
|
|
50115
50624
|
}
|
|
50116
|
-
|
|
50117
|
-
|
|
50118
|
-
|
|
50119
|
-
|
|
50120
|
-
|
|
50625
|
+
phases[newName] = phases[oldName];
|
|
50626
|
+
delete phases[oldName];
|
|
50627
|
+
const { tasks: oldPhaseTasks } = await accessor.queryTasks({ phase: oldName });
|
|
50628
|
+
let tasksUpdated = 0;
|
|
50629
|
+
for (const task of oldPhaseTasks) {
|
|
50630
|
+
task.phase = newName;
|
|
50631
|
+
await accessor.upsertSingleTask(task);
|
|
50632
|
+
tasksUpdated++;
|
|
50121
50633
|
}
|
|
50122
|
-
|
|
50123
|
-
|
|
50124
|
-
|
|
50125
|
-
|
|
50634
|
+
const updatedMeta = meta;
|
|
50635
|
+
let currentPhaseUpdated = false;
|
|
50636
|
+
if (updatedMeta.currentPhase === oldName) {
|
|
50637
|
+
updatedMeta.currentPhase = newName;
|
|
50638
|
+
currentPhaseUpdated = true;
|
|
50126
50639
|
}
|
|
50127
|
-
|
|
50128
|
-
|
|
50129
|
-
|
|
50130
|
-
|
|
50131
|
-
|
|
50640
|
+
await accessor.setMetaValue("project_meta", updatedMeta);
|
|
50641
|
+
const focus = await accessor.getMetaValue("focus_state");
|
|
50642
|
+
if (focus?.currentPhase === oldName) {
|
|
50643
|
+
focus.currentPhase = newName;
|
|
50644
|
+
await accessor.setMetaValue("focus_state", focus);
|
|
50132
50645
|
}
|
|
50133
|
-
|
|
50134
|
-
|
|
50135
|
-
|
|
50646
|
+
return { oldName, newName, tasksUpdated, currentPhaseUpdated };
|
|
50647
|
+
}
|
|
50648
|
+
async function deletePhase(slug, options = {}, _cwd, accessor) {
|
|
50649
|
+
const meta = await accessor.getMetaValue("project_meta");
|
|
50650
|
+
const phases = meta?.phases ?? {};
|
|
50651
|
+
if (!phases[slug]) {
|
|
50652
|
+
throw new CleoError(4 /* NOT_FOUND */, `Phase '${slug}' does not exist`);
|
|
50136
50653
|
}
|
|
50137
|
-
if (
|
|
50138
|
-
|
|
50139
|
-
|
|
50654
|
+
if (meta?.currentPhase === slug) {
|
|
50655
|
+
throw new CleoError(
|
|
50656
|
+
6 /* VALIDATION_ERROR */,
|
|
50657
|
+
`Cannot delete current project phase '${slug}'. Use 'phase set' to change phase first`
|
|
50658
|
+
);
|
|
50140
50659
|
}
|
|
50141
|
-
|
|
50142
|
-
|
|
50143
|
-
|
|
50660
|
+
const { tasks: phaseTasks } = await accessor.queryTasks({ phase: slug });
|
|
50661
|
+
if (phaseTasks.length > 0 && !options.reassignTo) {
|
|
50662
|
+
throw new CleoError(
|
|
50663
|
+
6 /* VALIDATION_ERROR */,
|
|
50664
|
+
`Cannot delete '${slug}': ${phaseTasks.length} tasks would be orphaned. Use --reassign-to <phase>`
|
|
50665
|
+
);
|
|
50144
50666
|
}
|
|
50145
|
-
if (options.
|
|
50146
|
-
|
|
50147
|
-
changes.push("noAutoComplete");
|
|
50667
|
+
if (!options.force) {
|
|
50668
|
+
throw new CleoError(2 /* INVALID_INPUT */, "Phase deletion requires --force flag for safety");
|
|
50148
50669
|
}
|
|
50149
|
-
if (options.
|
|
50150
|
-
|
|
50151
|
-
|
|
50152
|
-
|
|
50153
|
-
{
|
|
50154
|
-
epicId: task.id,
|
|
50155
|
-
currentStage: task.pipelineStage,
|
|
50156
|
-
newStage: options.pipelineStage
|
|
50157
|
-
},
|
|
50158
|
-
acc,
|
|
50159
|
-
cwd
|
|
50670
|
+
if (options.reassignTo) {
|
|
50671
|
+
if (!phases[options.reassignTo]) {
|
|
50672
|
+
throw new CleoError(
|
|
50673
|
+
4 /* NOT_FOUND */,
|
|
50674
|
+
`Reassignment target phase '${options.reassignTo}' does not exist`
|
|
50160
50675
|
);
|
|
50161
50676
|
}
|
|
50162
|
-
if (task.type !== "epic") {
|
|
50163
|
-
const epicAncestor = task.parentId ? await findEpicAncestor(task.parentId, acc) : null;
|
|
50164
|
-
const directParent = task.parentId ? await acc.loadSingleTask(task.parentId) : null;
|
|
50165
|
-
const epicToCheck = directParent?.type === "epic" ? directParent : epicAncestor;
|
|
50166
|
-
if (epicToCheck) {
|
|
50167
|
-
await validateChildStageCeiling(
|
|
50168
|
-
{ childStage: options.pipelineStage, epicId: epicToCheck.id },
|
|
50169
|
-
acc,
|
|
50170
|
-
cwd
|
|
50171
|
-
);
|
|
50172
|
-
}
|
|
50173
|
-
}
|
|
50174
|
-
task.pipelineStage = options.pipelineStage;
|
|
50175
|
-
changes.push("pipelineStage");
|
|
50176
50677
|
}
|
|
50177
|
-
|
|
50178
|
-
|
|
50179
|
-
const
|
|
50180
|
-
|
|
50181
|
-
|
|
50182
|
-
|
|
50183
|
-
task.parentId = null;
|
|
50184
|
-
if (task.type === "subtask") task.type = "task";
|
|
50185
|
-
changes.push("parentId");
|
|
50186
|
-
if (task.type !== originalType) changes.push("type");
|
|
50187
|
-
} else {
|
|
50188
|
-
const newParent = await acc.loadSingleTask(newParentId);
|
|
50189
|
-
if (!newParent) {
|
|
50190
|
-
throw new CleoError(10 /* PARENT_NOT_FOUND */, `Parent task ${newParentId} not found`);
|
|
50191
|
-
}
|
|
50192
|
-
if (newParent.type === "subtask") {
|
|
50193
|
-
throw new CleoError(
|
|
50194
|
-
13 /* INVALID_PARENT_TYPE */,
|
|
50195
|
-
`Cannot parent under subtask '${newParentId}'`
|
|
50196
|
-
);
|
|
50197
|
-
}
|
|
50198
|
-
const subtree = await acc.getSubtree(options.taskId);
|
|
50199
|
-
if (subtree.some((t) => t.id === newParentId)) {
|
|
50200
|
-
throw new CleoError(
|
|
50201
|
-
14 /* CIRCULAR_REFERENCE */,
|
|
50202
|
-
`Moving '${options.taskId}' under '${newParentId}' would create a circular reference`
|
|
50203
|
-
);
|
|
50204
|
-
}
|
|
50205
|
-
const ancestors = await acc.getAncestorChain(newParentId);
|
|
50206
|
-
const parentDepth = ancestors.length;
|
|
50207
|
-
const config2 = await loadConfig(cwd);
|
|
50208
|
-
const policy = resolveHierarchyPolicy(config2);
|
|
50209
|
-
if (parentDepth + 1 >= policy.maxDepth) {
|
|
50210
|
-
throw new CleoError(
|
|
50211
|
-
11 /* DEPTH_EXCEEDED */,
|
|
50212
|
-
`Maximum nesting depth ${policy.maxDepth} would be exceeded`
|
|
50213
|
-
);
|
|
50214
|
-
}
|
|
50215
|
-
task.parentId = newParentId;
|
|
50216
|
-
const newDepth = parentDepth + 1;
|
|
50217
|
-
if (newDepth === 1) task.type = "task";
|
|
50218
|
-
else if (newDepth >= 2) task.type = "subtask";
|
|
50219
|
-
changes.push("parentId");
|
|
50220
|
-
if (task.type !== originalType) changes.push("type");
|
|
50221
|
-
}
|
|
50678
|
+
let tasksReassigned = 0;
|
|
50679
|
+
if (options.reassignTo) {
|
|
50680
|
+
for (const task of phaseTasks) {
|
|
50681
|
+
task.phase = options.reassignTo;
|
|
50682
|
+
await accessor.upsertSingleTask(task);
|
|
50683
|
+
tasksReassigned++;
|
|
50222
50684
|
}
|
|
50223
50685
|
}
|
|
50224
|
-
|
|
50225
|
-
|
|
50686
|
+
delete phases[slug];
|
|
50687
|
+
await accessor.setMetaValue("project_meta", meta);
|
|
50688
|
+
return {
|
|
50689
|
+
deletedPhase: slug,
|
|
50690
|
+
tasksReassigned,
|
|
50691
|
+
reassignedTo: options.reassignTo ?? null
|
|
50692
|
+
};
|
|
50693
|
+
}
|
|
50694
|
+
function addPhaseHistoryEntryToMeta(meta, phase, transitionType, fromPhase, reason, taskCount) {
|
|
50695
|
+
if (!meta.phaseHistory) {
|
|
50696
|
+
meta.phaseHistory = [];
|
|
50226
50697
|
}
|
|
50227
|
-
|
|
50228
|
-
|
|
50229
|
-
|
|
50230
|
-
|
|
50231
|
-
|
|
50232
|
-
|
|
50233
|
-
|
|
50234
|
-
taskId: options.taskId,
|
|
50235
|
-
actor: "system",
|
|
50236
|
-
details: { changes, title: task.title },
|
|
50237
|
-
before: null,
|
|
50238
|
-
after: { changes, title: task.title }
|
|
50239
|
-
});
|
|
50698
|
+
meta.phaseHistory.push({
|
|
50699
|
+
phase,
|
|
50700
|
+
transitionType,
|
|
50701
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
50702
|
+
taskCount,
|
|
50703
|
+
fromPhase,
|
|
50704
|
+
reason
|
|
50240
50705
|
});
|
|
50241
|
-
return { task, changes };
|
|
50242
50706
|
}
|
|
50243
|
-
var
|
|
50244
|
-
|
|
50245
|
-
"packages/core/src/tasks/update.ts"() {
|
|
50707
|
+
var init_phases = __esm({
|
|
50708
|
+
"packages/core/src/phases/index.ts"() {
|
|
50246
50709
|
"use strict";
|
|
50247
50710
|
init_src();
|
|
50248
|
-
init_config();
|
|
50249
50711
|
init_errors3();
|
|
50250
|
-
init_session_enforcement();
|
|
50251
|
-
init_data_accessor();
|
|
50252
50712
|
init_add();
|
|
50253
|
-
|
|
50254
|
-
|
|
50255
|
-
|
|
50256
|
-
|
|
50257
|
-
|
|
50258
|
-
|
|
50259
|
-
|
|
50260
|
-
|
|
50261
|
-
|
|
50262
|
-
|
|
50263
|
-
|
|
50264
|
-
|
|
50265
|
-
"
|
|
50266
|
-
|
|
50267
|
-
|
|
50268
|
-
|
|
50269
|
-
|
|
50270
|
-
|
|
50271
|
-
|
|
50272
|
-
|
|
50273
|
-
|
|
50274
|
-
|
|
50275
|
-
|
|
50276
|
-
|
|
50277
|
-
"
|
|
50278
|
-
|
|
50713
|
+
}
|
|
50714
|
+
});
|
|
50715
|
+
|
|
50716
|
+
// packages/core/src/pipeline/phase.ts
|
|
50717
|
+
async function listPhases2(projectRoot, accessor) {
|
|
50718
|
+
try {
|
|
50719
|
+
const result = await listPhases(projectRoot, accessor);
|
|
50720
|
+
return { success: true, data: result };
|
|
50721
|
+
} catch (err) {
|
|
50722
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
50723
|
+
return {
|
|
50724
|
+
success: false,
|
|
50725
|
+
error: { code: "E_PHASE_LIST_FAILED", message }
|
|
50726
|
+
};
|
|
50727
|
+
}
|
|
50728
|
+
}
|
|
50729
|
+
async function showPhase2(projectRoot, phaseId, accessor) {
|
|
50730
|
+
try {
|
|
50731
|
+
const result = await showPhase(phaseId, projectRoot, accessor);
|
|
50732
|
+
return { success: true, data: result };
|
|
50733
|
+
} catch (err) {
|
|
50734
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
50735
|
+
return {
|
|
50736
|
+
success: false,
|
|
50737
|
+
error: { code: "E_PHASE_SHOW_FAILED", message }
|
|
50738
|
+
};
|
|
50739
|
+
}
|
|
50740
|
+
}
|
|
50741
|
+
var init_phase = __esm({
|
|
50742
|
+
"packages/core/src/pipeline/phase.ts"() {
|
|
50743
|
+
"use strict";
|
|
50744
|
+
init_phases();
|
|
50745
|
+
}
|
|
50746
|
+
});
|
|
50747
|
+
|
|
50748
|
+
// packages/core/src/pipeline/index.ts
|
|
50749
|
+
var pipeline_exports2 = {};
|
|
50750
|
+
__export(pipeline_exports2, {
|
|
50751
|
+
listPhases: () => listPhases2,
|
|
50752
|
+
showPhase: () => showPhase2
|
|
50753
|
+
});
|
|
50754
|
+
var init_pipeline2 = __esm({
|
|
50755
|
+
"packages/core/src/pipeline/index.ts"() {
|
|
50756
|
+
"use strict";
|
|
50757
|
+
init_phase();
|
|
50279
50758
|
}
|
|
50280
50759
|
});
|
|
50281
50760
|
|
|
@@ -62663,145 +63142,6 @@ var init_system2 = __esm({
|
|
|
62663
63142
|
}
|
|
62664
63143
|
});
|
|
62665
63144
|
|
|
62666
|
-
// packages/core/src/task-work/index.ts
|
|
62667
|
-
var task_work_exports = {};
|
|
62668
|
-
__export(task_work_exports, {
|
|
62669
|
-
currentTask: () => currentTask,
|
|
62670
|
-
getTaskHistory: () => getTaskHistory,
|
|
62671
|
-
getWorkHistory: () => getWorkHistory,
|
|
62672
|
-
startTask: () => startTask,
|
|
62673
|
-
stopTask: () => stopTask
|
|
62674
|
-
});
|
|
62675
|
-
async function currentTask(cwd, accessor) {
|
|
62676
|
-
const acc = accessor ?? await getAccessor(cwd);
|
|
62677
|
-
const focus = await acc.getMetaValue("focus_state");
|
|
62678
|
-
return {
|
|
62679
|
-
currentTask: focus?.currentTask ?? null,
|
|
62680
|
-
currentPhase: focus?.currentPhase ?? null,
|
|
62681
|
-
sessionNote: focus?.sessionNote ?? null,
|
|
62682
|
-
nextAction: focus?.nextAction ?? null
|
|
62683
|
-
};
|
|
62684
|
-
}
|
|
62685
|
-
async function startTask(taskId, cwd, accessor) {
|
|
62686
|
-
if (!taskId) {
|
|
62687
|
-
throw new CleoError(2 /* INVALID_INPUT */, "Task ID is required");
|
|
62688
|
-
}
|
|
62689
|
-
const acc = accessor ?? await getAccessor(cwd);
|
|
62690
|
-
const task = await acc.loadSingleTask(taskId);
|
|
62691
|
-
if (!task) {
|
|
62692
|
-
throw new CleoError(4 /* NOT_FOUND */, `Task not found: ${taskId}`, {
|
|
62693
|
-
fix: `Use 'cleo find "${taskId}"' to search`
|
|
62694
|
-
});
|
|
62695
|
-
}
|
|
62696
|
-
const { tasks: allTasks } = await acc.queryTasks({});
|
|
62697
|
-
const unresolvedDeps = getUnresolvedDeps(taskId, allTasks);
|
|
62698
|
-
if (unresolvedDeps.length > 0) {
|
|
62699
|
-
throw new CleoError(
|
|
62700
|
-
5 /* DEPENDENCY_ERROR */,
|
|
62701
|
-
`Task ${taskId} is blocked by unresolved dependencies: ${unresolvedDeps.join(", ")}`,
|
|
62702
|
-
{
|
|
62703
|
-
fix: `Complete blockers first: ${unresolvedDeps.map((d) => `cleo complete ${d}`).join(", ")}`
|
|
62704
|
-
}
|
|
62705
|
-
);
|
|
62706
|
-
}
|
|
62707
|
-
const focus = await acc.getMetaValue("focus_state") ?? {};
|
|
62708
|
-
const previousTask = focus.currentTask ?? null;
|
|
62709
|
-
focus.currentTask = taskId;
|
|
62710
|
-
focus.currentPhase = task.phase ?? null;
|
|
62711
|
-
const noteEntry = {
|
|
62712
|
-
note: `Started work on ${taskId}: ${task.title}`,
|
|
62713
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
62714
|
-
};
|
|
62715
|
-
if (!focus.sessionNotes) {
|
|
62716
|
-
focus.sessionNotes = [];
|
|
62717
|
-
}
|
|
62718
|
-
focus.sessionNotes.push(noteEntry);
|
|
62719
|
-
await acc.setMetaValue("focus_state", focus);
|
|
62720
|
-
await logOperation(
|
|
62721
|
-
"task_start",
|
|
62722
|
-
taskId,
|
|
62723
|
-
{
|
|
62724
|
-
previousTask,
|
|
62725
|
-
title: task.title
|
|
62726
|
-
},
|
|
62727
|
-
accessor
|
|
62728
|
-
);
|
|
62729
|
-
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
62730
|
-
hooks2.dispatch("PreToolUse", cwd ?? process.cwd(), {
|
|
62731
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
62732
|
-
taskId,
|
|
62733
|
-
taskTitle: task.title
|
|
62734
|
-
}).catch(() => {
|
|
62735
|
-
});
|
|
62736
|
-
return {
|
|
62737
|
-
taskId,
|
|
62738
|
-
taskTitle: task.title,
|
|
62739
|
-
previousTask
|
|
62740
|
-
};
|
|
62741
|
-
}
|
|
62742
|
-
async function stopTask(cwd, accessor) {
|
|
62743
|
-
const acc = accessor ?? await getAccessor(cwd);
|
|
62744
|
-
const focus = await acc.getMetaValue("focus_state");
|
|
62745
|
-
const previousTask = focus?.currentTask ?? null;
|
|
62746
|
-
if (!focus) {
|
|
62747
|
-
return { previousTask: null };
|
|
62748
|
-
}
|
|
62749
|
-
const taskId = focus.currentTask;
|
|
62750
|
-
const task = taskId ? await acc.loadSingleTask(taskId) : void 0;
|
|
62751
|
-
focus.currentTask = null;
|
|
62752
|
-
focus.nextAction = null;
|
|
62753
|
-
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
62754
|
-
if (taskId && task) {
|
|
62755
|
-
const { hooks: hooks2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
62756
|
-
hooks2.dispatch("PostToolUse", cwd ?? process.cwd(), {
|
|
62757
|
-
timestamp: now2,
|
|
62758
|
-
taskId,
|
|
62759
|
-
taskTitle: task.title,
|
|
62760
|
-
status: "done"
|
|
62761
|
-
}).catch(() => {
|
|
62762
|
-
});
|
|
62763
|
-
}
|
|
62764
|
-
await acc.setMetaValue("focus_state", focus);
|
|
62765
|
-
await logOperation(
|
|
62766
|
-
"task_stop",
|
|
62767
|
-
previousTask ?? "none",
|
|
62768
|
-
{
|
|
62769
|
-
previousTask
|
|
62770
|
-
},
|
|
62771
|
-
accessor
|
|
62772
|
-
);
|
|
62773
|
-
return { previousTask };
|
|
62774
|
-
}
|
|
62775
|
-
async function getWorkHistory(cwd, accessor) {
|
|
62776
|
-
const acc = accessor ?? await getAccessor(cwd);
|
|
62777
|
-
const focus = await acc.getMetaValue("focus_state");
|
|
62778
|
-
const notes = focus?.sessionNotes ?? [];
|
|
62779
|
-
const history = [];
|
|
62780
|
-
for (const note of notes) {
|
|
62781
|
-
const match = note.note.match(/^(?:Focus set to|Started work on) (T\d+)/);
|
|
62782
|
-
if (match) {
|
|
62783
|
-
history.push({
|
|
62784
|
-
taskId: match[1],
|
|
62785
|
-
timestamp: note.timestamp
|
|
62786
|
-
});
|
|
62787
|
-
}
|
|
62788
|
-
}
|
|
62789
|
-
return history.reverse();
|
|
62790
|
-
}
|
|
62791
|
-
var getTaskHistory;
|
|
62792
|
-
var init_task_work = __esm({
|
|
62793
|
-
"packages/core/src/task-work/index.ts"() {
|
|
62794
|
-
"use strict";
|
|
62795
|
-
init_src();
|
|
62796
|
-
init_errors3();
|
|
62797
|
-
init_data_accessor();
|
|
62798
|
-
init_add();
|
|
62799
|
-
init_dependency_check();
|
|
62800
|
-
init_handlers();
|
|
62801
|
-
getTaskHistory = getWorkHistory;
|
|
62802
|
-
}
|
|
62803
|
-
});
|
|
62804
|
-
|
|
62805
63145
|
// packages/core/src/tasks/archive.ts
|
|
62806
63146
|
async function archiveTasks(options = {}, cwd, accessor) {
|
|
62807
63147
|
const acc = accessor ?? await getAccessor(cwd);
|
|
@@ -63964,12 +64304,12 @@ function parseCommonFlags(args) {
|
|
|
63964
64304
|
flags.remaining = remaining;
|
|
63965
64305
|
return flags;
|
|
63966
64306
|
}
|
|
63967
|
-
function
|
|
64307
|
+
function resolveFormat2(flagFormat) {
|
|
63968
64308
|
if (flagFormat === "json" || flagFormat === "human") return flagFormat;
|
|
63969
64309
|
return process.stdout.isTTY ? "human" : "json";
|
|
63970
64310
|
}
|
|
63971
64311
|
function isJsonOutput(flags) {
|
|
63972
|
-
return
|
|
64312
|
+
return resolveFormat2(flags.format) === "json";
|
|
63973
64313
|
}
|
|
63974
64314
|
var init_flags = __esm({
|
|
63975
64315
|
"packages/core/src/ui/flags.ts"() {
|
|
@@ -64004,7 +64344,7 @@ __export(ui_exports, {
|
|
|
64004
64344
|
parseCommandHeader: () => parseCommandHeader,
|
|
64005
64345
|
parseCommonFlags: () => parseCommonFlags,
|
|
64006
64346
|
removeAliases: () => removeAliases,
|
|
64007
|
-
resolveFormat: () =>
|
|
64347
|
+
resolveFormat: () => resolveFormat2,
|
|
64008
64348
|
scanAllCommands: () => scanAllCommands,
|
|
64009
64349
|
validateHeader: () => validateHeader,
|
|
64010
64350
|
writeChangelogFile: () => writeChangelogFile
|
|
@@ -68333,6 +68673,7 @@ var init_cleo = __esm({
|
|
|
68333
68673
|
init_permissions();
|
|
68334
68674
|
init_registry3();
|
|
68335
68675
|
init_sharing();
|
|
68676
|
+
init_workspace();
|
|
68336
68677
|
init_orchestration();
|
|
68337
68678
|
init_reconciliation();
|
|
68338
68679
|
init_link_store();
|
|
@@ -68571,7 +68912,14 @@ var init_cleo = __esm({
|
|
|
68571
68912
|
discover: (p) => discoverRelated(p.query, p.method, p.limit),
|
|
68572
68913
|
search: (p) => searchAcrossProjects(p.pattern, p.project, p.limit),
|
|
68573
68914
|
setPermission: (p) => setPermission(p.name, p.level),
|
|
68574
|
-
sharingStatus: () => getSharingStatus()
|
|
68915
|
+
sharingStatus: () => getSharingStatus(),
|
|
68916
|
+
route: (message) => {
|
|
68917
|
+
const directive = parseDirective(message);
|
|
68918
|
+
if (!directive) return Promise.resolve([]);
|
|
68919
|
+
return routeDirective(directive);
|
|
68920
|
+
},
|
|
68921
|
+
workspaceStatus: () => workspaceStatus(),
|
|
68922
|
+
workspaceAgents: () => workspaceAgents()
|
|
68575
68923
|
};
|
|
68576
68924
|
}
|
|
68577
68925
|
// === Agents ===
|
|
@@ -75933,7 +76281,7 @@ async function runUpgrade(options = {}) {
|
|
|
75933
76281
|
return { success: false, upToDate: false, dryRun: isDryRun, actions, applied: 0, errors };
|
|
75934
76282
|
}
|
|
75935
76283
|
await forceCheckpointBeforeOperation("storage-migration", options.cwd);
|
|
75936
|
-
const { MigrationLogger: MigrationLogger2 } = await Promise.resolve().then(() => (init_logger3(),
|
|
76284
|
+
const { MigrationLogger: MigrationLogger2 } = await Promise.resolve().then(() => (init_logger3(), logger_exports2));
|
|
75937
76285
|
const {
|
|
75938
76286
|
createMigrationState: createMigrationState2,
|
|
75939
76287
|
updateMigrationPhase: updateMigrationPhase2,
|
|
@@ -80487,41 +80835,6 @@ var init_internal = __esm({
|
|
|
80487
80835
|
}
|
|
80488
80836
|
});
|
|
80489
80837
|
|
|
80490
|
-
// packages/cleo/src/cli/field-context.ts
|
|
80491
|
-
import {
|
|
80492
|
-
resolveFieldExtraction
|
|
80493
|
-
} from "@cleocode/lafs-protocol";
|
|
80494
|
-
function getFieldContext() {
|
|
80495
|
-
return currentContext;
|
|
80496
|
-
}
|
|
80497
|
-
var currentContext;
|
|
80498
|
-
var init_field_context = __esm({
|
|
80499
|
-
"packages/cleo/src/cli/field-context.ts"() {
|
|
80500
|
-
"use strict";
|
|
80501
|
-
currentContext = {
|
|
80502
|
-
mvi: "standard",
|
|
80503
|
-
mviSource: "default",
|
|
80504
|
-
expectsCustomMvi: false
|
|
80505
|
-
};
|
|
80506
|
-
}
|
|
80507
|
-
});
|
|
80508
|
-
|
|
80509
|
-
// packages/cleo/src/cli/format-context.ts
|
|
80510
|
-
function getFormatContext() {
|
|
80511
|
-
return currentResolution;
|
|
80512
|
-
}
|
|
80513
|
-
var currentResolution;
|
|
80514
|
-
var init_format_context = __esm({
|
|
80515
|
-
"packages/cleo/src/cli/format-context.ts"() {
|
|
80516
|
-
"use strict";
|
|
80517
|
-
currentResolution = {
|
|
80518
|
-
format: "json",
|
|
80519
|
-
source: "default",
|
|
80520
|
-
quiet: false
|
|
80521
|
-
};
|
|
80522
|
-
}
|
|
80523
|
-
});
|
|
80524
|
-
|
|
80525
80838
|
// packages/cleo/src/cli/renderers/normalizer.ts
|
|
80526
80839
|
function normalizeForHuman(command, data) {
|
|
80527
80840
|
switch (command) {
|
|
@@ -95457,6 +95770,23 @@ function camelToKebab(str) {
|
|
|
95457
95770
|
return str.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);
|
|
95458
95771
|
}
|
|
95459
95772
|
|
|
95773
|
+
// packages/cleo/src/cli/index.ts
|
|
95774
|
+
init_field_context();
|
|
95775
|
+
init_format_context();
|
|
95776
|
+
|
|
95777
|
+
// packages/cleo/src/cli/middleware/output-format.ts
|
|
95778
|
+
import { resolveOutputFormat } from "@cleocode/lafs-protocol";
|
|
95779
|
+
function resolveFormat(opts, defaults) {
|
|
95780
|
+
const input = {
|
|
95781
|
+
jsonFlag: opts["json"] === true,
|
|
95782
|
+
humanFlag: opts["human"] === true,
|
|
95783
|
+
quiet: opts["quiet"] === true,
|
|
95784
|
+
projectDefault: defaults?.projectDefault,
|
|
95785
|
+
userDefault: defaults?.userDefault
|
|
95786
|
+
};
|
|
95787
|
+
return resolveOutputFormat(input);
|
|
95788
|
+
}
|
|
95789
|
+
|
|
95460
95790
|
// packages/cleo/src/cli/commands/add.ts
|
|
95461
95791
|
init_cli();
|
|
95462
95792
|
init_renderers();
|
|
@@ -101394,6 +101724,28 @@ for (const shim of rootShim._subcommands) {
|
|
|
101394
101724
|
subCommands[alias] = shimToCitty(shim);
|
|
101395
101725
|
}
|
|
101396
101726
|
}
|
|
101727
|
+
{
|
|
101728
|
+
const argv = process.argv.slice(2);
|
|
101729
|
+
const rawOpts = {};
|
|
101730
|
+
for (let i = 0; i < argv.length; i++) {
|
|
101731
|
+
const arg = argv[i];
|
|
101732
|
+
if (arg === "--json") rawOpts["json"] = true;
|
|
101733
|
+
else if (arg === "--human") rawOpts["human"] = true;
|
|
101734
|
+
else if (arg === "--quiet") rawOpts["quiet"] = true;
|
|
101735
|
+
else if (arg === "--field" && i + 1 < argv.length) rawOpts["field"] = argv[++i];
|
|
101736
|
+
else if (arg === "--fields" && i + 1 < argv.length) rawOpts["fields"] = argv[++i];
|
|
101737
|
+
else if (arg === "--mvi" && i + 1 < argv.length) rawOpts["mvi"] = argv[++i];
|
|
101738
|
+
}
|
|
101739
|
+
const formatResolution = resolveFormat(rawOpts);
|
|
101740
|
+
setFormatContext(formatResolution);
|
|
101741
|
+
const fieldResolution = resolveFieldContext(rawOpts);
|
|
101742
|
+
setFieldContext(fieldResolution);
|
|
101743
|
+
if (argv[0] === "-V") {
|
|
101744
|
+
const { cliOutput: cliOutput2 } = await Promise.resolve().then(() => (init_renderers(), renderers_exports));
|
|
101745
|
+
cliOutput2({ version: CLI_VERSION }, { command: "version" });
|
|
101746
|
+
process.exit(0);
|
|
101747
|
+
}
|
|
101748
|
+
}
|
|
101397
101749
|
if (process.argv[2] === "mcp") {
|
|
101398
101750
|
const mcpPath = join119(import.meta.dirname ?? "", "..", "mcp", "index.js");
|
|
101399
101751
|
const { spawn: spawn3 } = await import("node:child_process");
|