@ordewell/core 0.11.2 → 0.12.0

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.
Files changed (42) hide show
  1. package/AUTHORS.md +3 -1
  2. package/dist/{IRunner-ihalYfTo.d.mts → IRunner-BwzyUVIL.d.mts} +62 -18
  3. package/dist/{IRunner-DOMtDTVt.d.ts → IRunner-DjJkYwko.d.ts} +62 -18
  4. package/dist/{ModeResolver-DyXeZ9ib.d.ts → ModeResolver-CHsaoV7M.d.ts} +1 -1
  5. package/dist/{ModeResolver-BDAgouuE.d.mts → ModeResolver-b_7bPlBS.d.mts} +1 -1
  6. package/dist/{Task-BL4Idm9r.d.mts → Task-BTEH-ztX.d.mts} +301 -26
  7. package/dist/{Task-BL4Idm9r.d.ts → Task-BTEH-ztX.d.ts} +301 -26
  8. package/dist/{chunk-MYXMIVWA.mjs → chunk-BFLVOYNR.mjs} +3 -3
  9. package/dist/{chunk-YAFNYNFX.mjs → chunk-BKTDYGIP.mjs} +14 -2
  10. package/dist/chunk-BKTDYGIP.mjs.map +1 -0
  11. package/dist/{chunk-QTZ5XTBY.mjs → chunk-F6WS3JLQ.mjs} +446 -10
  12. package/dist/chunk-F6WS3JLQ.mjs.map +1 -0
  13. package/dist/{chunk-7WNLN63J.mjs → chunk-HP2LNKST.mjs} +315 -51
  14. package/dist/chunk-HP2LNKST.mjs.map +1 -0
  15. package/dist/index.d.mts +242 -78
  16. package/dist/index.d.ts +242 -78
  17. package/dist/index.js +5598 -2005
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +4701 -1782
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/parsing.d.mts +2 -2
  22. package/dist/parsing.d.ts +2 -2
  23. package/dist/parsing.js.map +1 -1
  24. package/dist/parsing.mjs +3 -3
  25. package/dist/plan-utils.d.mts +4 -4
  26. package/dist/plan-utils.d.ts +4 -4
  27. package/dist/plan-utils.js +135 -19
  28. package/dist/plan-utils.js.map +1 -1
  29. package/dist/plan-utils.mjs +25 -3
  30. package/dist/{runSettingsText-CYMhTWfw.d.ts → runSettingsText-CvZ40IPv.d.ts} +1086 -190
  31. package/dist/{runSettingsText-tnmvdSfS.d.mts → runSettingsText-x-YML2ay.d.mts} +1086 -190
  32. package/dist/testing.d.mts +18 -2
  33. package/dist/testing.d.ts +18 -2
  34. package/dist/testing.js +71 -7
  35. package/dist/testing.js.map +1 -1
  36. package/dist/testing.mjs +68 -7
  37. package/dist/testing.mjs.map +1 -1
  38. package/package.json +2 -1
  39. package/dist/chunk-7WNLN63J.mjs.map +0 -1
  40. package/dist/chunk-QTZ5XTBY.mjs.map +0 -1
  41. package/dist/chunk-YAFNYNFX.mjs.map +0 -1
  42. /package/dist/{chunk-MYXMIVWA.mjs.map → chunk-BFLVOYNR.mjs.map} +0 -0
