@cleocode/cleo 2026.5.101 → 2026.5.103

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 CHANGED
@@ -1531,6 +1531,13 @@ var init_attachment_schema = __esm({
1531
1531
  }
1532
1532
  });
1533
1533
 
1534
+ // packages/contracts/src/boundary.ts
1535
+ var init_boundary = __esm({
1536
+ "packages/contracts/src/boundary.ts"() {
1537
+ "use strict";
1538
+ }
1539
+ });
1540
+
1534
1541
  // packages/contracts/src/branch-lock.ts
1535
1542
  var init_branch_lock = __esm({
1536
1543
  "packages/contracts/src/branch-lock.ts"() {
@@ -3912,6 +3919,38 @@ var init_operations_registry = __esm({
3912
3919
  }
3913
3920
  ]
3914
3921
  },
3922
+ {
3923
+ gateway: "mutate",
3924
+ domain: "tasks",
3925
+ operation: "saga.detach",
3926
+ description: "tasks.saga.detach (mutate) \u2014 remove a Saga member relation (task_relations type=groups); idempotent; appends to .cleo/audit/saga-detach.jsonl (T10118)",
3927
+ tier: 0,
3928
+ idempotent: true,
3929
+ sessionRequired: false,
3930
+ requiredParams: ["sagaId", "memberId"],
3931
+ params: [
3932
+ {
3933
+ name: "sagaId",
3934
+ type: "string",
3935
+ required: true,
3936
+ description: "Saga task ID",
3937
+ cli: { positional: true }
3938
+ },
3939
+ {
3940
+ name: "memberId",
3941
+ type: "string",
3942
+ required: true,
3943
+ description: "Member task ID to detach from the Saga",
3944
+ cli: { positional: true }
3945
+ },
3946
+ {
3947
+ name: "reason",
3948
+ type: "string",
3949
+ required: false,
3950
+ description: "Human-readable reason recorded in the audit log entry"
3951
+ }
3952
+ ]
3953
+ },
3915
3954
  {
3916
3955
  gateway: "query",
3917
3956
  domain: "tasks",
@@ -3961,6 +4000,56 @@ var init_operations_registry = __esm({
3961
4000
  }
3962
4001
  ]
3963
4002
  },
4003
+ {
4004
+ // T10117 — detach I5-violating parentId and re-attach via task_relations
4005
+ // type=groups (ADR-073 §1.2 invariant I5). Idempotent.
4006
+ gateway: "mutate",
4007
+ domain: "tasks",
4008
+ operation: "saga.repair",
4009
+ description: "tasks.saga.repair (mutate) \u2014 detach I5-violating parentId and re-attach via task_relations type=groups; idempotent",
4010
+ tier: 0,
4011
+ idempotent: true,
4012
+ sessionRequired: false,
4013
+ requiredParams: ["sagaId"],
4014
+ params: [
4015
+ {
4016
+ name: "sagaId",
4017
+ type: "string",
4018
+ required: true,
4019
+ description: "Saga task ID (must have label=saga)",
4020
+ cli: { positional: true }
4021
+ }
4022
+ ]
4023
+ },
4024
+ {
4025
+ // T10121 — idempotent cron-safe saga auto-close repair. Re-applies
4026
+ // T10116 logic for sagas whose members reached 100% terminal via paths
4027
+ // OTHER than completeTask (bulk SQL, crash recovery, manual edits).
4028
+ // Supersedes T10098 standalone scope.
4029
+ gateway: "mutate",
4030
+ domain: "tasks",
4031
+ operation: "saga.reconcile",
4032
+ description: "tasks.saga.reconcile (mutate) \u2014 idempotent cron-safe saga auto-close repair; per-saga advisory lock + audit log; supersedes T10098",
4033
+ tier: 0,
4034
+ idempotent: true,
4035
+ sessionRequired: false,
4036
+ requiredParams: [],
4037
+ params: [
4038
+ {
4039
+ name: "sagaId",
4040
+ type: "string",
4041
+ required: false,
4042
+ description: "Optional saga task ID. Omit to walk every saga.",
4043
+ cli: { positional: true }
4044
+ },
4045
+ {
4046
+ name: "dryRun",
4047
+ type: "boolean",
4048
+ required: false,
4049
+ description: "Report what would happen without mutating rows or writing audit log"
4050
+ }
4051
+ ]
4052
+ },
3964
4053
  {
3965
4054
  gateway: "mutate",
3966
4055
  domain: "tasks",
@@ -11081,6 +11170,7 @@ var init_src2 = __esm({
11081
11170
  "packages/contracts/src/index.ts"() {
11082
11171
  init_acceptance_gate_schema();
11083
11172
  init_attachment_schema();
11173
+ init_boundary();
11084
11174
  init_branch_lock();
11085
11175
  init_changesets();
11086
11176
  init_cli_category();
@@ -30688,6 +30778,16 @@ var init_sticky2 = __esm({
30688
30778
  // packages/cleo/src/dispatch/domains/tasks.ts
30689
30779
  import { getLogger as getLogger15, getProjectRoot as getProjectRoot18 } from "@cleocode/core";
30690
30780
  import { createAttachmentStore as createAttachmentStore4 } from "@cleocode/core/internal";
30781
+ import {
30782
+ sagaAdd as coreSagaAdd,
30783
+ sagaCreate as coreSagaCreate,
30784
+ detachSagaMember as coreSagaDetach,
30785
+ sagaList as coreSagaList,
30786
+ sagaMembers as coreSagaMembers,
30787
+ reconcileSaga as coreSagaReconcile,
30788
+ repairSaga as coreSagaRepair,
30789
+ sagaRollup as coreSagaRollup
30790
+ } from "@cleocode/core/sagas";
30691
30791
  async function fetchTaskAttachments(projectRoot, taskId) {
30692
30792
  try {
30693
30793
  const store = createAttachmentStore4();
@@ -30709,136 +30809,49 @@ async function fetchTaskAttachments(projectRoot, taskId) {
30709
30809
  }
30710
30810
  }
30711
30811
  async function sagaCreate(params) {
30712
- const projectRoot = getProjectRoot18();
30713
30812
  const title = typeof params.title === "string" ? params.title : "";
30714
30813
  const description = typeof params.description === "string" ? params.description : void 0;
30715
30814
  const acceptance = Array.isArray(params.acceptance) ? params.acceptance : void 0;
30716
30815
  return wrapCoreResult(
30717
- await addTaskWithSessionScope(projectRoot, {
30718
- title,
30719
- description,
30720
- labels: ["saga"],
30721
- type: "epic",
30722
- acceptance
30723
- }),
30816
+ await coreSagaCreate(getProjectRoot18(), { title, description, acceptance }),
30724
30817
  "saga.create"
30725
30818
  );
30726
30819
  }
30727
30820
  async function sagaAdd(params) {
30728
- const projectRoot = getProjectRoot18();
30729
30821
  const sagaId = typeof params.sagaId === "string" ? params.sagaId : "";
30730
30822
  const epicId = typeof params.epicId === "string" ? params.epicId : "";
30731
- if (!sagaId || !epicId) {
30732
- return lafsError("E_INVALID_INPUT", "sagaId and epicId are required", "saga.add");
30733
- }
30734
- const sagaResult = await taskShow(projectRoot, sagaId);
30735
- if (!sagaResult.success || !sagaResult.data) {
30736
- return lafsError("E_NOT_FOUND", `Saga not found: ${sagaId}`, "saga.add");
30737
- }
30738
- const sagaTask = sagaResult.data.task;
30739
- const sagaLabels = sagaTask?.labels ?? [];
30740
- if (!sagaLabels.includes("saga")) {
30741
- return lafsError("E_INVALID_INPUT", `Task ${sagaId} does not have label='saga'`, "saga.add");
30742
- }
30743
- const epicResult = await taskShow(projectRoot, epicId);
30744
- if (!epicResult.success || !epicResult.data) {
30745
- return lafsError("E_NOT_FOUND", `Epic not found: ${epicId}`, "saga.add");
30746
- }
30747
- const epicType = epicResult.data.task?.type;
30748
- if (epicType !== "epic") {
30749
- return lafsError(
30750
- "E_INVALID_INPUT",
30751
- `Task ${epicId} has type='${String(epicType)}', expected type='epic'`,
30752
- "saga.add"
30753
- );
30754
- }
30755
- const relResult = await taskRelatesAdd(projectRoot, sagaId, epicId, "groups", void 0);
30756
- if (!relResult.success) {
30757
- return lafsError(
30758
- "E_GENERAL",
30759
- relResult.error?.message ?? "Failed to link Epic to Saga",
30760
- "saga.add"
30761
- );
30762
- }
30763
- return lafsSuccess({ sagaId, epicId, added: relResult.data?.added ?? true }, "saga.add");
30823
+ return wrapCoreResult(await coreSagaAdd(getProjectRoot18(), { sagaId, epicId }), "saga.add");
30824
+ }
30825
+ async function sagaDetach(params) {
30826
+ const sagaId = typeof params.sagaId === "string" ? params.sagaId : "";
30827
+ const memberId = typeof params.memberId === "string" ? params.memberId : "";
30828
+ const reason = typeof params.reason === "string" ? params.reason : void 0;
30829
+ return wrapCoreResult(
30830
+ await coreSagaDetach(getProjectRoot18(), { sagaId, memberId, reason }),
30831
+ "saga.detach"
30832
+ );
30764
30833
  }
30765
30834
  async function sagaList() {
30766
- const projectRoot = getProjectRoot18();
30767
- const result = await taskList(projectRoot, { type: "epic", label: "saga" });
30768
- if (!result.success) {
30769
- return lafsError("E_GENERAL", result.error?.message ?? "Failed to list Sagas", "saga.list");
30770
- }
30771
- const tasks = result.data?.tasks ?? [];
30772
- const topLevel = tasks.filter((t) => {
30773
- const parentId = t.parentId;
30774
- return !parentId;
30775
- });
30776
- return lafsSuccess({ sagas: topLevel, total: topLevel.length }, "saga.list");
30835
+ return wrapCoreResult(await coreSagaList(getProjectRoot18()), "saga.list");
30777
30836
  }
30778
30837
  async function sagaMembers(params) {
30779
- const projectRoot = getProjectRoot18();
30780
30838
  const sagaId = typeof params.sagaId === "string" ? params.sagaId : "";
30781
- if (!sagaId) {
30782
- return lafsError("E_INVALID_INPUT", "sagaId is required", "saga.members");
30783
- }
30784
- const result = await taskRelates(projectRoot, sagaId);
30785
- if (!result.success) {
30786
- return lafsError(
30787
- "E_GENERAL",
30788
- result.error?.message ?? "Failed to list Saga members",
30789
- "saga.members"
30790
- );
30791
- }
30792
- const relations = result.data?.relations ?? [];
30793
- const members = relations.filter((r) => r.type === "groups");
30794
- return lafsSuccess(
30795
- {
30796
- sagaId,
30797
- members: members.map((r) => ({ epicId: r.taskId, type: r.type, reason: r.reason })),
30798
- total: members.length
30799
- },
30800
- "saga.members"
30801
- );
30839
+ return wrapCoreResult(await coreSagaMembers(getProjectRoot18(), { sagaId }), "saga.members");
30802
30840
  }
30803
30841
  async function sagaRollup(params) {
30804
- const projectRoot = getProjectRoot18();
30805
30842
  const sagaId = typeof params.sagaId === "string" ? params.sagaId : "";
30806
- if (!sagaId) {
30807
- return lafsError("E_INVALID_INPUT", "sagaId is required", "saga.rollup");
30808
- }
30809
- const relResult = await taskRelates(projectRoot, sagaId);
30810
- if (!relResult.success) {
30811
- return lafsError(
30812
- "E_GENERAL",
30813
- relResult.error?.message ?? "Failed to fetch Saga members for rollup",
30814
- "saga.rollup"
30815
- );
30816
- }
30817
- const members = (relResult.data?.relations ?? []).filter((r) => r.type === "groups");
30818
- const total = members.length;
30819
- if (total === 0) {
30820
- return lafsSuccess(
30821
- { sagaId, total: 0, done: 0, active: 0, blocked: 0, pending: 0, completionPct: 0 },
30822
- "saga.rollup"
30823
- );
30824
- }
30825
- const shows = await Promise.all(members.map((m) => taskShow(projectRoot, m.taskId)));
30826
- let done = 0;
30827
- let active = 0;
30828
- let blocked = 0;
30829
- let pending = 0;
30830
- for (const r of shows) {
30831
- if (!r.success) continue;
30832
- const status = r.data?.task?.status ?? "pending";
30833
- if (status === "done") done++;
30834
- else if (status === "active") active++;
30835
- else if (status === "blocked") blocked++;
30836
- else pending++;
30837
- }
30838
- const completionPct = total > 0 ? Math.round(done / total * 100) : 0;
30839
- return lafsSuccess(
30840
- { sagaId, total, done, active, blocked, pending, completionPct },
30841
- "saga.rollup"
30843
+ return wrapCoreResult(await coreSagaRollup(getProjectRoot18(), { sagaId }), "saga.rollup");
30844
+ }
30845
+ async function sagaRepair(params) {
30846
+ const sagaId = typeof params.sagaId === "string" ? params.sagaId : "";
30847
+ return wrapCoreResult(await coreSagaRepair(getProjectRoot18(), { sagaId }), "saga.repair");
30848
+ }
30849
+ async function sagaReconcile(params) {
30850
+ const sagaId = typeof params.sagaId === "string" && params.sagaId.length > 0 ? params.sagaId : void 0;
30851
+ const dryRun = params.dryRun === true;
30852
+ return wrapCoreResult(
30853
+ await coreSagaReconcile(getProjectRoot18(), { sagaId, dryRun }),
30854
+ "saga.reconcile"
30842
30855
  );
30843
30856
  }
30844
30857
  var _tasksTypedHandler, QUERY_OPS11, MUTATE_OPS10, TasksHandler;
@@ -31296,7 +31309,13 @@ var init_tasks3 = __esm({
31296
31309
  "unclaim",
31297
31310
  // Saga sub-domain (ADR-073)
31298
31311
  "saga.create",
31299
- "saga.add"
31312
+ "saga.add",
31313
+ // T10117 — repair an I5-violating saga (detach parentId, write groups edge).
31314
+ "saga.repair",
31315
+ // T10118 — repair verb for ADR-073 §1.2 I7 violations (detach saga member).
31316
+ "saga.detach",
31317
+ // T10121 — idempotent cron-safe auto-close repair (supersedes T10098 scope).
31318
+ "saga.reconcile"
31300
31319
  ]);
31301
31320
  TasksHandler = class {
31302
31321
  // -----------------------------------------------------------------------
@@ -31393,6 +31412,36 @@ var init_tasks3 = __esm({
31393
31412
  startTime
31394
31413
  );
31395
31414
  }
31415
+ if (operation === "saga.repair") {
31416
+ const envelope = await sagaRepair(params ?? {});
31417
+ return wrapResult(
31418
+ envelopeToEngineResult(envelope),
31419
+ "mutate",
31420
+ "tasks",
31421
+ operation,
31422
+ startTime
31423
+ );
31424
+ }
31425
+ if (operation === "saga.detach") {
31426
+ const envelope = await sagaDetach(params ?? {});
31427
+ return wrapResult(
31428
+ envelopeToEngineResult(envelope),
31429
+ "mutate",
31430
+ "tasks",
31431
+ operation,
31432
+ startTime
31433
+ );
31434
+ }
31435
+ if (operation === "saga.reconcile") {
31436
+ const envelope = await sagaReconcile(params ?? {});
31437
+ return wrapResult(
31438
+ envelopeToEngineResult(envelope),
31439
+ "mutate",
31440
+ "tasks",
31441
+ operation,
31442
+ startTime
31443
+ );
31444
+ }
31396
31445
  } catch (error) {
31397
31446
  getLogger15("domain:tasks").error(
31398
31447
  { gateway: "mutate", domain: "tasks", operation, err: error },
@@ -31465,7 +31514,13 @@ var init_tasks3 = __esm({
31465
31514
  "unclaim",
31466
31515
  // Saga sub-domain (ADR-073)
31467
31516
  "saga.create",
31468
- "saga.add"
31517
+ "saga.add",
31518
+ // T10117 — repair an I5-violating saga.
31519
+ "saga.repair",
31520
+ // T10118 — repair verb for ADR-073 §1.2 I7 violations
31521
+ "saga.detach",
31522
+ // T10121 — idempotent cron-safe auto-close repair.
31523
+ "saga.reconcile"
31469
31524
  ]
31470
31525
  };
31471
31526
  }
@@ -40645,6 +40700,10 @@ var init_complete = __esm({
40645
40700
  if (Array.isArray(unblockedTasks) && unblockedTasks.length > 0) {
40646
40701
  output2["unblockedTasks"] = unblockedTasks;
40647
40702
  }
40703
+ const worktreeAutoComplete = data?.worktreeAutoComplete;
40704
+ if (worktreeAutoComplete && typeof worktreeAutoComplete === "object") {
40705
+ output2["worktreeAutoComplete"] = worktreeAutoComplete;
40706
+ }
40648
40707
  cliOutput(output2, { command: "complete", operation: "tasks.complete" });
40649
40708
  }
40650
40709
  });
@@ -45844,6 +45903,20 @@ var init_doctor = __esm({
45844
45903
  type: "boolean",
45845
45904
  description: "Audit orphaned CLEO-generated temp directories and report what cleo gc --temp would remove (T9043)"
45846
45905
  },
45906
+ /**
45907
+ * T10119: audit every Saga (`type='epic'` + `label='saga'`) for
45908
+ * ADR-073 §1.2 invariant violations (I5/I7 + depth ladder) and
45909
+ * auto-close drift. Read-only; non-zero exit when any I-invariant
45910
+ * fails so the check is CI-gateable.
45911
+ *
45912
+ * @task T10119
45913
+ * @saga T10113
45914
+ * @epic T10209
45915
+ */
45916
+ "audit-sagas": {
45917
+ type: "boolean",
45918
+ description: "Audit every Saga for ADR-073 \xA71.2 invariant violations (I5/I7/depth) + auto-close drift (T10119)"
45919
+ },
45847
45920
  /**
45848
45921
  * T9983: migrate the worktree-include file location from
45849
45922
  * `<root>/.cleo/worktree-include` (legacy) to `<root>/.worktreeinclude`
@@ -46250,6 +46323,17 @@ var init_doctor = __esm({
46250
46323
  if (checkResult.details?.["orphans"] && checkResult.details["orphans"].length > 0 && (process.exitCode === void 0 || process.exitCode === 0)) {
46251
46324
  process.exitCode = 2;
46252
46325
  }
46326
+ } else if (args["audit-sagas"]) {
46327
+ progress.step(0, "Auditing Saga hierarchy for ADR-073 invariants");
46328
+ const { auditSagaHierarchy } = await import("@cleocode/core/doctor/saga-audit.js");
46329
+ const projectRoot = getProjectRoot33();
46330
+ const result = await auditSagaHierarchy(projectRoot);
46331
+ const summary = `Saga audit complete \u2014 ${result.sagas.length} saga(s) inspected, ${result.count} invariant violation(s), ${result.driftCount} drift warning(s)`;
46332
+ progress.complete(summary);
46333
+ cliOutput(result, { command: "doctor", operation: "doctor.audit-sagas" });
46334
+ if (result.count > 0 && (process.exitCode === void 0 || process.exitCode === 0)) {
46335
+ process.exitCode = 2;
46336
+ }
46253
46337
  } else {
46254
46338
  progress.step(0, "Checking CLEO directory");
46255
46339
  await dispatchFromCli(
@@ -46290,6 +46374,34 @@ var init_doctor = __esm({
46290
46374
  } catch {
46291
46375
  progress.complete("Health check complete");
46292
46376
  }
46377
+ try {
46378
+ const projectRoot = getProjectRoot33();
46379
+ const { auditSagaHierarchy } = await import("@cleocode/core/doctor/saga-audit.js");
46380
+ const sagaAudit = await auditSagaHierarchy(projectRoot);
46381
+ if (sagaAudit.sagas.length === 0) {
46382
+ humanLine("\nSaga Hierarchy: no sagas found in tasks.db");
46383
+ } else {
46384
+ const header = `
46385
+ Saga Hierarchy (${sagaAudit.sagas.length} saga(s), ${sagaAudit.count} violation(s), ${sagaAudit.driftCount} drift warning(s)):`;
46386
+ humanLine(header);
46387
+ for (const s of sagaAudit.sagas) {
46388
+ const violationSuffix = s.violations.length > 0 ? `, ${s.violations.length} violation(s)` : "";
46389
+ humanLine(
46390
+ ` ${s.sagaId} \xB7 status=${s.status} \xB7 ${s.doneCount}/${s.memberCount} members done${violationSuffix}`
46391
+ );
46392
+ for (const v of s.violations) {
46393
+ humanLine(` [${v.kind}] ${v.message}`);
46394
+ }
46395
+ }
46396
+ }
46397
+ if (sagaAudit.count > 0 && (process.exitCode === void 0 || process.exitCode === 0)) {
46398
+ process.exitCode = 2;
46399
+ }
46400
+ } catch (err) {
46401
+ const msg = err instanceof Error ? err.message : String(err);
46402
+ humanLine(`
46403
+ Saga Hierarchy: audit skipped (${msg})`);
46404
+ }
46293
46405
  }
46294
46406
  } catch (err) {
46295
46407
  progress.error("Health check failed");
@@ -59755,7 +59867,7 @@ __export(saga_exports, {
59755
59867
  sagaCommand: () => sagaCommand
59756
59868
  });
59757
59869
  import { parseAcceptanceCriteria } from "@cleocode/core";
59758
- var createCommand3, addCommand11, listCommand22, membersCommand, rollupCommand2, sagaCommand;
59870
+ var createCommand3, addCommand11, detachCommand2, listCommand22, membersCommand, repairCommand, reconcileCommand5, rollupCommand2, sagaCommand;
59759
59871
  var init_saga = __esm({
59760
59872
  "packages/cleo/src/cli/commands/saga.ts"() {
59761
59873
  "use strict";
@@ -59827,6 +59939,38 @@ var init_saga = __esm({
59827
59939
  );
59828
59940
  }
59829
59941
  });
59942
+ detachCommand2 = defineCommand({
59943
+ meta: {
59944
+ name: "detach",
59945
+ description: "Remove a Saga member relation (task_relations type=groups) \u2014 idempotent, audit-logged"
59946
+ },
59947
+ args: {
59948
+ sagaId: {
59949
+ type: "positional",
59950
+ description: "Saga task ID",
59951
+ required: true
59952
+ },
59953
+ memberId: {
59954
+ type: "positional",
59955
+ description: "Member task ID to detach from the Saga",
59956
+ required: true
59957
+ },
59958
+ reason: {
59959
+ type: "string",
59960
+ description: "Human-readable reason recorded in the audit log entry",
59961
+ required: false
59962
+ }
59963
+ },
59964
+ async run({ args }) {
59965
+ await dispatchFromCli(
59966
+ "mutate",
59967
+ "tasks",
59968
+ "saga.detach",
59969
+ { sagaId: args.sagaId, memberId: args.memberId, reason: args.reason },
59970
+ { command: "saga", operation: "tasks.saga.detach" }
59971
+ );
59972
+ }
59973
+ });
59830
59974
  listCommand22 = defineCommand({
59831
59975
  meta: {
59832
59976
  name: "list",
@@ -59858,6 +60002,56 @@ var init_saga = __esm({
59858
60002
  );
59859
60003
  }
59860
60004
  });
60005
+ repairCommand = defineCommand({
60006
+ meta: {
60007
+ name: "repair",
60008
+ description: "Detach an I5-violating parentId from a Saga and re-attach via task_relations.type='groups' (ADR-073 \xA71.2). Idempotent."
60009
+ },
60010
+ args: {
60011
+ sagaId: {
60012
+ type: "positional",
60013
+ description: "Saga task ID (must have label=saga)",
60014
+ required: true
60015
+ }
60016
+ },
60017
+ async run({ args }) {
60018
+ await dispatchFromCli(
60019
+ "mutate",
60020
+ "tasks",
60021
+ "saga.repair",
60022
+ { sagaId: args.sagaId },
60023
+ { command: "saga", operation: "tasks.saga.repair" }
60024
+ );
60025
+ }
60026
+ });
60027
+ reconcileCommand5 = defineCommand({
60028
+ meta: {
60029
+ name: "reconcile",
60030
+ description: "Idempotent cron-safe saga auto-close repair \u2014 re-applies T10116 logic for state changed outside completeTask"
60031
+ },
60032
+ args: {
60033
+ sagaId: {
60034
+ type: "positional",
60035
+ description: "Optional saga task ID. Omit to walk every saga.",
60036
+ required: false
60037
+ },
60038
+ "dry-run": {
60039
+ type: "boolean",
60040
+ description: "Report what would happen without mutating rows or writing audit log",
60041
+ required: false
60042
+ }
60043
+ },
60044
+ async run({ args }) {
60045
+ const sagaId = typeof args.sagaId === "string" && args.sagaId.length > 0 ? args.sagaId : void 0;
60046
+ await dispatchFromCli(
60047
+ "mutate",
60048
+ "tasks",
60049
+ "saga.reconcile",
60050
+ { sagaId, dryRun: args["dry-run"] === true },
60051
+ { command: "saga", operation: "tasks.saga.reconcile" }
60052
+ );
60053
+ }
60054
+ });
59861
60055
  rollupCommand2 = defineCommand({
59862
60056
  meta: {
59863
60057
  name: "rollup",
@@ -59886,9 +60080,12 @@ var init_saga = __esm({
59886
60080
  subCommands: {
59887
60081
  create: createCommand3,
59888
60082
  add: addCommand11,
60083
+ detach: detachCommand2,
59889
60084
  list: listCommand22,
59890
60085
  members: membersCommand,
59891
- rollup: rollupCommand2
60086
+ rollup: rollupCommand2,
60087
+ repair: repairCommand,
60088
+ reconcile: reconcileCommand5
59892
60089
  },
59893
60090
  async run({ cmd, rawArgs }) {
59894
60091
  const firstArg = rawArgs?.find((a) => !a.startsWith("-"));
@@ -61464,7 +61661,7 @@ __export(sequence_exports, {
61464
61661
  sequenceCommand: () => sequenceCommand
61465
61662
  });
61466
61663
  import { getProjectRoot as getProjectRoot40 } from "@cleocode/core/internal";
61467
- var showCommand12, checkCommand6, repairCommand, sequenceCommand;
61664
+ var showCommand12, checkCommand6, repairCommand2, sequenceCommand;
61468
61665
  var init_sequence = __esm({
61469
61666
  "packages/cleo/src/cli/commands/sequence.ts"() {
61470
61667
  "use strict";
@@ -61495,7 +61692,7 @@ var init_sequence = __esm({
61495
61692
  );
61496
61693
  }
61497
61694
  });
61498
- repairCommand = defineCommand({
61695
+ repairCommand2 = defineCommand({
61499
61696
  meta: { name: "repair", description: "Reset counter to max + 1 if behind" },
61500
61697
  async run() {
61501
61698
  const { repairSequence } = await import("@cleocode/core/internal");
@@ -61519,7 +61716,7 @@ var init_sequence = __esm({
61519
61716
  subCommands: {
61520
61717
  show: showCommand12,
61521
61718
  check: checkCommand6,
61522
- repair: repairCommand
61719
+ repair: repairCommand2
61523
61720
  },
61524
61721
  async run({ cmd, rawArgs }) {
61525
61722
  const firstArg = rawArgs?.find((a) => !a.startsWith("-"));
@@ -64246,7 +64443,7 @@ var sync_exports = {};
64246
64443
  __export(sync_exports, {
64247
64444
  syncCommand: () => syncCommand6
64248
64445
  });
64249
- var linksRemoveCommand, linksCommand2, reconcileCommand5, syncCommand6;
64446
+ var linksRemoveCommand, linksCommand2, reconcileCommand6, syncCommand6;
64250
64447
  var init_sync = __esm({
64251
64448
  "packages/cleo/src/cli/commands/sync.ts"() {
64252
64449
  "use strict";
@@ -64308,7 +64505,7 @@ var init_sync = __esm({
64308
64505
  );
64309
64506
  }
64310
64507
  });
64311
- reconcileCommand5 = defineCommand({
64508
+ reconcileCommand6 = defineCommand({
64312
64509
  meta: {
64313
64510
  name: "reconcile",
64314
64511
  description: "Reconcile external tasks from a JSON file against CLEO tasks"
@@ -64363,7 +64560,7 @@ var init_sync = __esm({
64363
64560
  meta: { name: "sync", description: "External task synchronisation management" },
64364
64561
  subCommands: {
64365
64562
  links: linksCommand2,
64366
- reconcile: reconcileCommand5
64563
+ reconcile: reconcileCommand6
64367
64564
  },
64368
64565
  async run({ cmd, rawArgs }) {
64369
64566
  const firstArg = rawArgs?.find((a) => !a.startsWith("-"));