@agentxm/workspace-operations 0.28.4-bootstrap.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 (45) hide show
  1. package/LICENSE +110 -0
  2. package/README.md +12 -0
  3. package/dist/src/index.d.ts +31 -0
  4. package/dist/src/index.js +42 -0
  5. package/dist/src/live.d.ts +13 -0
  6. package/dist/src/live.js +12 -0
  7. package/dist/src/operations/augment-plan.d.ts +25 -0
  8. package/dist/src/operations/augment-plan.js +51 -0
  9. package/dist/src/operations/load-workspace.d.ts +43 -0
  10. package/dist/src/operations/load-workspace.js +77 -0
  11. package/dist/src/operations/scan-plan-readiness.d.ts +22 -0
  12. package/dist/src/operations/scan-plan-readiness.js +41 -0
  13. package/dist/src/operations/transaction.d.ts +58 -0
  14. package/dist/src/operations/transaction.js +359 -0
  15. package/dist/src/operations/transition-lock.d.ts +66 -0
  16. package/dist/src/operations/transition-lock.js +291 -0
  17. package/dist/src/plan/apply-plan.d.ts +45 -0
  18. package/dist/src/plan/apply-plan.js +238 -0
  19. package/dist/src/plan/errors.d.ts +85 -0
  20. package/dist/src/plan/errors.js +101 -0
  21. package/dist/src/plan/execution-candidate.d.ts +20 -0
  22. package/dist/src/plan/execution-candidate.js +95 -0
  23. package/dist/src/plan/interruption-signal.d.ts +18 -0
  24. package/dist/src/plan/interruption-signal.js +13 -0
  25. package/dist/src/plan/job-step-message.d.ts +7 -0
  26. package/dist/src/plan/job-step-message.js +7 -0
  27. package/dist/src/plan/operation-events.d.ts +62 -0
  28. package/dist/src/plan/operation-events.js +41 -0
  29. package/dist/src/plan/operation-journal.d.ts +69 -0
  30. package/dist/src/plan/operation-journal.js +52 -0
  31. package/dist/src/plan/operation-resolution.d.ts +219 -0
  32. package/dist/src/plan/operation-resolution.js +324 -0
  33. package/dist/src/plan/plan-execution.d.ts +75 -0
  34. package/dist/src/plan/plan-execution.js +117 -0
  35. package/dist/src/plan/plan.d.ts +248 -0
  36. package/dist/src/plan/plan.js +95 -0
  37. package/dist/src/plan/resolve-plan-interaction.d.ts +79 -0
  38. package/dist/src/plan/resolve-plan-interaction.js +52 -0
  39. package/dist/src/plan/resolve-plan.d.ts +42 -0
  40. package/dist/src/plan/resolve-plan.js +694 -0
  41. package/dist/src/plan/step-failure-conversions.d.ts +33 -0
  42. package/dist/src/plan/step-failure-conversions.js +177 -0
  43. package/dist/src/testing.d.ts +11 -0
  44. package/dist/src/testing.js +11 -0
  45. package/package.json +61 -0