@@ -1,5 +1,5 @@
1
- import { R as IRunnerSession, ar as QueuedTaskMessage, b6 as StructuredTurnEnd, b5 as StructuredEvent, bc as TaskCompleteArgs, t as CheckpointAnswer, aX as ScriptExit, be as TaskMessageFrom, aE as RunnerCommand, S as InvokedCommand, k as ApprovalDecision, O as IConfig, P as IFileSystem } from './IRunner-ihalYfTo.mjs';
2
- import { y as IntegrationDisposal, aA as RunnerSessionCost, x as IWorktreeIsolation, J as IsolationAvailability, R as IsolationMergeResult, b4 as TreeSnapshot, aF as SetupFailure, U as IsolationPruneResult, V as IsolationRemoval, S as IsolationOutcome, ao as RepairEvidence, X as IsolationRun, aS as Task, ah as PrepareIntent, ai as PreparedTask, q as HandoffCommit, K as IsolationHandoff } from './Task-BL4Idm9r.mjs';
1
+ import { R as IRunnerSession, ar as QueuedTaskMessage, b6 as StructuredTurnEnd, b5 as StructuredEvent, bc as TaskCompleteArgs, t as CheckpointAnswer, aX as ScriptExit, be as TaskMessageFrom, aE as RunnerCommand, S as InvokedCommand, k as ApprovalDecision, O as IConfig, P as IFileSystem } from './IRunner-BwzyUVIL.mjs';
2
+ import { J as IntegrationDisposal, aL as RunnerSessionCost, z as IWorktreeIsolation, L as IsolationAvailability, T as IsolationMergeResult, bf as TreeSnapshot, aQ as SetupFailure, W as IsolationPruneResult, X as IsolationRemoval, U as IsolationOutcome, _ as IsolationRevertResult, aH as RevertCommand, aw as RepairEvidence, a0 as IsolationRun, b1 as Task, ao as PrepareIntent, ap as PreparedTask, q as HandoffCommit, a7 as LandedWork, aI as RevertWatch, M as IsolationHandoff } from './Task-BTEH-ztX.mjs';
3
3
  import 'child_process';
4
4
  import 'zod/v4';
5
5
 
@@ -131,6 +131,9 @@ type FakeIsolationCall = {
131
131
  } | {
132
132
  op: 'discard';
133
133
  integration: IntegrationDisposal;
134
+ } | {
135
+ op: 'readLanded' | 'revert';
136
+ taskIds: readonly string[];
134
137
  };
135
138
  /**
136
139
  * An in-memory {@link IWorktreeIsolation} for scheduling tests: no git, no
@@ -179,17 +182,26 @@ declare class FakeWorktreeIsolation implements IWorktreeIsolation {
179
182
  removal: IsolationRemoval;
180
183
  /** Per task id; a task not listed integrates as `merged`. */
181
184
  outcomes: Map<string, IsolationOutcome>;
185
+ /** What `revert` stops with; a revert that goes through when null. */
186
+ revertStop: Exclude<IsolationRevertResult, {
187
+ outcome: 'reverted';
188
+ }> | null;
189
+ /** What `readLanded` finds of a task's work in the user's branch, by task id. */
190
+ inBranch: Map<string, RevertCommand[]>;
182
191
  /** Per task id, what `verifyRepair` finds; a task not listed passes. */
183
192
  repairEvidence: Map<string, RepairEvidence>;
184
193
  calls: FakeIsolationCall[];
185
194
  private holds;
186
195
  private verifyHolds;
196
+ private revertHold;
187
197
  private runCount;
188
198
  private log;
189
199
  /** Task ids in the order `op` was called for them. */
190
200
  taskIdsFor(op: 'prepare' | 'reopen' | 'verifyRepair' | 'integrate' | 'release'): string[];
191
201
  /** Make `integrate` for this task wait until the returned function is called. */
192
202
  holdIntegration(taskId: string): () => void;
203
+ /** Make the next `revert` wait, past its `refusal`, until the returned function is called. */
204
+ holdRevert(): () => void;
193
205
  /** Make `verifyRepair` for this task wait until the returned function is called. */
194
206
  holdVerification(taskId: string): () => void;
195
207
  isActive(workspaceRoot: string): Promise<IsolationAvailability>;
