@agentxm/workspace-operations 0.28.12 → 0.28.13

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 (35) hide show
  1. package/dist/src/index.d.ts +11 -10
  2. package/dist/src/index.js +16 -12
  3. package/dist/src/operations/scan-plan-readiness.d.ts +1 -1
  4. package/dist/src/operations/scan-plan-readiness.js +1 -1
  5. package/dist/src/plan/apply-plan.js +8 -8
  6. package/dist/src/plan/execution-candidate.d.ts +7 -1
  7. package/dist/src/plan/execution-candidate.js +9 -2
  8. package/dist/src/plan/interruption-resolution.d.ts +50 -0
  9. package/dist/src/plan/interruption-resolution.js +158 -0
  10. package/dist/src/plan/operation-journal.d.ts +9 -9
  11. package/dist/src/plan/operation-journal.js +5 -20
  12. package/dist/src/plan/operation-resolution.d.ts +1 -1
  13. package/dist/src/plan/plan-execution-fixtures.d.ts +2 -2
  14. package/dist/src/plan/plan-execution-fixtures.js +2 -2
  15. package/dist/src/plan/plan-execution.d.ts +48 -0
  16. package/dist/src/plan/plan-execution.js +40 -0
  17. package/dist/src/plan/plan.d.ts +9 -19
  18. package/dist/src/plan/resolve-plan-interaction.d.ts +1 -1
  19. package/dist/src/plan/resolve-plan-interaction.js +1 -1
  20. package/dist/src/plan/resolve-plan.d.ts +38 -23
  21. package/dist/src/plan/resolve-plan.js +114 -96
  22. package/dist/src/plan/step-failure-conversions.d.ts +2 -1
  23. package/dist/src/testing.d.ts +22 -1
  24. package/dist/src/testing.js +23 -1
  25. package/package.json +12 -16
  26. package/dist/src/live.d.ts +0 -13
  27. package/dist/src/live.js +0 -12
  28. package/dist/src/operations/load-workspace.d.ts +0 -44
  29. package/dist/src/operations/load-workspace.js +0 -80
  30. package/dist/src/operations/memory-transition-lock.d.ts +0 -20
  31. package/dist/src/operations/memory-transition-lock.js +0 -57
  32. package/dist/src/operations/transaction.d.ts +0 -60
  33. package/dist/src/operations/transaction.js +0 -358
  34. package/dist/src/operations/transition-lock.d.ts +0 -72
  35. package/dist/src/operations/transition-lock.js +0 -298
@@ -7,7 +7,29 @@
7
7
  * @experimental This API is unstable and may change without notice.
8
8
  * @packageDocumentation
9
9
  */
10
+ import * as Layer from "effect/Layer";
11
+ import { ConfiguredAgentOutcomesProvider } from "@agentxm/workspace-state";
12
+ import { ConfiguredAgentOutcomesProviderTest } from "@agentxm/workspace-state/testing";
13
+ import { FootprintRecorder, makeFootprintRecorder } from "@agentxm/workspace-transactions";
14
+ import { OperationJournal, makeOperationJournal } from "./plan/operation-journal.js";
15
+ /**
16
+ * An empty journal for one test invocation, standing in for the
17
+ * per-invocation journal the CLI's operation lifecycle creates around every
18
+ * command. Provide it wherever a test drives a plan directly instead of
19
+ * through that lifecycle. A test that asserts on what was recorded should
20
+ * build the service itself with `makeOperationJournal` and keep the ref.
21
+ */
22
+ export const OperationJournalTest = Layer.effect(OperationJournal, makeOperationJournal);
23
+ /** A fresh footprint recorder for one test invocation. */
24
+ export const FootprintRecorderTest = Layer.effect(FootprintRecorder, makeFootprintRecorder);
25
+ /**
26
+ * Every per-invocation service `resolveExecutionCandidate` acquires that the CLI's
27
+ * operation lifecycle opens around a command: the journal, the footprint
28
+ * recorder, and a configured-agent outcome provider with no per-type
29
+ * refinement. A test that drives a plan directly needs all of them, so this
30
+ * is the layer to reach for rather than assembling the three by hand.
31
+ */
32
+ export const PlanInvocationTest = Layer.mergeAll(OperationJournalTest, FootprintRecorderTest, ConfiguredAgentOutcomesProviderTest);
10
33
  export { ResolvePlanInteractionTest, } from "./plan/resolve-plan-interaction.js";