@@ -0,0 +1,219 @@
1
+ /**
2
+ * Operation resolution — the single truthful value every plan-family command
3
+ * terminates with.
4
+ *
5
+ * One `OperationResolution` is produced at every termination path of a
6
+ * plan-family invocation (preview, blocked, cancelled, applied, partial,
7
+ * failed, interrupted). The operation outcome is a pure derivation over the
8
+ * unit terminal multiset and the operation-level events the value carries, and
9
+ * the exit code is a pure mapping from that outcome. Every channel — machine
10
+ * document, human render, telemetry — projects this value; none re-derives its
11
+ * own account of what happened.
12
+ *
13
+ * @experimental This API is unstable and may change without notice.
14
+ */
15
+ import type * as Option from "effect/Option";
16
+ import * as Schema from "effect/Schema";
17
+ import type { OperationErrorCategory, StepFailure } from "./errors.js";
18
+ import type { ReleaseAgeOperationEvidence } from "@agentxm/registry-protocol/unstable/registry/release-age-policy";
19
+ import type { SuggestedAction } from "@agentxm/registry-protocol/unstable/suggested-action";
20
+ import type { BlockingClass, ExecutedPlan, Job, JobStepArtifact, OperationPrecondition, OperationPresentation, PlanRiskCondition, RegistryLifecycleEvidence } from "./plan.js";
21
+ import type { ConfiguredAgentOutcome } from "@agentxm/workspace-state";
22
+ /**
23
+ * Canonical unit states. `planned` and `ready` are pre-terminal and appear only
24
+ * in preview-mode and not-executed resolutions; the rest are terminal.
25
+ * Warnings annotate a state and are never a state of their own.
26
+ */
27
+ export declare const UnitStateSchema: Schema.Literals<readonly ["planned", "ready", "committed", "unchanged", "failed", "rolled-back", "blocked", "skipped", "cancelled", "interrupted"]>;
28
+ export type UnitState = typeof UnitStateSchema.Type;
29
+ /** Lifecycle phase in which an operation event (blocking, waiting) occurred. */
30
+ export declare const OperationPhaseSchema: Schema.Literals<readonly ["planning", "preview", "confirmation", "validation", "apply", "restoration"]>;
31
+ export type OperationPhase = typeof OperationPhaseSchema.Type;
32
+ /** Canonical operation terminal outcomes. */
33
+ export declare const OperationOutcomeSchema: Schema.Literals<readonly ["previewed", "applied", "no-op", "partial", "failed", "blocked", "cancelled", "interrupted"]>;
34
+ export type OperationOutcome = typeof OperationOutcomeSchema.Type;
35
+ /** Atomicity class that a closure declares and that an execution applies. */
36
+ export declare const AtomicityClassSchema: Schema.Literals<readonly ["closure-atomic", "non-rollbackable"]>;
37
+ export type AtomicityClass = typeof AtomicityClassSchema.Type;
38
+ /** Post-termination disposition of one unit's durable effects. */
39
+ export declare const UnitDispositionSchema: Schema.Literals<readonly ["restored", "retained", "untouched", "unknown"]>;
40
+ export type UnitDisposition = typeof UnitDispositionSchema.Type;
41
+ /**
42
+ * A typed blocking condition: what class of condition prevented work, which
43
+ * subject it blocked, in which phase it was determined, and — where one exists
44
+ * — the machine-readable escape that resolves it.
45
+ */
46
+ export interface OperationBlock {
47
+ readonly class: BlockingClass;
48
+ readonly subject: string;
49
+ readonly phase: OperationPhase;
50
+ readonly detail: string;
51
+ /**
52
+ * Cause class carried for blocking classes whose exit is not pinned by the
53
+ * class alone (`precondition-unmet`, `external-blocked`).
54
+ */
55
+ readonly causeCode?: OperationErrorCategory;
56
+ /** Machine-readable reference to what blocked the subject. */
57
+ readonly reference?: string;
58
+ readonly escape?: SuggestedAction;
59
+ }
60
+ export interface ResolvedUnit<Output = never> {
61
+ /** Stable identity: the planned step key where one exists, else the label. */
62
+ readonly id: string;
63
+ readonly label: string;
64
+ readonly state: UnitState;
65
+ /** Present on units of a failed or interrupted closure. */
66
+ readonly disposition?: UnitDisposition;
67
+ /** Present exactly when `state` is `blocked`. */
68
+ readonly blocking?: OperationBlock;
69
+ readonly message?: string;
70
+ /** Annotations on the state, never a state of their own. */
71
+ readonly warnings?: ReadonlyArray<string>;
72
+ readonly error?: StepFailure;
73
+ readonly artifact?: JobStepArtifact;
74
+ readonly agentOutcomes?: ReadonlyArray<ConfiguredAgentOutcome>;
75
+ readonly registryLifecycle?: RegistryLifecycleEvidence;
76
+ readonly links?: {
77
+ readonly html: string;
78
+ };
79
+ readonly output?: Output;
80
+ }
81
+ export interface OperationInterruption {
82
+ readonly signal: "SIGINT" | "SIGTERM";
83
+ /**
84
+ * Durable-state disposition of attempted work at the stopping point:
85
+ * `restored` when the closure rolled it back, `retained` when settled
86
+ * commits stand, `unknown` when a started unit's settlement was not
87
+ * observed, and `none` when nothing was attempted.
88
+ */
89
+ readonly disposition: "restored" | "retained" | "unknown" | "none";
90
+ }
91
+ /** One observed durable change or restoration. */
92
+ export interface OperationFootprintEntry {
93
+ readonly path: string;
94
+ readonly change: "created" | "modified" | "removed" | "restored";
95
+ }
96
+ /**
97
+ * Machine-readable recovery content accompanying a `failed`, `partial`, or
98
+ * `interrupted` outcome: what durable state was retained rather than restored
99
+ * and what action resolves it. It never blocks a later invocation — the next
100
+ * mutation converges from the current workspace state.
101
+ */
102
+ export interface OperationRecovery {
103
+ readonly retained: ReadonlyArray<string>;
104
+ /** OS-temporary directory preserving pre-change snapshots, when it survives. */
105
+ readonly snapshotDir?: string;
106
+ readonly actions: ReadonlyArray<SuggestedAction>;
107
+ }
108
+ export interface OperationAtomicity {
109
+ /** The class the operation's closures declared. */
110
+ readonly declared: AtomicityClass;
111
+ /**
112
+ * The class that actually applied to durable effects: `closure-atomic`
113
+ * when effects were fully restored or never made; `non-rollbackable` when
114
+ * effects were retained, by design or because restoration failed.
115
+ */
116
+ readonly applied: AtomicityClass;
117
+ }
118
+ export interface OperationResolution<Output = never> {
119
+ readonly _tag: "OperationResolution";
120
+ readonly name: string;
121
+ readonly description: Option.Option<string>;
122
+ readonly mode: "preview" | "apply";
123
+ readonly candidateId?: string;
124
+ readonly atomicity: OperationAtomicity;
125
+ readonly units: ReadonlyArray<ResolvedUnit<Output>>;
126
+ /** The user declined a required confirmation before any mutation. */
127
+ readonly declined?: boolean;
128
+ /** Operation-level typed blocking; nothing was attempted. */
129
+ readonly blocking?: OperationBlock;
130
+ /** Operation-level failure cause, carrying the cause class for the exit. */
131
+ readonly failure?: StepFailure;
132
+ readonly interruption?: OperationInterruption;
133
+ /** A flag-requested divergence check found divergence on a preview. */
134
+ readonly divergence?: boolean;
135
+ /** Observed durable footprint reported by the mutation layers. */
136
+ readonly footprint?: ReadonlyArray<OperationFootprintEntry>;
137
+ readonly recovery?: OperationRecovery;
138
+ readonly presentation?: OperationPresentation;
139
+ readonly releaseAge?: ReleaseAgeOperationEvidence;
140
+ readonly preconditions?: ReadonlyArray<OperationPrecondition>;
141
+ readonly riskConditions?: ReadonlyArray<PlanRiskCondition>;
142
+ readonly suggestions?: ReadonlyArray<SuggestedAction>;
143
+ }
144
+ export interface UnitStateCounts {
145
+ readonly total: number;
146
+ readonly planned: number;
147
+ readonly ready: number;
148
+ readonly committed: number;
149
+ readonly unchanged: number;
150
+ readonly failed: number;
151
+ readonly rolledBack: number;
152
+ readonly blocked: number;
153
+ readonly skipped: number;
154
+ readonly cancelled: number;
155
+ readonly interrupted: number;
156
+ /** Annotation count, outside the state partition. */
157
+ readonly warnings: number;
158
+ }
159
+ export declare const countUnitStates: (units: ReadonlyArray<ResolvedUnit<unknown>>) => UnitStateCounts;
160
+ /**
161
+ * The operation outcome, derived — never decided — from the resolution's
162
+ * operation-level events and its unit terminal multiset:
163
+ *
164
+ * - an external termination request resolves `interrupted`;
165
+ * - a typed blocking condition that prevented execution resolves `blocked`;
166
+ * - a declined confirmation resolves `cancelled`;
167
+ * - preview mode with planned units resolves `previewed`;
168
+ * - an empty preview resolves `no-op`;
169
+ * - otherwise the multiset decides: restored work is `failed` (with its
170
+ * rollback report), surviving commits plus failures are `partial`, commits
171
+ * alone are `applied`, and zero state-changing effects are `no-op`.
172
+ */
173
+ export declare const deriveOperationOutcome: (resolution: OperationResolution<unknown>) => OperationOutcome;
174
+ export declare const unitIdOf: (step: {
175
+ readonly key?: string;
176
+ readonly label: string;
177
+ }) => string;
178
+ /** Units of a plan that was not executed: planned readiness, typed blocking. */
179
+ export declare const plannedUnits: <Requirements, Output>(jobs: ReadonlyArray<Job<Requirements, Output>>) => ReadonlyArray<ResolvedUnit<Output>>;
180
+ /**
181
+ * Units of an executed plan. `restored: true` marks the closure-atomic
182
+ * failure path where every committed effect was rolled back.
183
+ */
184
+ export declare const executedUnits: <Output>(executed: ExecutedPlan<Output>, options?: {
185
+ readonly restored?: boolean;
186
+ }) => ReadonlyArray<ResolvedUnit<Output>>;
187
+ /**
188
+ * Stable-identity ordering for machine documents. Code-unit comparison, not
189
+ * locale collation, so the order is identical on every host.
190
+ */
191
+ export declare const unitsByStableIdentity: <Output>(units: ReadonlyArray<ResolvedUnit<Output>>) => ReadonlyArray<ResolvedUnit<Output>>;
192
+ export interface MakeOperationResolutionArgs<Output> {
193
+ readonly name: string;
194
+ readonly description: Option.Option<string>;
195
+ readonly mode: "preview" | "apply";
196
+ readonly atomicity: OperationAtomicity;
197
+ readonly units: ReadonlyArray<ResolvedUnit<Output>>;
198
+ readonly candidateId?: string | undefined;
199
+ readonly declined?: boolean | undefined;
200
+ readonly blocking?: OperationBlock | undefined;
201
+ readonly failure?: StepFailure | undefined;
202
+ readonly interruption?: OperationInterruption | undefined;
203
+ readonly divergence?: boolean | undefined;
204
+ readonly footprint?: ReadonlyArray<OperationFootprintEntry> | undefined;
205
+ readonly recovery?: OperationRecovery | undefined;
206
+ readonly presentation?: OperationPresentation | undefined;
207
+ readonly releaseAge?: ReleaseAgeOperationEvidence | undefined;
208
+ readonly preconditions?: ReadonlyArray<OperationPrecondition> | undefined;
209
+ readonly riskConditions?: ReadonlyArray<PlanRiskCondition> | undefined;
210
+ readonly suggestions?: ReadonlyArray<SuggestedAction> | undefined;
211
+ }
212
+ export declare const makeOperationResolution: <Output = never>(args: MakeOperationResolutionArgs<Output>) => OperationResolution<Output>;
213
+ /** The atomicity class a plan declares; local plans default closure-atomic. */
214
+ export declare const declaredAtomicity: (plan: {
215
+ readonly executionCapabilities?: {
216
+ readonly rollback: "local-atomic" | "non-rollbackable";
217
+ };
218
+ }) => AtomicityClass;
219
+ //# sourceMappingURL=operation-resolution.d.ts.map
@@ -0,0 +1,324 @@
1
+ /**
2
+ * Operation resolution — the single truthful value every plan-family command
3
+ * terminates with.
4
+ *
5
+ * One `OperationResolution` is produced at every termination path of a
6
+ * plan-family invocation (preview, blocked, cancelled, applied, partial,
7
+ * failed, interrupted). The operation outcome is a pure derivation over the
8
+ * unit terminal multiset and the operation-level events the value carries, and
9
+ * the exit code is a pure mapping from that outcome. Every channel — machine
10
+ * document, human render, telemetry — projects this value; none re-derives its
11
+ * own account of what happened.
12
+ *
13
+ * @experimental This API is unstable and may change without notice.
14
+ */
15
+ import * as Schema from "effect/Schema";
16
+ // -----------------------------------------------------------------------------
17
+ // Canonical vocabulary
18
+ // -----------------------------------------------------------------------------
19
+ /**
20
+ * Canonical unit states. `planned` and `ready` are pre-terminal and appear only
21
+ * in preview-mode and not-executed resolutions; the rest are terminal.
22
+ * Warnings annotate a state and are never a state of their own.
23
+ */
24
+ export const UnitStateSchema = Schema.Literals([
25
+ "planned",
26
+ "ready",
27
+ "committed",
28
+ "unchanged",
29
+ "failed",
30
+ "rolled-back",
31
+ "blocked",
32
+ "skipped",
33
+ "cancelled",
34
+ // Started but not settled when the operation stopped; the disposition
35
+ // carries the durable-effect fact (restored, retained, or unknown).
36
+ "interrupted",
37
+ ]).annotate({
38
+ identifier: "UnitState",
39
+ title: "Unit State",
40
+ description: "Canonical lifecycle state of one unit of work.",
41
+ });
42
+ /** Lifecycle phase in which an operation event (blocking, waiting) occurred. */
43
+ export const OperationPhaseSchema = Schema.Literals([
44
+ "planning",
45
+ "preview",
46
+ "confirmation",
47
+ "validation",
48
+ "apply",
49
+ "restoration",
50
+ ]).annotate({
51
+ identifier: "OperationPhase",
52
+ title: "Operation Phase",
53
+ description: "Lifecycle phase of a plan-family operation.",
54
+ });
55
+ /** Canonical operation terminal outcomes. */
56
+ export const OperationOutcomeSchema = Schema.Literals([
57
+ "previewed",
58
+ "applied",
59
+ "no-op",
60
+ "partial",
61
+ "failed",
62
+ "blocked",
63
+ "cancelled",
64
+ "interrupted",
65
+ ]).annotate({
66
+ identifier: "OperationOutcome",
67
+ title: "Operation Outcome",
68
+ description: "Canonical terminal outcome of a plan-family operation.",
69
+ });
70
+ /** Atomicity class that a closure declares and that an execution applies. */
71
+ export const AtomicityClassSchema = Schema.Literals([
72
+ "closure-atomic",
73
+ "non-rollbackable",
74
+ ]).annotate({
75
+ identifier: "AtomicityClass",
76
+ title: "Atomicity Class",
77
+ description: "Failure-atomicity class of an operation's durable effects.",
78
+ });
79
+ /** Post-termination disposition of one unit's durable effects. */
80
+ export const UnitDispositionSchema = Schema.Literals([
81
+ "restored",
82
+ "retained",
83
+ "untouched",
84
+ // Settlement was not observed before the operation stopped: the unit's
85
+ // durable effects may or may not exist. Only evidenced states are reported;
86
+ // unknown is the evidenced absence of settlement, never a guess.
87
+ "unknown",
88
+ ]).annotate({
89
+ identifier: "UnitDisposition",
90
+ title: "Unit Disposition",
91
+ description: "What became of a unit's durable effects after termination.",
92
+ });
93
+ export const countUnitStates = (units) => {
94
+ let planned = 0;
95
+ let ready = 0;
96
+ let committed = 0;
97
+ let unchanged = 0;
98
+ let failed = 0;
99
+ let rolledBack = 0;
100
+ let blocked = 0;
101
+ let skipped = 0;
102
+ let cancelled = 0;
103
+ let interrupted = 0;
104
+ let warnings = 0;
105
+ for (const unit of units) {
106
+ warnings += unit.warnings?.length ?? 0;
107
+ switch (unit.state) {
108
+ case "planned":
109
+ planned += 1;
110
+ break;
111
+ case "ready":
112
+ ready += 1;
113
+ break;
114
+ case "committed":
115
+ committed += 1;
116
+ break;
117
+ case "unchanged":
118
+ unchanged += 1;
119
+ break;
120
+ case "failed":
121
+ failed += 1;
122
+ break;
123
+ case "rolled-back":
124
+ rolledBack += 1;
125
+ break;
126
+ case "blocked":
127
+ blocked += 1;
128
+ break;
129
+ case "skipped":
130
+ skipped += 1;
131
+ break;
132
+ case "cancelled":
133
+ cancelled += 1;
134
+ break;
135
+ case "interrupted":
136
+ interrupted += 1;
137
+ break;
138
+ }
139
+ }
140
+ return {
141
+ total: units.length,
142
+ planned,
143
+ ready,
144
+ committed,
145
+ unchanged,
146
+ failed,
147
+ rolledBack,
148
+ blocked,
149
+ skipped,
150
+ cancelled,
151
+ interrupted,
152
+ warnings,
153
+ };
154
+ };
155
+ /**
156
+ * The operation outcome, derived — never decided — from the resolution's
157
+ * operation-level events and its unit terminal multiset:
158
+ *
159
+ * - an external termination request resolves `interrupted`;
160
+ * - a typed blocking condition that prevented execution resolves `blocked`;
161
+ * - a declined confirmation resolves `cancelled`;
162
+ * - preview mode with planned units resolves `previewed`;
163
+ * - an empty preview resolves `no-op`;
164
+ * - otherwise the multiset decides: restored work is `failed` (with its
165
+ * rollback report), surviving commits plus failures are `partial`, commits
166
+ * alone are `applied`, and zero state-changing effects are `no-op`.
167
+ */
168
+ export const deriveOperationOutcome = (resolution) => {
169
+ if (resolution.interruption !== undefined)
170
+ return "interrupted";
171
+ if (resolution.blocking !== undefined)
172
+ return "blocked";
173
+ if (resolution.declined === true)
174
+ return "cancelled";
175
+ if (resolution.mode === "preview" && resolution.units.length > 0)
176
+ return "previewed";
177
+ const counts = countUnitStates(resolution.units);
178
+ if (counts.rolledBack > 0)
179
+ return "failed";
180
+ const attemptedFailures = counts.failed + counts.blocked;
181
+ const operationFailed = resolution.failure !== undefined;
182
+ if (counts.committed > 0) {
183
+ return attemptedFailures > 0 || operationFailed ? "partial" : "applied";
184
+ }
185
+ if (attemptedFailures > 0 || operationFailed)
186
+ return "failed";
187
+ return "no-op";
188
+ };
189
+ // -----------------------------------------------------------------------------
190
+ // Unit construction from plan machinery
191
+ // -----------------------------------------------------------------------------
192
+ export const unitIdOf = (step) => step.key ?? step.label;
193
+ /** Units of a plan that was not executed: planned readiness, typed blocking. */
194
+ export const plannedUnits = (jobs) => jobs.flatMap((job) => job.steps.map((step) => {
195
+ const base = {
196
+ id: unitIdOf(step),
197
+ label: step.label,
198
+ ...(step.artifact === undefined ? {} : { artifact: step.artifact }),
199
+ ...(step.agentOutcomes === undefined ? {} : { agentOutcomes: step.agentOutcomes }),
200
+ ...(step.registryLifecycle === undefined
201
+ ? {}
202
+ : { registryLifecycle: step.registryLifecycle }),
203
+ };
204
+ switch (step.readiness) {
205
+ case "ready":
206
+ return {
207
+ ...base,
208
+ state: "ready",
209
+ ...(step.message === undefined || step.message.length === 0
210
+ ? {}
211
+ : { message: step.message }),
212
+ };
213
+ case "warn":
214
+ return { ...base, state: "ready", warnings: [step.warnMessage] };
215
+ case "error":
216
+ return {
217
+ ...base,
218
+ state: "blocked",
219
+ message: step.errorMessage,
220
+ blocking: {
221
+ class: "precondition-unmet",
222
+ subject: unitIdOf(step),
223
+ phase: "planning",
224
+ detail: step.errorMessage,
225
+ ...(step.blockingConditionIds !== undefined && step.blockingConditionIds.length > 0
226
+ ? { reference: step.blockingConditionIds[0] }
227
+ : {}),
228
+ },
229
+ };
230
+ }
231
+ }));
232
+ /**
233
+ * Units of an executed plan. `restored: true` marks the closure-atomic
234
+ * failure path where every committed effect was rolled back.
235
+ */
236
+ export const executedUnits = (executed, options) => executed.jobs.flatMap((job) => job.steps.map((step) => {
237
+ const base = {
238
+ id: unitIdOf(step),
239
+ label: step.label,
240
+ ...(step.agentOutcomes === undefined ? {} : { agentOutcomes: step.agentOutcomes }),
241
+ ...(step.registryLifecycle === undefined
242
+ ? {}
243
+ : { registryLifecycle: step.registryLifecycle }),
244
+ };
245
+ if (step.result.result === "success") {
246
+ const success = {
247
+ ...base,
248
+ ...(step.result.message.length === 0 ? {} : { message: step.result.message }),
249
+ ...(step.result.warnings !== undefined && step.result.warnings.length > 0
250
+ ? { warnings: step.result.warnings }
251
+ : {}),
252
+ ...(step.result.artifact === undefined ? {} : { artifact: step.result.artifact }),
253
+ ...(step.result.links === undefined ? {} : { links: step.result.links }),
254
+ ...(step.result.output === undefined ? {} : { output: step.result.output }),
255
+ };
256
+ if (step.result.disposition === "skipped") {
257
+ return { ...success, state: "skipped" };
258
+ }
259
+ if (step.result.disposition === "unchanged" ||
260
+ step.result.artifact?.change === "unchanged") {
261
+ return { ...success, state: "unchanged" };
262
+ }
263
+ if (options?.restored === true) {
264
+ return { ...success, state: "rolled-back", disposition: "restored" };
265
+ }
266
+ return { ...success, state: "committed" };
267
+ }
268
+ const failureBase = {
269
+ ...base,
270
+ message: step.result.message,
271
+ error: step.result.error,
272
+ };
273
+ const blocking = step.result.blocking;
274
+ if (blocking !== undefined) {
275
+ return {
276
+ ...failureBase,
277
+ state: "blocked",
278
+ ...(options?.restored === true ? { disposition: "untouched" } : {}),
279
+ blocking: {
280
+ class: blocking.class,
281
+ subject: unitIdOf(step),
282
+ phase: "apply",
283
+ detail: step.result.message,
284
+ ...(blocking.reference === undefined ? {} : { reference: blocking.reference }),
285
+ },
286
+ };
287
+ }
288
+ return {
289
+ ...failureBase,
290
+ state: "failed",
291
+ ...(options?.restored === true ? { disposition: "restored" } : {}),
292
+ };
293
+ }));
294
+ /**
295
+ * Stable-identity ordering for machine documents. Code-unit comparison, not
296
+ * locale collation, so the order is identical on every host.
297
+ */
298
+ export const unitsByStableIdentity = (units) => [...units].sort((left, right) => (left.id < right.id ? -1 : left.id > right.id ? 1 : 0));
299
+ export const makeOperationResolution = (args) => ({
300
+ _tag: "OperationResolution",
301
+ name: args.name,
302
+ description: args.description,
303
+ mode: args.mode,
304
+ atomicity: args.atomicity,
305
+ units: args.units,
306
+ ...(args.candidateId === undefined ? {} : { candidateId: args.candidateId }),
307
+ ...(args.declined === undefined ? {} : { declined: args.declined }),
308
+ ...(args.blocking === undefined ? {} : { blocking: args.blocking }),
309
+ ...(args.failure === undefined ? {} : { failure: args.failure }),
310
+ ...(args.interruption === undefined ? {} : { interruption: args.interruption }),
311
+ ...(args.divergence === undefined ? {} : { divergence: args.divergence }),
312
+ ...(args.footprint === undefined ? {} : { footprint: args.footprint }),
313
+ ...(args.recovery === undefined ? {} : { recovery: args.recovery }),
314
+ ...(args.presentation === undefined ? {} : { presentation: args.presentation }),
315
+ ...(args.releaseAge === undefined ? {} : { releaseAge: args.releaseAge }),
316
+ ...(args.preconditions === undefined ? {} : { preconditions: args.preconditions }),
317
+ ...(args.riskConditions === undefined ? {} : { riskConditions: args.riskConditions }),
318
+ ...(args.suggestions === undefined ? {} : { suggestions: args.suggestions }),
319
+ });
320
+ /** The atomicity class a plan declares; local plans default closure-atomic. */
321
+ export const declaredAtomicity = (plan) => plan.executionCapabilities?.rollback === "non-rollbackable"
322
+ ? "non-rollbackable"
323
+ : "closure-atomic";
324
+ //# sourceMappingURL=operation-resolution.js.map
@@ -0,0 +1,75 @@
1
+ import type { SuggestedAction } from "@agentxm/registry-protocol/unstable/suggested-action";
2
+ import type { PlanPolicyId } from "./plan.js";
3
+ import type { ExtensionType } from "@agentxm/extension-model/unstable/extensions/common";
4
+ export interface ConfiguredAgentOperation {
5
+ readonly extensionType: ExtensionType;
6
+ readonly name: string;
7
+ readonly plannedState: "enabled" | "disabled" | "absent";
8
+ }
9
+ export type ConfirmationRecoveryValue = {
10
+ readonly _tag: "Public";
11
+ readonly value: string;
12
+ } | {
13
+ readonly _tag: "Protected";
14
+ } | {
15
+ readonly _tag: "Unclassified";
16
+ };
17
+ export type ConfirmationRecoveryArgument = {
18
+ readonly _tag: "Option";
19
+ readonly flag: string;
20
+ readonly value: ConfirmationRecoveryValue;
21
+ } | {
22
+ readonly _tag: "Positional";
23
+ readonly value: ConfirmationRecoveryValue;
24
+ } | {
25
+ readonly _tag: "Switch";
26
+ readonly flag: string;
27
+ readonly enabled: boolean;
28
+ };
29
+ export interface ConfirmationRecovery {
30
+ readonly command: ReadonlyArray<string>;
31
+ readonly arguments: ReadonlyArray<ConfirmationRecoveryArgument>;
32
+ }
33
+ export type PlanExecutionRequest = {
34
+ readonly mode: "preview";
35
+ } | {
36
+ readonly mode: "apply";
37
+ readonly confirmableRiskApproval: "prompt-if-interactive" | "preapproved";
38
+ readonly acceptedPolicies: ReadonlySet<PlanPolicyId>;
39
+ };
40
+ /** Invocation-scoped policy input plus safe replay metadata for approval recovery. */
41
+ export type PlanExecution = {
42
+ readonly request: {
43
+ readonly mode: "preview";
44
+ };
45
+ readonly configuredAgentOperations?: ReadonlyArray<ConfiguredAgentOperation>;
46
+ } | {
47
+ readonly request: Extract<PlanExecutionRequest, {
48
+ readonly mode: "apply";
49
+ }>;
50
+ readonly approvalRecovery: ConfirmationRecovery;
51
+ readonly configuredAgentOperations?: ReadonlyArray<ConfiguredAgentOperation>;
52
+ };
53
+ export declare const previewPlanExecution: PlanExecution;
54
+ export declare const applyPlanExecution: (options: {
55
+ readonly approval: "prompt-if-interactive" | "preapproved";
56
+ readonly acceptedPolicies?: ReadonlySet<PlanPolicyId>;
57
+ readonly recovery: ConfirmationRecovery;
58
+ readonly configuredAgentOperations?: ReadonlyArray<ConfiguredAgentOperation>;
59
+ }) => PlanExecution;
60
+ export declare const preapprovedPlanExecution: PlanExecution;
61
+ export declare const promptablePlanExecution: (recovery: ConfirmationRecovery, acceptedPolicies?: ReadonlySet<PlanPolicyId>) => PlanExecution;
62
+ export declare const publicRecoveryValue: (value: string) => ConfirmationRecoveryValue;
63
+ export declare const protectedRecoveryValue: () => ConfirmationRecoveryValue;
64
+ export declare const unclassifiedRecoveryValue: () => ConfirmationRecoveryValue;
65
+ export declare const credentialFreeLocatorRecoveryValue: (value: string) => ConfirmationRecoveryValue;
66
+ export declare const recoveryOption: (flag: string, value: ConfirmationRecoveryValue) => ConfirmationRecoveryArgument;
67
+ export declare const recoveryPositional: (value: ConfirmationRecoveryValue) => ConfirmationRecoveryArgument;
68
+ export declare const recoverySwitch: (flag: string, enabled: boolean) => ConfirmationRecoveryArgument;
69
+ export declare const renderConfirmationRecoveryCommand: (recovery: ConfirmationRecovery, options?: {
70
+ readonly includeYes?: boolean;
71
+ readonly additionalSwitches?: ReadonlyArray<string>;
72
+ }) => string | undefined;
73
+ export declare const namedPolicyRecoverySuggestions: (recovery: ConfirmationRecovery, requiredFlags: ReadonlyArray<string>) => ReadonlyArray<SuggestedAction>;
74
+ export declare const confirmationRecoverySuggestions: (recovery: ConfirmationRecovery) => ReadonlyArray<SuggestedAction>;
75
+ //# sourceMappingURL=plan-execution.d.ts.map