@@ -204,6 +216,10 @@ declare class FakeWorktreeIsolation implements IWorktreeIsolation {
204
216
  verifyRepair(task: Task, _run: IsolationRun): Promise<RepairEvidence>;
205
217
  /** Like git: the landing is recorded and persisted before the (held) merge, and cleared once it settles. */
206
218
  integrate(task: Task, run: IsolationRun, persist?: () => void, commit?: HandoffCommit): Promise<IsolationOutcome>;
219
+ /** Newest landing first, read as the plan's highest order: scheduling tests land in plan order. */
220
+ readLanded(run: IsolationRun, taskIds: readonly string[]): Promise<LandedWork>;
221
+ /** Like git: the turn, then the judgement, then the records go in one step with the tasks back. */
222
+ revert(run: IsolationRun, taskIds: readonly string[], watch: RevertWatch): Promise<IsolationRevertResult>;
207
223
  release(run: IsolationRun, taskId: string, opts: {
208
224
  keep: boolean;
209
225
  }): Promise<IsolationRemoval>;
package/dist/testing.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as IRunnerSession, ar as QueuedTaskMessage, b6 as StructuredTurnEnd, b5 as StructuredEvent, bc as TaskCompleteArgs, t as CheckpointAnswer, aX as ScriptExit, be as TaskMessageFrom, aE as RunnerCommand, S as InvokedCommand, k as ApprovalDecision, O as IConfig, P as IFileSystem } from './IRunner-DOMtDTVt.js';
2
- import { y as IntegrationDisposal, aA as RunnerSessionCost, x as IWorktreeIsolation, J as IsolationAvailability, R as IsolationMergeResult, b4 as TreeSnapshot, aF as SetupFailure, U as IsolationPruneResult, V as IsolationRemoval, S as IsolationOutcome, ao as RepairEvidence, X as IsolationRun, aS as Task, ah as PrepareIntent, ai as PreparedTask, q as HandoffCommit, K as IsolationHandoff } from './Task-BL4Idm9r.js';
1
+ import { R as IRunnerSession, ar as QueuedTaskMessage, b6 as StructuredTurnEnd, b5 as StructuredEvent, bc as TaskCompleteArgs, t as CheckpointAnswer, aX as ScriptExit, be as TaskMessageFrom, aE as RunnerCommand, S as InvokedCommand, k as ApprovalDecision, O as IConfig, P as IFileSystem } from './IRunner-DjJkYwko.js';
2
+ import { J as IntegrationDisposal, aL as RunnerSessionCost, z as IWorktreeIsolation, L as IsolationAvailability, T as IsolationMergeResult, bf as TreeSnapshot, aQ as SetupFailure, W as IsolationPruneResult, X as IsolationRemoval, U as IsolationOutcome, _ as IsolationRevertResult, aH as RevertCommand, aw as RepairEvidence, a0 as IsolationRun, b1 as Task, ao as PrepareIntent, ap as PreparedTask, q as HandoffCommit, a7 as LandedWork, aI as RevertWatch, M as IsolationHandoff } from './Task-BTEH-ztX.js';
3
3
  import 'child_process';
4
4
  import 'zod/v4';
5
5
 
@@ -131,6 +131,9 @@ type FakeIsolationCall = {
131
131
  } | {
132
132
  op: 'discard';
133
133
  integration: IntegrationDisposal;
134
+ } | {
135
+ op: 'readLanded' | 'revert';
136
+ taskIds: readonly string[];
134
137
  };
135
138
  /**
136
139
  * An in-memory {@link IWorktreeIsolation} for scheduling tests: no git, no
@@ -179,17 +182,26 @@ declare class FakeWorktreeIsolation implements IWorktreeIsolation {
179
182
  removal: IsolationRemoval;
180
183
  /** Per task id; a task not listed integrates as `merged`. */
181
184
  outcomes: Map<string, IsolationOutcome>;
185
+ /** What `revert` stops with; a revert that goes through when null. */
186
+ revertStop: Exclude<IsolationRevertResult, {
187
+ outcome: 'reverted';
188
+ }> | null;
189
+ /** What `readLanded` finds of a task's work in the user's branch, by task id. */
190
+ inBranch: Map<string, RevertCommand[]>;
182
191
  /** Per task id, what `verifyRepair` finds; a task not listed passes. */
183
192
  repairEvidence: Map<string, RepairEvidence>;
184
193
  calls: FakeIsolationCall[];
185
194
  private holds;
186
195
  private verifyHolds;
196
+ private revertHold;
187
197
  private runCount;
188
198
  private log;
189
199
  /** Task ids in the order `op` was called for them. */
190
200
  taskIdsFor(op: 'prepare' | 'reopen' | 'verifyRepair' | 'integrate' | 'release'): string[];
191
201
  /** Make `integrate` for this task wait until the returned function is called. */
192
202
  holdIntegration(taskId: string): () => void;
203
+ /** Make the next `revert` wait, past its `refusal`, until the returned function is called. */
204
+ holdRevert(): () => void;
193
205
  /** Make `verifyRepair` for this task wait until the returned function is called. */
194
206
  holdVerification(taskId: string): () => void;
195
207
  isActive(workspaceRoot: string): Promise<IsolationAvailability>;
