@multiclawcli/core 0.8.2 → 0.9.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.
package/dist/index.js CHANGED
@@ -2721,6 +2721,8 @@ var Orchestrator = class {
2721
2721
  constructor(config, sessions) {
2722
2722
  this.config = config;
2723
2723
  this.eventBus = new EventBus();
2724
+ /** Which configured checkpoints have already been triggered this run. */
2725
+ this.checkpointTriggered = /* @__PURE__ */ new Set();
2724
2726
  this.workDir = path5.resolve(config.workDir);
2725
2727
  fs4.mkdirSync(this.workDir, { recursive: true });
2726
2728
  this.contextManager = new ContextManager(config.context);
@@ -2896,7 +2898,31 @@ var Orchestrator = class {
2896
2898
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2897
2899
  payload: { stageIndex: i }
2898
2900
  });
2899
- if (!allSuccess && !this.config.continueOnError) {
2901
+ if (this.config.checkpoints?.length && this.config.onCheckpoint) {
2902
+ for (let cpIdx = 0; cpIdx < this.config.checkpoints.length; cpIdx++) {
2903
+ if (this.checkpointTriggered.has(cpIdx)) continue;
2904
+ const cp = this.config.checkpoints[cpIdx];
2905
+ if (cp.afterAgents.every((id) => executedIds.has(id))) {
2906
+ this.checkpointTriggered.add(cpIdx);
2907
+ const response = await this.handleCheckpoint(cp, results, options.signal);
2908
+ if (response.action === "cancel") {
2909
+ cancelled = true;
2910
+ allSuccess = false;
2911
+ break;
2912
+ }
2913
+ if (response.action === "modify") {
2914
+ const current = this.contextManager.get("requirement") ?? "";
2915
+ this.contextManager.set(
2916
+ "requirement",
2917
+ `${current}
2918
+
2919
+ [Checkpoint feedback] ${response.instruction}`
2920
+ );
2921
+ }
2922
+ }
2923
+ }
2924
+ }
2925
+ if (cancelled || !allSuccess && !this.config.continueOnError) {
2900
2926
  for (const remainingStage of stages.slice(i + 1)) {
2901
2927
  for (const agent of remainingStage) {
2902
2928
  this.eventBus.emit({
@@ -3075,6 +3101,19 @@ Address these findings within your assigned scope, preserve the complete task re
3075
3101
  acceptance.status = "failed";
3076
3102
  }
3077
3103
  }
3104
+ async handleCheckpoint(policy, results, signal) {
3105
+ if (signal?.aborted) return { action: "cancel" };
3106
+ const completedAgents = policy.afterAgents.map((id) => {
3107
+ const r = results.find((res) => res.agentId === id && res.status === "success");
3108
+ if (!r) return void 0;
3109
+ return { id: r.agentId, name: r.agentName, output: r.output };
3110
+ }).filter((a) => a !== void 0);
3111
+ const info = {
3112
+ label: policy.label || "review checkpoint",
3113
+ completedAgents
3114
+ };
3115
+ return this.config.onCheckpoint(info, signal ?? new AbortController().signal);
3116
+ }
3078
3117
  stageInfos(stages) {
3079
3118
  const getModel = (agent) => resolveModel(agent, this.config);
3080
3119
  return stages.map((stage, i) => ({
@@ -7,6 +7,8 @@ export declare class Orchestrator {
7
7
  private contextManager;
8
8
  private runner;
9
9
  private workDir;
10
+ /** Which configured checkpoints have already been triggered this run. */
11
+ private checkpointTriggered;
10
12
  constructor(config: MultiClawConfig, sessions?: AgentSessionManager);
11
13
  preview(options?: {
12
14
  signal?: AbortSignal;
@@ -16,6 +18,7 @@ export declare class Orchestrator {
16
18
  }): Promise<OrchestratorResult>;
17
19
  private reviewPolicyError;
18
20
  private reviewDelivery;
21
+ private handleCheckpoint;
19
22
  private stageInfos;
20
23
  /**
21
24
  * Order the agents into stages, degrading to declaration order if the graph is
@@ -38,6 +38,36 @@ export interface ReviewPolicy {
38
38
  /** Maximum repair passes (0–5); defaults to 1. Review runs once more after each pass. */
39
39
  maxRepairRounds?: number;
40
40
  }
41
+ /**
42
+ * A checkpoint pauses the pipeline after specific agents complete, giving the
43
+ * user a chance to review their output before downstream agents run.
44
+ */
45
+ export interface CheckpointPolicy {
46
+ /** Agent IDs that must all complete before this checkpoint triggers. */
47
+ afterAgents: string[];
48
+ /** Label shown to the user in the checkpoint prompt. */
49
+ label?: string;
50
+ }
51
+ /** What the orchestrator presents when a checkpoint is reached. */
52
+ export interface CheckpointInfo {
53
+ label: string;
54
+ completedAgents: Array<{
55
+ id: string;
56
+ name: string;
57
+ output?: string;
58
+ }>;
59
+ }
60
+ /** How the user responds to a checkpoint. */
61
+ export type CheckpointResponse = {
62
+ action: "continue";
63
+ } | {
64
+ action: "modify";
65
+ instruction: string;
66
+ } | {
67
+ action: "cancel";
68
+ };
69
+ /** Caller-owned checkpoint handler; headless callers continue automatically. */
70
+ export type CheckpointHandler = (checkpoint: CheckpointInfo, signal: AbortSignal) => Promise<CheckpointResponse>;
41
71
  export interface ReviewVerdict {
42
72
  verdict: "approved" | "changes_required";
43
73
  summary: string;
@@ -95,6 +125,10 @@ export interface MultiClawConfig {
95
125
  useLeader?: boolean;
96
126
  /** Opt-in delivery gate. Execution success alone does not satisfy this policy. */
97
127
  review?: ReviewPolicy;
128
+ /** Pause points after specific agents complete, for human review before continuation. */
129
+ checkpoints?: CheckpointPolicy[];
130
+ /** Caller-owned checkpoint handler; absent checkpoints proceed automatically. */
131
+ onCheckpoint?: CheckpointHandler;
98
132
  /** Caller-owned live approvals. Ask mode without a handler fails closed. */
99
133
  permissions?: {
100
134
  mode: "auto" | "ask" | "deny";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@multiclawcli/core",
3
- "version": "0.8.2",
3
+ "version": "0.9.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",