11
34
  export { interactiveOnlyPlanExecution, preapprovedPlanExecution, promptablePlanExecution, } from "./plan/plan-execution-fixtures.js";
12
- export { makeMemoryTransitionLockWorld, } from "./operations/memory-transition-lock.js";
13
35
  //# sourceMappingURL=testing.js.map
package/package.json CHANGED
@@ -4,17 +4,18 @@
4
4
  "url": "https://github.com/agentxm/axm/issues"
5
5
  },
6
6
  "dependencies": {
7
- "@agentxm/extension-model": "^0.28.12",
8
- "@agentxm/registry-protocol": "^0.28.12",
9
- "@agentxm/workspace-state": "^0.28.12",
10
- "effect": "4.0.0-rc.112",
11
- "proper-lockfile": "^4.1.2"
12
- },
13
- "description": "AXM workspace operations kernel: plans, execution candidates, operation resolutions, and workspace transactions for the axm CLI. Unstable and unsupported — use the axm.sh CLI.",
7
+ "@agentxm/extension-model": "^0.28.13",
8
+ "@agentxm/extension-resolution": "^0.28.13",
9
+ "@agentxm/registry-protocol": "^0.28.13",
10
+ "@agentxm/workspace-state": "^0.28.13",
11
+ "@agentxm/workspace-transactions": "^0.28.13",
12
+ "effect": "4.0.0-rc.112"
13
+ },
14
+ "description": "AXM workspace operations: plans, execution candidates, closure execution, and operation resolutions for the axm CLI. Unstable and unsupported — use the axm.sh CLI.",
14
15
  "devDependencies": {
16
+ "@agentxm/specification-metadata": "^0.28.13",
15
17
  "@effect/platform-node": "4.0.0-rc.112",
16
18
  "@effect/vitest": "4.0.0-rc.112",
17
- "@types/proper-lockfile": "^4.1.4",
18
19
  "@typescript/native": "npm:typescript@^7.0.2",
19
20
  "typescript": "npm:@typescript/typescript6@^6.0.2",
20
21
  "vitest": "^4.1.10",
@@ -29,11 +30,6 @@
29
30
  "default": "./dist/src/index.js",
30
31
  "types": "./dist/src/index.d.ts"
31
32
  },
32
- "./live": {
33
- "axm-source": "./src/live.ts",
34
- "default": "./dist/src/live.js",
35
- "types": "./dist/src/live.d.ts"
36
- },
37
33
  "./testing": {
38
34
  "axm-source": "./src/testing.ts",
39
35
  "default": "./dist/src/testing.js",
@@ -54,11 +50,11 @@
54
50
  "access": "public"
55
51
  },
56
52
  "repository": {
57
- "directory": "packages/workspace-operations",
53
+ "directory": "packages/core/workspace-operations",
58
54
  "type": "git",
59
55
  "url": "https://github.com/agentxm/axm.git"
60
56
  },
61
57
  "sideEffects": false,
62
58
  "type": "module",