@@ -204,6 +216,10 @@ declare class FakeWorktreeIsolation implements IWorktreeIsolation {
204
216
  verifyRepair(task: Task, _run: IsolationRun): Promise<RepairEvidence>;
205
217
  /** Like git: the landing is recorded and persisted before the (held) merge, and cleared once it settles. */
206
218
  integrate(task: Task, run: IsolationRun, persist?: () => void, commit?: HandoffCommit): Promise<IsolationOutcome>;
219
+ /** Newest landing first, read as the plan's highest order: scheduling tests land in plan order. */
220
+ readLanded(run: IsolationRun, taskIds: readonly string[]): Promise<LandedWork>;
221
+ /** Like git: the turn, then the judgement, then the records go in one step with the tasks back. */
222
+ revert(run: IsolationRun, taskIds: readonly string[], watch: RevertWatch): Promise<IsolationRevertResult>;
207
223
  release(run: IsolationRun, taskId: string, opts: {
208
224
  keep: boolean;
209
225
  }): Promise<IsolationRemoval>;
package/dist/testing.js CHANGED
@@ -45,6 +45,9 @@ function integrationBranchFor(runId) {
45
45
  function noRemoval() {
46
46
  return { preserved: [], refused: [] };
47
47
  }
48
+ function landedInRepo(run, record, repoPath) {
49
+ return !!record.repos[repoPath]?.changed || run.landings?.[record.taskId]?.[repoPath] !== void 0;
50
+ }
48
51
  function handoffOf(run) {
49
52
  const merged = Object.values(run.tasks).filter((r) => r.status === "merged" && !r.inHead).sort((a, b) => a.order - b.order);
50
53
  const entry = (r) => ({
@@ -60,7 +63,7 @@ function handoffOf(run) {
60
63
  baseRef: repo.baseRef,
61
64
  ...repo.baseBranch ? { baseBranch: repo.baseBranch } : {},
62
65
  ...repo.startedDetached ? { startedDetached: true } : {},
63
- landed: merged.filter((r) => r.repos[repo.path]?.changed).map(entry)
66
+ landed: merged.filter((r) => landedInRepo(run, r, repo.path)).map(entry)
64
67
  })),
65
68
  landed: merged.map(entry)
66
69
  };
@@ -107,6 +110,7 @@ function fakeConfig(overrides = {}) {
107
110
  // Off so a test that is not about the allowlist sees every prompt it raises.
108
111
  approvalDefaults: false,
109
112
  effectAllowlist: [],
113
+ notifyCommand: [],
110
114
  webReadBudget: 40,
111
115
  plannerNativeShell: false,
112
116
  setProviderModelLists: () => {
@@ -377,11 +381,16 @@ var FakeWorktreeIsolation = class {
377
381
  removal = noRemoval();
378
382
  /** Per task id; a task not listed integrates as `merged`. */
379
383
  outcomes = /* @__PURE__ */ new Map();
384
+ /** What `revert` stops with; a revert that goes through when null. */
385
+ revertStop = null;
386
+ /** What `readLanded` finds of a task's work in the user's branch, by task id. */
387
+ inBranch = /* @__PURE__ */ new Map();
380
388
  /** Per task id, what `verifyRepair` finds; a task not listed passes. */
381
389
  repairEvidence = /* @__PURE__ */ new Map();
382
390
  calls = [];
383
391
  holds = /* @__PURE__ */ new Map();
384
392
  verifyHolds = /* @__PURE__ */ new Map();
393
+ revertHold = null;
385
394
  runCount = 0;
386
395
  log(call) {
387
396
  this.calls.push(call);
@@ -398,6 +407,14 @@ var FakeWorktreeIsolation = class {
398
407
  }));
399
408
  return open;
400
409
  }
410
+ /** Make the next `revert` wait, past its `refusal`, until the returned function is called. */
411
+ holdRevert() {
412
+ let open;
413
+ this.revertHold = new Promise((resolve) => {
414
+ open = resolve;
415
+ });
416
+ return open;
417
+ }
401
418
  /** Make `verifyRepair` for this task wait until the returned function is called. */
402
419
  holdVerification(taskId) {
403
420
  let open;
@@ -431,7 +448,9 @@ var FakeWorktreeIsolation = class {
431
448
  })),
432
449
  shared: [...this.shared],
433
450
  sharedRepos: [...this.sharedRepos],
434
- tasks: {}
451
+ tasks: {},
452
+ keepsEveryLanding: true,
453
+ carried: {}
435
454
  };
436
455
  }
