@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,117 @@
1
+ export const previewPlanExecution = { request: { mode: "preview" } };
2
+ export const applyPlanExecution = (options) => ({
3
+ request: {
4
+ mode: "apply",
5
+ confirmableRiskApproval: options.approval,
6
+ acceptedPolicies: options.acceptedPolicies ?? new Set(),
7
+ },
8
+ approvalRecovery: options.recovery,
9
+ ...(options.configuredAgentOperations === undefined
10
+ ? {}
11
+ : { configuredAgentOperations: options.configuredAgentOperations }),
12
+ });
13
+ const emptyRecovery = { command: [], arguments: [] };
14
+ export const preapprovedPlanExecution = applyPlanExecution({
15
+ approval: "preapproved",
16
+ recovery: emptyRecovery,
17
+ });
18
+ export const promptablePlanExecution = (recovery, acceptedPolicies) => applyPlanExecution({
19
+ approval: "prompt-if-interactive",
20
+ ...(acceptedPolicies === undefined ? {} : { acceptedPolicies }),
21
+ recovery,
22
+ });
23
+ export const publicRecoveryValue = (value) => ({
24
+ _tag: "Public",
25
+ value,
26
+ });
27
+ export const protectedRecoveryValue = () => ({ _tag: "Protected" });
28
+ export const unclassifiedRecoveryValue = () => ({
29
+ _tag: "Unclassified",
30
+ });
31
+ export const credentialFreeLocatorRecoveryValue = (value) => {
32
+ try {
33
+ const parsed = new URL(value);
34
+ const hasSensitiveQuery = [...parsed.searchParams.keys()].some((key) => /(?:auth|key|password|secret|signature|token)/i.test(key));
35
+ return parsed.username.length === 0 && parsed.password.length === 0 && !hasSensitiveQuery
36
+ ? publicRecoveryValue(value)
37
+ : protectedRecoveryValue();
38
+ }
39
+ catch {
40
+ return publicRecoveryValue(value);
41
+ }
42
+ };
43
+ export const recoveryOption = (flag, value) => ({ _tag: "Option", flag, value });
44
+ export const recoveryPositional = (value) => ({ _tag: "Positional", value });
45
+ export const recoverySwitch = (flag, enabled) => ({
46
+ _tag: "Switch",
47
+ flag,
48
+ enabled,
49
+ });
50
+ const safeShellToken = /^[A-Za-z0-9_@%+=:,./^-]+$/;
51
+ const quoteShellToken = (value) => value.length > 0 && safeShellToken.test(value) ? value : `'${value.replaceAll("'", `'"'"'`)}'`;
52
+ const isReplayable = (argument) => argument._tag === "Switch" ||
53
+ (argument.value._tag === "Public" && !/[()]/.test(argument.value.value));
54
+ const renderValue = (value) => value._tag === "Public" && !/[()]/.test(value.value) ? quoteShellToken(value.value) : undefined;
55
+ export const renderConfirmationRecoveryCommand = (recovery, options = {}) => {
56
+ if (recovery.command.length === 0 || !recovery.arguments.every(isReplayable))
57
+ return undefined;
58
+ const optionTokens = recovery.arguments.flatMap((argument) => {
59
+ switch (argument._tag) {
60
+ case "Switch":
61
+ return argument.enabled && argument.flag !== "--preview" && argument.flag !== "--yes"
62
+ ? [argument.flag]
63
+ : [];
64
+ case "Option": {
65
+ if (argument.flag === "--preview" || argument.flag === "--yes")
66
+ return [];
67
+ const value = renderValue(argument.value);
68
+ return value === undefined ? [] : [argument.flag, value];
69
+ }
70
+ case "Positional":
71
+ return [];
72
+ }
73
+ });
74
+ const positionalValues = recovery.arguments.flatMap((argument) => {
75
+ if (argument._tag !== "Positional")
76
+ return [];
77
+ const value = renderValue(argument.value);
78
+ return value === undefined ? [] : [value];
79
+ });
80
+ const needsOptionTerminator = recovery.arguments.some((argument) => argument._tag === "Positional" &&
81
+ argument.value._tag === "Public" &&
82
+ argument.value.value.startsWith("-"));
83
+ const tokens = [
84
+ "axm",
85
+ ...recovery.command,
86
+ ...optionTokens,
87
+ ...(options.includeYes === false ? [] : ["--yes"]),
88
+ ...(options.additionalSwitches ?? []),
89
+ ...(needsOptionTerminator ? ["--"] : []),
90
+ ...positionalValues,
91
+ ];
92
+ return tokens.join(" ");
93
+ };
94
+ export const namedPolicyRecoverySuggestions = (recovery, requiredFlags) => {
95
+ const command = renderConfirmationRecoveryCommand(recovery, {
96
+ includeYes: false,
97
+ additionalSwitches: requiredFlags,
98
+ });
99
+ return command === undefined
100
+ ? [
101
+ {
102
+ description: `Rerun the original invocation with ${requiredFlags.join(" ")}; a retry command is unavailable because it contains protected or unclassified values.`,
103
+ },
104
+ ]
105
+ : [{ description: "Retry with the required policy override", cmd: command }];
106
+ };
107
+ export const confirmationRecoverySuggestions = (recovery) => {
108
+ const command = renderConfirmationRecoveryCommand(recovery);
109
+ return command === undefined
110
+ ? [
111
+ {
112
+ description: "Rerun the original invocation with --yes; a retry command is unavailable because it contains protected or unclassified values.",
113
+ },
114
+ ]
115
+ : [{ description: "Retry with explicit confirmation", cmd: command }];
116
+ };
117
+ //# sourceMappingURL=plan-execution.js.map
@@ -0,0 +1,248 @@
1
+ /**
2
+ * Plan types for workspace operations.
3
+ *
4
+ * Uses a readiness-based model where each step carries its own `run` effect
5
+ * (for ready/warn steps) or an error message (for error steps). A plan retains
6
+ * the environment required by its executable steps so callers can compose
7
+ * dependencies once at the command boundary.
8
+ *
9
+ * This module is the stable kernel home for the plan-pipeline primitives. It
10
+ * is imported by the CLI, the lint module, and any shared-kernel consumer that
11
+ * composes workspace Operations. The registry Worker SHALL NOT import it —
12
+ * publish never applies fixes, so the plan pipeline tree-shakes out of the
13
+ * Worker bundle.
14
+ *
15
+ * @experimental This API is unstable and may change without notice.
16
+ * @packageDocumentation
17
+ */
18
+ import type * as Effect from "effect/Effect";
19
+ import type * as Option from "effect/Option";
20
+ import * as Schema from "effect/Schema";
21
+ import { type StepFailure } from "./errors.js";
22
+ import { type ExtensionType } from "@agentxm/extension-model/unstable/extensions/common";
23
+ import type { ArtifactChange } from "@agentxm/workspace-state";
24
+ import type { ConfiguredAgentOutcome } from "@agentxm/workspace-state";
25
+ import type { DeprecationView } from "@agentxm/extension-model/unstable/extensions/deprecation";
26
+ import type { ReleaseAgeOperationEvidence } from "@agentxm/registry-protocol/unstable/registry/release-age-policy";
27
+ import type { SuggestedAction } from "@agentxm/registry-protocol/unstable/suggested-action";
28
+ export declare const PlanPolicyIds: readonly ["ignore-version-constraints", "accept-warnings"];
29
+ export declare const PlanPolicyIdSchema: Schema.Literals<readonly ["ignore-version-constraints", "accept-warnings"]>;
30
+ export type PlanPolicyId = typeof PlanPolicyIdSchema.Type;
31
+ /**
32
+ * Bounded blocking reason classes. Prose never carries a blocking reason on
33
+ * its own; every blocked unit or operation names one of these classes.
34
+ */
35
+ export declare const BlockingClassSchema: Schema.Literals<readonly ["approval-required", "override-required", "precondition-unmet", "dependency-failed", "dependency-cycle", "stale-candidate", "policy-excluded", "resource-conflict", "external-blocked", "operation-aborted"]>;
36
+ export type BlockingClass = typeof BlockingClassSchema.Type;
37
+ /** Typed blocking carried by a unit result that did not proceed. */
38
+ export interface UnitBlocking {
39
+ readonly class: BlockingClass;
40
+ /** Machine-readable reference to the blocking unit or condition. */
41
+ readonly reference?: string;
42
+ }
43
+ export declare const PlanRiskConditionSchema: Schema.Union<readonly [Schema.Struct<{
44
+ readonly level: Schema.Literal<"confirmable">;
45
+ readonly id: Schema.String;
46
+ readonly detail: Schema.String;
47
+ }>, Schema.Struct<{
48
+ readonly level: Schema.Literal<"override-required">;
49
+ readonly id: Schema.String;
50
+ readonly policy: Schema.Literals<readonly ["ignore-version-constraints", "accept-warnings"]>;
51
+ readonly requiredFlag: Schema.String;
52
+ readonly detail: Schema.String;
53
+ }>, Schema.Struct<{
54
+ readonly level: Schema.Literal<"blocked">;
55
+ readonly id: Schema.String;
56
+ readonly detail: Schema.String;
57
+ readonly errorCode: Schema.Literals<readonly ["issues", "usage", "not_found", "auth", "forbidden", "conflict", "rate_limit", "network", "validation", "internal", "unavailable", "quota", "auth_required", "auth_expired", "auth_denied", "timeout"]>;
58
+ }>]>;
59
+ export type PlanRiskCondition = typeof PlanRiskConditionSchema.Type;
60
+ /**
61
+ * Generic operation type used by all extension operation handlers.
62
+ * Each operation is identified by a string name and carries typed args.
63
+ */
64
+ export interface Operation<TName extends string, TArgs> {
65
+ readonly name: TName;
66
+ readonly args: TArgs;
67
+ }
68
+ export declare const ArtifactMechanismSchema: Schema.Literals<readonly ["symlink", "copy"]>;
69
+ export type ArtifactMechanism = typeof ArtifactMechanismSchema.Type;
70
+ export interface JobStepArtifact {
71
+ readonly path: string;
72
+ readonly scope: "project" | "user";
73
+ readonly agents?: ReadonlyArray<string>;
74
+ readonly version?: string;
75
+ readonly change: ArtifactChange;
76
+ readonly mechanism?: ArtifactMechanism;
77
+ readonly previousVersion?: string;
78
+ readonly fileCount?: number;
79
+ readonly targets?: ReadonlyArray<JobStepArtifactTarget>;
80
+ readonly agentOutcomes?: ReadonlyArray<ConfiguredAgentOutcome>;
81
+ readonly source?: JobStepArtifactSource;
82
+ readonly managedRegions?: ReadonlyArray<JobStepManagedRegion>;
83
+ /** Registry lifecycle evidence captured when the candidate was resolved. */
84
+ readonly registryLifecycle?: {
85
+ readonly deprecation: DeprecationView;
86
+ };
87
+ }
88
+ export interface JobStepManagedRegion {
89
+ readonly unitId: string;
90
+ readonly path: string;
91
+ readonly owner: string;
92
+ }
93
+ export interface JobStepArtifactTarget {
94
+ readonly path: string;
95
+ readonly change: ArtifactChange;
96
+ readonly agentIds?: ReadonlyArray<string>;
97
+ }
98
+ export interface JobStepArtifactSource {
99
+ readonly type: string;
100
+ readonly origin: string;
101
+ readonly ref?: string;
102
+ readonly directory?: string;
103
+ readonly gitTreeHash?: string;
104
+ }
105
+ export interface RegistryLifecycleEvidence {
106
+ readonly deprecation: DeprecationView;
107
+ }
108
+ export type JobStepResult<Output = never> = {
109
+ readonly result: "success";
110
+ readonly message: string;
111
+ /** `skipped`: deliberately not attempted per policy; `unchanged`: evaluated, nothing to do. */
112
+ readonly disposition?: "skipped" | "unchanged";
113
+ readonly warnings?: ReadonlyArray<string>;
114
+ readonly links?: {
115
+ readonly html: string;
116
+ };
117
+ readonly artifact?: JobStepArtifact;
118
+ readonly output?: Output;
119
+ } | {
120
+ readonly result: "error";
121
+ readonly message: string;
122
+ readonly error: StepFailure;
123
+ /** Present when the unit was prevented rather than failing on its own. */
124
+ readonly blocking?: UnitBlocking;
125
+ };
126
+ export interface ReadyJobStep<Requirements = never, Output = never> {
127
+ readonly key?: string;
128
+ readonly dependsOn?: ReadonlyArray<string>;
129
+ readonly readiness: "ready";
130
+ readonly label: string;
131
+ readonly message?: string;
132
+ readonly artifact?: JobStepArtifact;
133
+ readonly agentOutcomes?: ReadonlyArray<ConfiguredAgentOutcome>;
134
+ readonly registryLifecycle?: RegistryLifecycleEvidence;
135
+ readonly run: Effect.Effect<JobStepResult<Output>, StepFailure, Requirements>;
136
+ }
137
+ export interface WarnJobStep<Requirements = never, Output = never> {
138
+ readonly key?: string;
139
+ readonly dependsOn?: ReadonlyArray<string>;
140
+ readonly readiness: "warn";
141
+ readonly warnMessage: string;
142
+ readonly label: string;
143
+ readonly artifact?: JobStepArtifact;
144
+ readonly agentOutcomes?: ReadonlyArray<ConfiguredAgentOutcome>;
145
+ readonly registryLifecycle?: RegistryLifecycleEvidence;
146
+ readonly run: Effect.Effect<JobStepResult<Output>, StepFailure, Requirements>;
147
+ }
148
+ export interface ErrorJobStep {
149
+ readonly key?: string;
150
+ readonly dependsOn?: ReadonlyArray<string>;
151
+ readonly readiness: "error";
152
+ readonly errorMessage: string;
153
+ readonly label: string;
154
+ readonly artifact?: JobStepArtifact;
155
+ readonly agentOutcomes?: ReadonlyArray<ConfiguredAgentOutcome>;
156
+ readonly registryLifecycle?: RegistryLifecycleEvidence;
157
+ /** Semantic blockers already represented in Plan.riskConditions. */
158
+ readonly blockingConditionIds?: ReadonlyArray<string>;
159
+ }
160
+ export type PlannedJobStep<Requirements = never, Output = never> = ReadyJobStep<Requirements, Output> | WarnJobStep<Requirements, Output> | ErrorJobStep;
161
+ export interface CompletedJobStep<Output = never> {
162
+ readonly key?: string;
163
+ readonly label: string;
164
+ readonly blockedBy?: ReadonlyArray<string>;
165
+ readonly registryLifecycle?: RegistryLifecycleEvidence;
166
+ readonly agentOutcomes?: ReadonlyArray<ConfiguredAgentOutcome>;
167
+ readonly result: JobStepResult<Output>;
168
+ }
169
+ export type JobExecutionPolicy = "fail-fast" | "best-effort";
170
+ export interface Job<Requirements = never, Output = never> {
171
+ readonly steps: ReadonlyArray<PlannedJobStep<Requirements, Output>>;
172
+ readonly concurrency: "unbounded" | number;
173
+ /**
174
+ * Defaults to ordered fail-fast execution. Use `best-effort` only when every
175
+ * sibling step is independent; a failure still blocks subsequent jobs.
176
+ */
177
+ readonly executionPolicy?: JobExecutionPolicy;
178
+ }
179
+ /**
180
+ * Typed render vocabulary a planner declares for its operation; replaces
181
+ * verb and subject inference from plan names.
182
+ */
183
+ export interface OperationPresentation {
184
+ readonly verb: {
185
+ /** e.g. "update" */
186
+ readonly imperative: string;
187
+ /** e.g. "Updated" */
188
+ readonly past: string;
189
+ /** e.g. "Updating" */
190
+ readonly gerund: string;
191
+ };
192
+ readonly subject: {
193
+ readonly singular: string;
194
+ readonly plural: string;
195
+ };
196
+ }
197
+ /** Presentation for an operation on one extension type (or extensions generally). */
198
+ export declare const operationPresentation: (verb: OperationPresentation["verb"], type?: ExtensionType) => OperationPresentation;
199
+ /** Fallback vocabulary for planners that declare no presentation. */
200
+ export declare const defaultOperationPresentation: OperationPresentation;
201
+ export declare const presentationOf: (plan: {
202
+ readonly presentation?: OperationPresentation;
203
+ }) => OperationPresentation;
204
+ export declare const OperationPreconditionSchema: Schema.Struct<{
205
+ readonly id: Schema.String;
206
+ readonly label: Schema.String;
207
+ readonly status: Schema.Literals<readonly ["met", "unmet"]>;
208
+ readonly detail: Schema.optional<Schema.String>;
209
+ readonly blockedOn: Schema.optional<Schema.Literal<"human">>;
210
+ readonly command: Schema.optional<Schema.String>;
211
+ }>;
212
+ export type OperationPrecondition = typeof OperationPreconditionSchema.Type;
213
+ export interface Plan<Requirements = never, Output = never> {
214
+ readonly _tag: "Plan";
215
+ readonly name: string;
216
+ readonly description: Option.Option<string>;
217
+ readonly jobs: ReadonlyArray<Job<Requirements, Output>>;
218
+ readonly releaseAge?: ReleaseAgeOperationEvidence;
219
+ readonly preconditions?: ReadonlyArray<OperationPrecondition>;
220
+ /** Typed render vocabulary for this operation's human output. */
221
+ readonly presentation?: OperationPresentation;
222
+ /** Semantic conditions evaluated by the shared execution-policy boundary. */
223
+ readonly riskConditions?: ReadonlyArray<PlanRiskCondition>;
224
+ /** Recovery specific to an operation that cannot currently be applied. */
225
+ readonly failureSuggestions?: ReadonlyArray<SuggestedAction>;
226
+ /** Persisted inputs outside workspace state that materially determine this plan. */
227
+ readonly materialPaths?: ReadonlyArray<string>;
228
+ /** Local plans roll back candidate-wide; remote effects report truthful partial outcomes. */
229
+ readonly executionCapabilities?: {
230
+ readonly rollback: "local-atomic" | "non-rollbackable";
231
+ };
232
+ }
233
+ export interface ExecutedJob<Output = never> {
234
+ readonly steps: ReadonlyArray<CompletedJobStep<Output>>;
235
+ readonly concurrency: "unbounded" | number;
236
+ readonly executionPolicy?: JobExecutionPolicy;
237
+ }
238
+ export interface ExecutedPlan<Output = never> {
239
+ readonly _tag: "ExecutedPlan";
240
+ readonly name: string;
241
+ readonly description: Option.Option<string>;
242
+ readonly jobs: ReadonlyArray<ExecutedJob<Output>>;
243
+ readonly releaseAge?: ReleaseAgeOperationEvidence;
244
+ readonly preconditions?: ReadonlyArray<OperationPrecondition>;
245
+ readonly riskConditions?: ReadonlyArray<PlanRiskCondition>;
246
+ readonly candidateId?: string;
247
+ }
248
+ //# sourceMappingURL=plan.d.ts.map
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Plan types for workspace operations.
3
+ *
4
+ * Uses a readiness-based model where each step carries its own `run` effect
5
+ * (for ready/warn steps) or an error message (for error steps). A plan retains
6
+ * the environment required by its executable steps so callers can compose
7
+ * dependencies once at the command boundary.
8
+ *
9
+ * This module is the stable kernel home for the plan-pipeline primitives. It
10
+ * is imported by the CLI, the lint module, and any shared-kernel consumer that
11
+ * composes workspace Operations. The registry Worker SHALL NOT import it —
12
+ * publish never applies fixes, so the plan pipeline tree-shakes out of the
13
+ * Worker bundle.
14
+ *
15
+ * @experimental This API is unstable and may change without notice.
16
+ * @packageDocumentation
17
+ */
18
+ import * as Schema from "effect/Schema";
19
+ import { OperationErrorCategorySchema } from "./errors.js";
20
+ import { EXTENSION_TYPE_TABLE, } from "@agentxm/extension-model/unstable/extensions/common";
21
+ export const PlanPolicyIds = ["ignore-version-constraints", "accept-warnings"];
22
+ export const PlanPolicyIdSchema = Schema.Literals(PlanPolicyIds);
23
+ /**
24
+ * Bounded blocking reason classes. Prose never carries a blocking reason on
25
+ * its own; every blocked unit or operation names one of these classes.
26
+ */
27
+ export const BlockingClassSchema = Schema.Literals([
28
+ "approval-required",
29
+ "override-required",
30
+ "precondition-unmet",
31
+ "dependency-failed",
32
+ "dependency-cycle",
33
+ "stale-candidate",
34
+ "policy-excluded",
35
+ "resource-conflict",
36
+ "external-blocked",
37
+ "operation-aborted",
38
+ ]).annotate({
39
+ identifier: "BlockingClass",
40
+ title: "Blocking Class",
41
+ description: "Bounded reason class for work that did not proceed.",
42
+ });
43
+ export const PlanRiskConditionSchema = Schema.Union([
44
+ Schema.Struct({
45
+ level: Schema.Literal("confirmable"),
46
+ id: Schema.String,
47
+ detail: Schema.String,
48
+ }),
49
+ Schema.Struct({
50
+ level: Schema.Literal("override-required"),
51
+ id: Schema.String,
52
+ policy: PlanPolicyIdSchema,
53
+ requiredFlag: Schema.String,
54
+ detail: Schema.String,
55
+ }),
56
+ Schema.Struct({
57
+ level: Schema.Literal("blocked"),
58
+ id: Schema.String,
59
+ detail: Schema.String,
60
+ errorCode: OperationErrorCategorySchema,
61
+ }),
62
+ ]);
63
+ // -----------------------------------------------------------------------------
64
+ // Step result types
65
+ // -----------------------------------------------------------------------------
66
+ export const ArtifactMechanismSchema = Schema.Literals(["symlink", "copy"]);
67
+ /** Presentation for an operation on one extension type (or extensions generally). */
68
+ export const operationPresentation = (verb, type) => ({
69
+ verb,
70
+ subject: type === undefined
71
+ ? { singular: "extension", plural: "extensions" }
72
+ : {
73
+ singular: EXTENSION_TYPE_TABLE[type].sentenceLabel,
74
+ plural: EXTENSION_TYPE_TABLE[type].pluralSentenceLabel,
75
+ },
76
+ });
77
+ /** Fallback vocabulary for planners that declare no presentation. */
78
+ export const defaultOperationPresentation = {
79
+ verb: { imperative: "apply", past: "Applied", gerund: "Applying" },
80
+ subject: { singular: "change", plural: "changes" },
81
+ };
82
+ export const presentationOf = (plan) => plan.presentation ?? defaultOperationPresentation;
83
+ export const OperationPreconditionSchema = Schema.Struct({
84
+ id: Schema.String,
85
+ label: Schema.String,
86
+ status: Schema.Literals(["met", "unmet"]),
87
+ detail: Schema.optional(Schema.String),
88
+ blockedOn: Schema.optional(Schema.Literal("human")),
89
+ command: Schema.optional(Schema.String),
90
+ }).annotate({
91
+ identifier: "OperationPrecondition",
92
+ title: "Operation Precondition",
93
+ description: "A condition that must be satisfied before an operation can apply.",
94
+ });
95
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Plan-resolution interaction port.
3
+ *
4
+ * `previewOrApplyPlan` presents candidates, reports progress, and obtains the
5
+ * apply confirmation exclusively through this service. The CLI runtime
6
+ * provides the renderer- and prompt-backed implementation; wording, verbosity
7
+ * gating, and progress presentation belong to that implementation, never to
8
+ * the kernel.
9
+ *
10
+ * @experimental This API is unstable and may change without notice.
11
+ */
12
+ import * as Effect from "effect/Effect";
13
+ import * as Layer from "effect/Layer";
14
+ import * as Option from "effect/Option";
15
+ import * as ServiceMap from "effect/Context";
16
+ import type { PlanInteractionFailed } from "./errors.js";
17
+ import type { ConfirmationRecovery } from "./plan-execution.js";
18
+ import type { Plan } from "./plan.js";
19
+ /**
20
+ * Outcome of the apply confirmation. `cancelled` is the typed successor of a
21
+ * caught prompt cancellation at the CLI implementation; the kernel treats it
22
+ * as declined today, but the distinction is preserved for resolutions.
23
+ */
24
+ export type ApplyConfirmation = "approved" | "declined" | "cancelled";
25
+ export interface ResolvePlanInteractionService {
26
+ /** Whether an interactive confirmation can be obtained. */
27
+ readonly isConfirmationAvailable: Effect.Effect<boolean>;
28
+ readonly confirmApplyChanges: (recovery: ConfirmationRecovery) => Effect.Effect<ApplyConfirmation, PlanInteractionFailed>;
29
+ /**
30
+ * Present the immutable candidate. The implementation owns the
31
+ * verbosity/quiet/mode gate and all wording; the kernel calls this
32
+ * unconditionally.
33
+ */
34
+ readonly presentPlan: (plan: Plan<unknown, unknown>, options: {
35
+ readonly mode: "preview" | "apply";
36
+ }) => Effect.Effect<void>;
37
+ /** Progress envelope for lockfile reconciliation. */
38
+ readonly withPlanningProgress: <A, E, R>(planName: string, run: () => Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
39
+ /**
40
+ * Progress envelope for apply. The implementation subscribes to the
41
+ * operation lifecycle stream itself (`plan/operation-events`) and maps unit
42
+ * and restoration events to progress updates.
43
+ */
44
+ readonly withApplyProgress: <A, E, R>(planName: string, run: () => Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
45
+ /** Transition-lock contention notice. */
46
+ readonly noteTransitionWait: (holder: Option.Option<{
47
+ readonly command: string;
48
+ readonly pid: number;
49
+ }>) => Effect.Effect<void>;
50
+ }
51
+ declare const ResolvePlanInteraction_base: ServiceMap.ServiceClass<ResolvePlanInteraction, "@agentxm/workspace-operations/plan/resolve-plan-interaction/ResolvePlanInteraction", ResolvePlanInteractionService>;
52
+ export declare class ResolvePlanInteraction extends ResolvePlanInteraction_base {
53
+ }
54
+ export interface ResolvePlanInteractionTestState {
55
+ readonly confirmApplyChangesCalls: Array<ConfirmationRecovery>;
56
+ readonly presentPlanCalls: Array<{
57
+ readonly planName: string;
58
+ readonly mode: "preview" | "apply";
59
+ }>;
60
+ readonly planningProgress: Array<string>;
61
+ readonly applyProgress: Array<string>;
62
+ transitionWaits: number;
63
+ }
64
+ export declare const ResolvePlanInteractionTest: (overrides?: {
65
+ readonly isConfirmationAvailable?: boolean;
66
+ readonly confirmApplyChanges?: (recovery: ConfirmationRecovery) => Effect.Effect<ApplyConfirmation, PlanInteractionFailed>;
67
+ readonly presentPlan?: (plan: Plan<unknown, unknown>, options: {
68
+ readonly mode: "preview" | "apply";
69
+ }) => Effect.Effect<void>;
70
+ readonly noteTransitionWait?: (holder: Option.Option<{
71
+ readonly command: string;
72
+ readonly pid: number;
73
+ }>) => Effect.Effect<void>;
74
+ }) => {
75
+ layer: Layer.Layer<ResolvePlanInteraction, never, never>;
76
+ state: ResolvePlanInteractionTestState;
77
+ };
78
+ export {};
79
+ //# sourceMappingURL=resolve-plan-interaction.d.ts.map
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Plan-resolution interaction port.
3
+ *
4
+ * `previewOrApplyPlan` presents candidates, reports progress, and obtains the
5
+ * apply confirmation exclusively through this service. The CLI runtime
6
+ * provides the renderer- and prompt-backed implementation; wording, verbosity
7
+ * gating, and progress presentation belong to that implementation, never to
8
+ * the kernel.
9
+ *
10
+ * @experimental This API is unstable and may change without notice.
11
+ */
12
+ import * as Effect from "effect/Effect";
13
+ import * as Layer from "effect/Layer";
14
+ import * as Option from "effect/Option";
15
+ import * as ServiceMap from "effect/Context";
16
+ export class ResolvePlanInteraction extends ServiceMap.Service()("@agentxm/workspace-operations/plan/resolve-plan-interaction/ResolvePlanInteraction") {
17
+ }
18
+ export const ResolvePlanInteractionTest = (overrides) => {
19
+ const state = {
20
+ confirmApplyChangesCalls: [],
21
+ presentPlanCalls: [],
22
+ planningProgress: [],
23
+ applyProgress: [],
24
+ transitionWaits: 0,
25
+ };
26
+ const layer = Layer.succeed(ResolvePlanInteraction, {
27
+ isConfirmationAvailable: Effect.succeed(overrides?.isConfirmationAvailable ?? false),
28
+ confirmApplyChanges: (recovery) => Effect.gen(function* () {
29
+ state.confirmApplyChangesCalls.push(recovery);
30
+ return yield* overrides?.confirmApplyChanges?.(recovery) ??
31
+ Effect.succeed("approved");
32
+ }),
33
+ presentPlan: (plan, options) => Effect.gen(function* () {
34
+ state.presentPlanCalls.push({ planName: plan.name, mode: options.mode });
35
+ yield* overrides?.presentPlan?.(plan, options) ?? Effect.void;
36
+ }),
37
+ withPlanningProgress: (planName, run) => Effect.suspend(() => {
38
+ state.planningProgress.push(planName);
39
+ return run();
40
+ }),
41
+ withApplyProgress: (planName, run) => Effect.suspend(() => {
42
+ state.applyProgress.push(planName);
43
+ return run();
44
+ }),
45
+ noteTransitionWait: (holder) => Effect.gen(function* () {
46
+ state.transitionWaits += 1;
47
+ yield* overrides?.noteTransitionWait?.(holder) ?? Effect.void;
48
+ }),
49
+ });
50
+ return { layer, state };
51
+ };
52
+ //# sourceMappingURL=resolve-plan-interaction.js.map
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Plan preview/apply function.
3
+ *
4
+ * Orchestrates `augmentPlanWithReconciliation`, `scanPlanReadiness`,
5
+ * and `applyPlan` with the `ResolvePlanInteraction` port, and produces
6
+ * one `OperationResolution` at every termination path. Channels project the
7
+ * returned resolution; presentation and prompting live behind the port, and
8
+ * per-type outcome refinement behind the optional
9
+ * `ConfiguredAgentOutcomesProvider` port.
10
+ *
11
+ * This is a free function, not a method on WorkspaceMutationsService.
12
+ *
13
+ * @experimental This API is unstable and may change without notice.
14
+ */
15
+ import * as FileSystem from "effect/FileSystem";
16
+ import * as Path from "effect/Path";
17
+ import * as Effect from "effect/Effect";
18
+ import { ApprovalRecoveryMissing, StepFailure } from "./errors.js";
19
+ import { type ExecutionCandidate } from "./execution-candidate.js";
20
+ import type { Plan } from "./plan.js";
21
+ import { type OperationResolution } from "./operation-resolution.js";
22
+ import { WorkspaceMutations } from "@agentxm/workspace-state";
23
+ import { ResolvePlanInteraction } from "./resolve-plan-interaction.js";
24
+ import { type PlanExecution } from "./plan-execution.js";
25
+ /**
26
+ * Preview or apply (display, confirm, and execute) a plan using the workspace read model.
27
+ *
28
+ * Steps:
29
+ * 1. Augment plan with lockfile reconciliation if needed
30
+ * 2. Scan for errors/warnings
31
+ * 3. Construct and display the exact candidate
32
+ * 4. Fail closed on blockers and missing named policies
33
+ * 5. Preview or approve confirmable semantic risk
34
+ * 6. Revalidate and apply the same candidate
35
+ *
36
+ * Every termination path resolves to one `OperationResolution`.
37
+ */
38
+ export declare const previewOrApplyPlan: <Requirements, Output>(plan: Plan<Requirements, Output>, options: {
39
+ execution: PlanExecution;
40
+ beforeApply?: (candidate: ExecutionCandidate<Requirements, Output>) => Effect.Effect<void, StepFailure, Requirements>;
41
+ }) => Effect.Effect<OperationResolution<Output>, import("./errors.js").CandidateFingerprintFailed | ApprovalRecoveryMissing | import("./errors.js").PlanInteractionFailed | import("@agentxm/workspace-state").WorkspaceTransitionAcquireFailure | import("@agentxm/workspace-state").LockfileValidationError | import("@agentxm/workspace-state").WorkspaceSettingsReadFailure, Path.Path | FileSystem.FileSystem | ResolvePlanInteraction | WorkspaceMutations | Exclude<Requirements, import("effect/Scope").Scope>>;
42
+ //# sourceMappingURL=resolve-plan.d.ts.map