63
- "version": "0.28.12"
64
- }
59
+ "version": "0.28.13"
60
+ }
@@ -1,13 +0,0 @@
1
- /**
2
- * @agentxm/workspace-operations environment-backed composition.
3
- *
4
- * The composed workspace layer every entry point provides. Only application
5
- * composition roots import this module; feature logic keeps
6
- * `WorkspaceMutations` in its Effect environment.
7
- *
8
- * @experimental This API is unstable and may change without notice.
9
- * @packageDocumentation
10
- */
11
- export { layer, loadWorkspace, makeWorkspaceTransactionCapabilities, } from "./operations/load-workspace.js";
12
- export type { WorkspaceLayerOptions } from "@agentxm/workspace-state";
13
- //# sourceMappingURL=live.d.ts.map
package/dist/src/live.js DELETED
@@ -1,12 +0,0 @@
1
- /**
2
- * @agentxm/workspace-operations environment-backed composition.
3
- *
4
- * The composed workspace layer every entry point provides. Only application
5
- * composition roots import this module; feature logic keeps
6
- * `WorkspaceMutations` in its Effect environment.
7
- *
8
- * @experimental This API is unstable and may change without notice.
9
- * @packageDocumentation
10
- */
11
- export { layer, loadWorkspace, makeWorkspaceTransactionCapabilities, } from "./operations/load-workspace.js";
12
- //# sourceMappingURL=live.js.map
@@ -1,44 +0,0 @@
1
- /**
2
- * Live workspace composition: the one seam that needs both the workspace
3
- * state facade and the operations-side transaction machinery. Supplies the
4
- * transaction capabilities to `makeWorkspaceMutations` and publishes the
5
- * `loadWorkspace` effect and `layer` every entry point composes.
6
- *
7
- * @experimental This API is unstable and may change without notice.
8
- */
9
- import * as Effect from "effect/Effect";
10
- import * as FileSystem from "effect/FileSystem";
11
- import * as Layer from "effect/Layer";
12
- import * as Path from "effect/Path";
13
- import { WorkspaceMutations, type MakeWorkspaceTransactionCapabilities, type WorkspaceLayerOptions, type WorkspaceMutationsError, type WorkspaceMutationsService } from "@agentxm/workspace-state";
14
- import { type WorkspaceTransitionLock } from "./transition-lock.js";
15
- /**
16
- * The live transaction capabilities: the runner claims the shared settings
17
- * and lockfile targets by default, and both members eliminate FileSystem and
18
- * Path so the facade's methods stay `R = never` for callers.
19
- */
20
- export declare const makeWorkspaceTransactionCapabilities: (lock: WorkspaceTransitionLock) => MakeWorkspaceTransactionCapabilities;
21
- /**
22
- * Create workspace mutations effect.
23
- *
24
- * Loads an existing workspace from disk.
25
- *
26
- * The workspace must already be initialized. Missing or invalid settings and
27
- * invalid or unsupported lockfiles fail fast with a typed workspace error.
28
- *
29
- * @param options - WorkspaceMutations layer options
30
- * @returns Effect yielding WorkspaceMutationsService
31
- */
32
- export declare const loadWorkspace: (options: WorkspaceLayerOptions) => Effect.Effect<WorkspaceMutationsService, WorkspaceMutationsError, FileSystem.FileSystem | Path.Path>;
33
- /**
34
- * Create a layer that loads workspace read model from disk.
35
- *
36
- * The workspace must already be initialized.
37
- *
38
- * @param options - WorkspaceMutations layer options
39
- * @returns Layer providing WorkspaceMutations
40
- *
41
- * @experimental This API is unstable and may change without notice.
42
- */
43
- export declare const layer: (options: WorkspaceLayerOptions) => Layer.Layer<WorkspaceMutations, WorkspaceMutationsError, Path.Path | FileSystem.FileSystem>;
44
- //# sourceMappingURL=load-workspace.d.ts.map
@@ -1,80 +0,0 @@
1
- /**
2
- * Live workspace composition: the one seam that needs both the workspace
3
- * state facade and the operations-side transaction machinery. Supplies the
4
- * transaction capabilities to `makeWorkspaceMutations` and publishes the
5
- * `loadWorkspace` effect and `layer` every entry point composes.
6
- *
7
- * @experimental This API is unstable and may change without notice.
8
- */
9
- import * as Effect from "effect/Effect";
10
- import * as FileSystem from "effect/FileSystem";
11
- import * as Layer from "effect/Layer";
12
- import * as Path from "effect/Path";
13
- import * as Semaphore from "effect/Semaphore";
14
- import { WorkspaceMutations, makeWorkspaceMutations, } from "@agentxm/workspace-state";
15
- import { runWorkspaceTransaction } from "./transaction.js";
16
- import { liveWorkspaceTransitionLock } from "./transition-lock.js";
17
- /**
18
- * The live transaction capabilities: the runner claims the shared settings
19
- * and lockfile targets by default, and both members eliminate FileSystem and
20
- * Path so the facade's methods stay `R = never` for callers.
21
- */
22
- export const makeWorkspaceTransactionCapabilities = (lock) => ({ workspaceDir, settingsPath, lockPath }) => Effect.gen(function* () {
23
- const fs = yield* FileSystem.FileSystem;
24
- const path = yield* Path.Path;
25
- // Transaction admission must be distinct from the facade's mutation
26
- // mutex: a transaction calls the same service's mutation methods while
27
- // it owns the outer admission permit.
28
- const transactionSemaphore = yield* Semaphore.make(1);
29
- const fsLayer = Layer.mergeAll(Layer.succeed(FileSystem.FileSystem, fs), Layer.succeed(Path.Path, path));
30
- const runTransaction = (args) => runWorkspaceTransaction({
31
- lock,
32
- workspaceDir,
33
- semaphore: transactionSemaphore,
34
- targets: [
35
- ...(args.claimDefaultTargets === false ? [] : [settingsPath, lockPath]),
36
- ...(args.targets ?? []),
37
- ],
38
- transition: args.transition,
39
- validate: args.validate,
40
- ...(args.onRestorationStarted === undefined
41
- ? {}
42
- : { onRestorationStarted: args.onRestorationStarted }),
43
- }).pipe(Effect.provide(fsLayer));
44
- const acquireTransition = (request) => lock
45
- .acquire({
46
- workspaceDir,
47
- holder: {
48
- command: request.command,
49
- pid: process.pid,
50
- ...(request.candidateId === undefined ? {} : { candidateId: request.candidateId }),
51
- },
52
- ...(request.onWaiting === undefined ? {} : { onWaiting: request.onWaiting }),
53
- })
54
- .pipe(Effect.provide(fsLayer));
55
- return { runTransaction, acquireTransition };
56
- });
57
- /**
58
- * Create workspace mutations effect.
59
- *
60
- * Loads an existing workspace from disk.
61
- *
62
- * The workspace must already be initialized. Missing or invalid settings and
63
- * invalid or unsupported lockfiles fail fast with a typed workspace error.
64
- *
65
- * @param options - WorkspaceMutations layer options
66
- * @returns Effect yielding WorkspaceMutationsService
67
- */
68
- export const loadWorkspace = (options) => makeWorkspaceMutations(options, makeWorkspaceTransactionCapabilities(liveWorkspaceTransitionLock));
69
- /**
70
- * Create a layer that loads workspace read model from disk.
71
- *
72
- * The workspace must already be initialized.
73
- *
74
- * @param options - WorkspaceMutations layer options
75
- * @returns Layer providing WorkspaceMutations
76
- *
77
- * @experimental This API is unstable and may change without notice.
78
- */
79
- export const layer = (options) => Layer.effect(WorkspaceMutations, loadWorkspace(options));
80
- //# sourceMappingURL=load-workspace.js.map
@@ -1,20 +0,0 @@
1
- /**
2
- * Deterministic in-process workspace transition admission for tests.
3
- *
4
- * One world owns admission state while each invocation receives an isolated
5
- * ownership view. Waiting uses Effect time so contention and interruption can
6
- * be exercised without native timers or lock files.
7
- *
8
- * @experimental This API is unstable and may change without notice.
9
- */
10
- import type { WorkspaceTransitionLock } from "./transition-lock.js";
11
- export interface MemoryTransitionLockWorld {
12
- readonly counts: () => {
13
- readonly acquisitions: number;
14
- readonly releases: number;
15
- };
16
- readonly invocation: () => WorkspaceTransitionLock;
17
- }
18
- /** Make one isolated admission world for a deterministic test scenario. */
19
- export declare const makeMemoryTransitionLockWorld: () => MemoryTransitionLockWorld;
20
- //# sourceMappingURL=memory-transition-lock.d.ts.map
@@ -1,57 +0,0 @@
1
- /**
2
- * Deterministic in-process workspace transition admission for tests.
3
- *
4
- * One world owns admission state while each invocation receives an isolated
5
- * ownership view. Waiting uses Effect time so contention and interruption can
6
- * be exercised without native timers or lock files.
7
- *
8
- * @experimental This API is unstable and may change without notice.
9
- */
10
- import * as Effect from "effect/Effect";
11
- import * as Option from "effect/Option";
12
- import * as Semaphore from "effect/Semaphore";
13
- /** Make one isolated admission world for a deterministic test scenario. */
14
- export const makeMemoryTransitionLockWorld = () => {
15
- const admission = Semaphore.makeUnsafe(1);
16
- let acquisitions = 0;
17
- let releases = 0;
18
- let holder = Option.none();
19
- return {
20
- counts: () => ({ acquisitions, releases }),
21
- invocation: () => {
22
- let held;
23
- return {
24
- held: (directory) => (held?.directory === directory ? held.lease : undefined),
25
- acquire: (args) => Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
26
- let waitedMillis = 0;
27
- let reportedWaiting = false;
28
- while (!(yield* admission.takeIfAvailable(1))) {
29
- if (!reportedWaiting && args.onWaiting !== undefined) {
30
- yield* restore(args.onWaiting(holder));
31
- reportedWaiting = true;
32
- }
33
- if (waitedMillis >= (args.waitBoundMillis ?? 60_000)) {
34
- return Option.some({ holder, waitedMillis });
35
- }
36
- yield* restore(Effect.sleep("250 millis"));
37
- waitedMillis += 250;
38
- }
39
- holder = Option.some(args.holder);
40
- acquisitions += 1;
41
- held = {
42
- directory: args.workspaceDir,
43
- lease: { compromised: Effect.never, isCompromised: () => false },
44
- };
45
- yield* Effect.addFinalizer(() => Effect.gen(function* () {
46
- held = undefined;
47
- holder = Option.none();
48
- releases += 1;
49
- yield* admission.release(1);
50
- }));
51
- return Option.none();
52
- })),
53
- };
54
- },
55
- };
56
- };
57
- //# sourceMappingURL=memory-transition-lock.js.map
@@ -1,60 +0,0 @@
1
- /**
2
- * Workspace transaction mechanics: the snapshot/restore/validate/rollback
3
- * runner and the closure settlement operations, implemented against the
4
- * ambient authority context declared in `../transaction.ts`.
5
- *
6
- * @experimental This API is unstable and may change without notice.
7
- */
8
- import * as Effect from "effect/Effect";
9
- import * as FileSystem from "effect/FileSystem";
10
- import * as Path from "effect/Path";
11
- import * as Semaphore from "effect/Semaphore";
12
- import { WorkspaceRestorationIncomplete, type WorkspaceTransactionFailure } from "@agentxm/workspace-state";
13
- import type { WorkspaceTransitionLock } from "./transition-lock.js";
14
- /** Run one semantic closure's mutations under its closure identity. */
15
- export declare const withWorkspaceClosure: (closureId: string) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
16
- export interface WorkspaceTransactionArgs<A, E, R> {
17
- readonly lock: WorkspaceTransitionLock;
18
- readonly workspaceDir: string;
19
- /** In-process admission owned by the workspace service instance. */
20
- readonly semaphore: Semaphore.Semaphore;
21
- /** Authoritative files or directories that the transition may mutate. */
22
- readonly targets: ReadonlyArray<string>;
23
- /** Desired, lock, canonical, projection, and native-configuration mutation. */
24
- readonly transition: Effect.Effect<A, E, R>;
25
- /** Confirms the complete durable postcondition before the transaction commits. */
26
- readonly validate: (value: A) => Effect.Effect<void, E, R>;
27
- /** Observes the start of rollback restoration; never controls it. */
28
- readonly onRestorationStarted?: Effect.Effect<void>;
29
- }
30
- /**
31
- * Settle one closure: its commits stand, so its snapshots leave the
32
- * restoration set and a later closure touching the same target takes a fresh
33
- * post-commit preimage. No-op outside a transaction.
34
- */
35
- export declare const settleWorkspaceClosure: (closureId: string) => Effect.Effect<void>;
36
- /**
37
- * Roll back one failed closure: restore and verify exactly its snapshots, in
38
- * reverse order, leaving every other closure's work in place. A restoration
39
- * that does not complete and verify records a pending typed failure the
40
- * transaction surfaces at its end — the truth travels in memory, never
41
- * through a later workspace write. No-op outside a transaction.
42
- */
43
- export declare const rollbackWorkspaceClosure: (closureId: string) => Effect.Effect<void>;
44
- /**
45
- * Run one coupled workspace mutation under the workspace transition lock.
46
- *
47
- * Every authoritative target is snapshotted into a uniquely prefixed
48
- * OS-temporary directory before the transition begins. A failed transition or
49
- * postcondition check restores and verifies the exact pre-operation paths and
50
- * removes the snapshots; a restoration that does not complete and verify
51
- * fails with the typed {@link WorkspaceRestorationIncomplete}, preserving the
52
- * snapshot directory for manual inspection. Nothing about a failure persists
53
- * in the workspace: the next mutation plans from the current workspace state.
54
- *
55
- * The invocation-level transition hold is reused when a plan-family apply
56
- * already acquired it; otherwise this transaction acquires its own for the
57
- * duration of the mutation.
58
- */
59
- export declare const runWorkspaceTransaction: <A, E, R>(args: WorkspaceTransactionArgs<A, E, R>) => Effect.Effect<A, WorkspaceTransactionFailure | WorkspaceRestorationIncomplete | E, R | FileSystem.FileSystem | Path.Path>;
60
- //# sourceMappingURL=transaction.d.ts.map