437
456
  async prepare(task, run, _intent, opts = {}) {
@@ -494,6 +513,10 @@ var FakeWorktreeIsolation = class {
494
513
  if (outcome === "merged") {
495
514
  delete record.conflictRepo;
496
515
  delete record.conflictFiles;
516
+ for (const repo of changed) {
517
+ ((run.landings ??= {})[task.id] ??= {})[repo] = [...run.landings?.[task.id]?.[repo] ?? [], `tip-${repo}`];
518
+ (run.landedTasks ??= {})[task.id] = { taskId: task.id, order: task.order, title: task.title };
519
+ }
497
520
  } else {
498
521
  record.conflictRepo = this.stopsIn.get(task.id) ?? changed[0] ?? SELF_REPO;
499
522
  const files = this.conflictFiles.get(task.id);
@@ -502,6 +525,44 @@ var FakeWorktreeIsolation = class {
502
525
  }
503
526
  return outcome;
504
527
  }
528
+ /** Newest landing first, read as the plan's highest order: scheduling tests land in plan order. */
529
+ async readLanded(run, taskIds) {
530
+ this.log({ op: "readLanded", taskIds });
531
+ const records = taskIds.flatMap((id) => run.tasks[id] ?? run.landedTasks?.[id] ?? []).sort((a, b) => b.order - a.order);
532
+ const tasks = records.map((r) => ({
533
+ taskId: r.taskId,
534
+ order: r.order,
535
+ title: r.title,
536
+ repos: Object.keys(run.landings?.[r.taskId] ?? {})
537
+ }));
538
+ return { ok: true, tasks, inBranch: records.flatMap((r) => this.inBranch.get(r.taskId) ?? []) };
539
+ }
540
+ /** Like git: the turn, then the judgement, then the records go in one step with the tasks back. */
541
+ async revert(run, taskIds, watch) {
542
+ this.log({ op: "revert", taskIds });
543
+ const hold = this.revertHold;
544
+ this.revertHold = null;
545
+ await hold;
546
+ const reason = watch.refusal();
547
+ if (reason) return { outcome: "refused", reason };
548
+ if (this.revertStop) return this.revertStop;
549
+ const landed = await this.readLanded(run, taskIds);
550
+ if (!landed.ok) return { outcome: "failed", error: landed.error };
551
+ if (landed.inBranch.length > 0) return { outcome: "in-branch", commands: landed.inBranch };
552
+ run.landing = { taskId: taskIds[0], tips: {}, reverts: {} };
553
+ watch.persist();
554
+ delete run.landing;
555
+ for (const id of taskIds) {
556
+ if (run.tasks[id]?.status === "merged") delete run.tasks[id];
557
+ else if (run.tasks[id]?.status === "conflict") run.tasks[id].status = "kept";
558
+ delete run.landings?.[id];
559
+ delete run.landedTasks?.[id];
560
+ delete run.landedOn?.[id];
561
+ }
562
+ run.reverted = true;
563
+ watch.settled(taskIds);
564
+ return { outcome: "reverted", tasks: landed.tasks };
565
+ }
505
566
  async release(run, taskId, opts) {
506
567
  this.log({ op: "release", taskId, keep: opts.keep });
507
568
  const record = run.tasks[taskId];
@@ -543,13 +604,16 @@ var FakeWorktreeIsolation = class {
543
604
  }
544
605
  async findInHead(run) {
545
606
  this.log({ op: "findInHead" });
546
- const found = [];
607
+ const changed = [];
547
608
  for (const record of Object.values(run.tasks)) {
548
- if (record.status !== "merged" || record.inHead || !this.mergedByHand.has(record.taskId)) continue;
549
- record.inHead = true;
550
- found.push(record.taskId);
609
+ if (record.status !== "merged") continue;
610
+ const merged = this.mergedByHand.has(record.taskId);
611
+ if (merged === !!record.inHead) continue;
612
+ if (merged) record.inHead = true;
613
+ else delete record.inHead;
614
+ changed.push(record.taskId);
551
615
  }
552
- return found;
616
+ return changed;
553
617
  }
554
618
  async snapshotTree() {
555
619
  this.log({ op: "snapshotTree" });