@agentxm/workspace-operations 0.29.4 → 0.30.1

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.
@@ -12,7 +12,7 @@
12
12
  * @packageDocumentation
13
13
  */
14
14
  export { BlockingClassSchema, defaultOperationPresentation, operationPresentation, presentationOf, ArtifactMechanismSchema, PackMembershipDeltaSchema, ConfirmableConsentSchema, OperationPreconditionSchema, PlanPolicyIdSchema, PlanPolicyIds, PlanRiskConditionSchema, } from "./plan/plan.js";
15
- export type { ArtifactMechanism, BlockingClass, CompletedJobStep, ConfirmableConsent, ErrorJobStep, ExecutedJob, ExecutedPlan, Job, JobStepArtifact, PackMembershipDelta, JobStepArtifactSource, JobStepArtifactTarget, JobStepResult, Operation, OperationPrecondition, OperationPresentation, Plan, PlanExecutionCapabilities, PlanPolicyId, PlanRiskCondition, PlannedJobStep, ReadyJobStep, RegistryLifecycleEvidence, UnitBlocking, WarnJobStep, } from "./plan/plan.js";
15
+ export type { ArtifactMechanism, BlockingClass, CompletedJobStep, ConfirmableConsent, ErrorJobStep, ExecutedJob, ExecutedPlan, Job, JobStepArtifact, PackMembershipDelta, JobStepArtifactSource, JobStepArtifactTarget, JobStepArtifactReference, JobStepResult, Operation, OperationPrecondition, OperationPresentation, Plan, PlanExecutionCapabilities, PlanPolicyId, PlanRiskCondition, PlannedJobStep, ReadyJobStep, RegistryLifecycleEvidence, UnitBlocking, WarnJobStep, } from "./plan/plan.js";
16
16
  export { AtomicityClassSchema, OperationOutcomeSchema, OperationPhaseSchema, UnitDispositionSchema, UnitStateSchema, countUnitStates, declaredAtomicity, deriveOperationOutcome, executedUnits, makeOperationResolution, plannedUnits, unitIdOf, unitsByStableIdentity, } from "./plan/operation-resolution.js";
17
17
  export type { AtomicityClass, MakeOperationResolutionArgs, OperationAtomicity, OperationBlock, OperationFootprintEntry, OperationInterruption, OperationOutcome, OperationPhase, OperationRecovery, OperationResolution, ResolvedUnit, UnitDisposition, UnitState, UnitStateCounts, } from "./plan/operation-resolution.js";
18
18
  export { OperationJournal, appendResolvedUnit, appendStartedUnit, recordJournalPhase, getOperationJournal, makeOperationJournal, recordOperationJournal, updateOperationJournal, type OperationJournalService, type OperationJournalState, } from "./plan/operation-journal.js";
@@ -23,9 +23,9 @@ export type OperationHandler<Op, R = never> = (op: Op) => Effect.Effect<JobStepR
23
23
  /**
24
24
  * Apply a plan by iterating jobs and executing step run closures.
25
25
  *
26
- * Any readiness error gates the complete plan before execution. At runtime,
27
- * jobs use ordered fail-fast execution by default. A job may explicitly opt
28
- * into best-effort execution for independent siblings; failures still block
26
+ * Readiness errors in ordered jobs gate the complete plan. A job may explicitly
27
+ * opt into best-effort execution for independent siblings, including siblings
28
+ * blocked during preparation. Runtime failures still block
29
29
  * all subsequent jobs.
30
30
  *
31
31
  * Never fails — catches StepFailure and converts to error results.
@@ -36,19 +36,9 @@ const stepEvidence = (step) => ({
36
36
  const executeStep = (step) => {
37
37
  switch (step.readiness) {
38
38
  case "error":
39
- return Effect.succeed({
40
- ...(step.key === undefined ? {} : { key: step.key }),
41
- ...stepEvidence(step),
42
- label: step.label,
43
- result: {
44
- result: "error",
45
- message: step.errorMessage,
46
- error: new StepFailure({
47
- category: "internal",
48
- detail: step.errorMessage,
49
- }),
50
- },
51
- });
39
+ return Effect.succeed(blockStep(step, step.errorMessage, {
40
+ class: "precondition-unmet",
41
+ }));
52
42
  case "ready":
53
43
  return step.run.pipe(Effect.map((result) => ({
54
44
  ...(step.key === undefined ? {} : { key: step.key }),
@@ -202,7 +192,8 @@ const executeDependencyAwareJob = (job, observeStart, observeStep) => Effect.gen
202
192
  export const applyPlan = (plan, options) => Effect.gen(function* () {
203
193
  const observeStep = options?.onStepCompleted ?? (() => Effect.void);
204
194
  const observeStart = options?.onStepStarted ?? (() => Effect.void);
205
- const hasReadinessError = plan.jobs.some((job) => job.steps.some((step) => step.readiness === "error"));
195
+ const hasReadinessError = plan.jobs.some((job) => job.executionPolicy !== "best-effort" &&
196
+ job.steps.some((step) => step.readiness === "error"));
206
197
  // Any job with an error blocks every later job; the fact travels in a
207
198
  // `Ref` because it crosses the job traversal's iteration boundary.
208
199
  const blocked = yield* Ref.make(false);
@@ -6,8 +6,14 @@ import * as Option from "effect/Option";
6
6
  import { CandidateFingerprintFailed } from "./errors.js";
7
7
  const collectArtifactPaths = (plan) => plan.jobs.flatMap((job) => job.steps.flatMap((step) => {
8
8
  if (step.artifact === undefined)
9
- return [];
10
- return [step.artifact.path, ...(step.artifact.targets ?? []).map((target) => target.path)];
9
+ return step.materialPaths ?? [];
10
+ return [
11
+ ...(step.materialPaths ?? []),
12
+ step.artifact.path,
13
+ ...(step.artifact.targets ?? []).map((target) => target.path),
14
+ ...(step.artifact.references ?? []).map((reference) => reference.path),
15
+ ...(step.artifact.managedRegions ?? []).map((region) => region.path),
16
+ ];
11
17
  }));
12
18
  const resolveMaterialPaths = (plan, settingsPath, lockPath, baseDir, path) => Array.from(new Set([settingsPath, lockPath, ...(plan.materialPaths ?? []), ...collectArtifactPaths(plan)].map((candidate) => path.resolve(baseDir, candidate)))).sort();
13
19
  const fingerprintPath = (target, label, fs, path) => Effect.gen(function* () {
@@ -57,6 +63,7 @@ const planIdentity = (plan, baseDir, path) => JSON.stringify({
57
63
  steps: job.steps.map((step) => ({
58
64
  key: step.key,
59
65
  dependsOn: step.dependsOn,
66
+ materialPaths: step.materialPaths,
60
67
  label: step.label,
61
68
  readiness: step.readiness,
62
69
  artifact: step.artifact,
@@ -104,6 +104,8 @@ export interface JobStepArtifact {
104
104
  readonly previousVersion?: string;
105
105
  readonly fileCount?: number;
106
106
  readonly targets?: ReadonlyArray<JobStepArtifactTarget>;
107
+ /** Observed retained, absent, or unresolved state; these are not write targets. */
108
+ readonly references?: ReadonlyArray<JobStepArtifactReference>;
107
109
  readonly agentOutcomes?: ReadonlyArray<ConfiguredAgentOutcome>;
108
110
  readonly source?: JobStepArtifactSource;
109
111
  readonly managedRegions?: ReadonlyArray<JobStepManagedRegion>;
@@ -118,10 +120,20 @@ export interface JobStepManagedRegion {
118
120
  readonly path: string;
119
121
  readonly owner: string;
120
122
  }
123
+ export interface JobStepArtifactReference {
124
+ readonly path: string;
125
+ readonly state: "retained" | "absent" | "unknown";
126
+ readonly reason: string;
127
+ readonly unitId?: string;
128
+ readonly owner?: string;
129
+ }
121
130
  export interface JobStepArtifactTarget {
122
131
  readonly path: string;
123
132
  readonly change: ArtifactChange;
124
133
  readonly agentIds?: ReadonlyArray<string>;
134
+ readonly unitId?: string;
135
+ readonly owner?: string;
136
+ readonly entryName?: string;
125
137
  }
126
138
  export interface JobStepArtifactSource {
127
139
  readonly type: string;
@@ -154,6 +166,8 @@ export type JobStepResult<Output = never> = {
154
166
  export interface ReadyJobStep<Requirements = never, Output = never> {
155
167
  readonly key?: string;
156
168
  readonly dependsOn?: ReadonlyArray<string>;
169
+ /** Read-only inputs fingerprinted with this step, distinct from its write footprint. */
170
+ readonly materialPaths?: ReadonlyArray<string>;
157
171
  readonly readiness: "ready";
158
172
  readonly label: string;
159
173
  readonly message?: string;
@@ -166,6 +180,8 @@ export interface ReadyJobStep<Requirements = never, Output = never> {
166
180
  export interface WarnJobStep<Requirements = never, Output = never> {
167
181
  readonly key?: string;
168
182
  readonly dependsOn?: ReadonlyArray<string>;
183
+ /** Read-only inputs fingerprinted with this step, distinct from its write footprint. */
184
+ readonly materialPaths?: ReadonlyArray<string>;
169
185
  readonly readiness: "warn";
170
186
  readonly warnMessage: string;
171
187
  readonly label: string;
@@ -178,6 +194,8 @@ export interface WarnJobStep<Requirements = never, Output = never> {
178
194
  export interface ErrorJobStep {
179
195
  readonly key?: string;
180
196
  readonly dependsOn?: ReadonlyArray<string>;
197
+ /** Read-only inputs fingerprinted with this step, distinct from its write footprint. */
198
+ readonly materialPaths?: ReadonlyArray<string>;
181
199
  readonly readiness: "error";
182
200
  readonly errorMessage: string;
183
201
  readonly label: string;
@@ -203,7 +221,8 @@ export interface Job<Requirements = never, Output = never> {
203
221
  readonly concurrency: "unbounded" | number;
204
222
  /**
205
223
  * Defaults to ordered fail-fast execution. Use `best-effort` only when every
206
- * sibling step is independent; a failure still blocks subsequent jobs.
224
+ * sibling step is independent, including readiness failures; a failure still
225
+ * blocks subsequent jobs.
207
226
  */
208
227
  readonly executionPolicy?: JobExecutionPolicy;
209
228
  }
@@ -108,7 +108,10 @@ const outcomesFor = (ws, provider, configuredAgents, operation, state) => {
108
108
  /** The readiness blockers a plan's error steps contribute beyond declared conditions. */
109
109
  const readinessBlockersOf = (plan) => {
110
110
  const declaredConditionIds = new Set((plan.riskConditions ?? []).map((condition) => condition.id));
111
- return plan.jobs.flatMap((job) => job.steps.flatMap((step) => step.readiness === "error"
111
+ const hasRunnable = plan.jobs.some((job) => job.steps.some((step) => step.readiness !== "error"));
112
+ return plan.jobs
113
+ .filter((job) => !hasRunnable || job.executionPolicy !== "best-effort")
114
+ .flatMap((job) => job.steps.flatMap((step) => step.readiness === "error"
112
115
  ? (step.blockingConditionIds ?? []).length > 0 &&
113
116
  (step.blockingConditionIds ?? []).every((id) => declaredConditionIds.has(id))
114
117
  ? []
@@ -193,7 +196,10 @@ export const resolveExecutionCandidate = Effect.fn("resolveExecutionCandidate")(
193
196
  const candidatePlan = candidate.plan;
194
197
  const operations = candidate.configuredAgentOperations;
195
198
  const configuredAgents = operations.length === 0 ? [] : yield* ws.getConfiguredAgents();
196
- const readiness = scanPlanReadiness(candidatePlan);
199
+ const readiness = scanPlanReadiness({
200
+ ...candidatePlan,
201
+ jobs: candidatePlan.jobs.filter((job) => job.executionPolicy !== "best-effort"),
202
+ });
197
203
  const readinessBlockers = readinessBlockersOf(candidatePlan);
198
204
  const riskConditions = candidatePlan.riskConditions ?? [];
199
205
  const atomicity = declaredAtomicity(candidatePlan);
package/package.json CHANGED
@@ -4,36 +4,33 @@
4
4
  "url": "https://github.com/agentxm/axm/issues"
5
5
  },
6
6
  "dependencies": {
7
- "@agentxm/extension-model": "^0.29.4",
8
- "@agentxm/extension-resolution": "^0.29.4",
9
- "@agentxm/registry-protocol": "^0.29.4",
10
- "@agentxm/workspace-state": "^0.29.4",
11
- "@agentxm/workspace-transactions": "^0.29.4",
7
+ "@agentxm/extension-model": "^0.30.1",
8
+ "@agentxm/extension-resolution": "^0.30.1",
9
+ "@agentxm/registry-protocol": "^0.30.1",
10
+ "@agentxm/workspace-state": "^0.30.1",
11
+ "@agentxm/workspace-transactions": "^0.30.1",
12
12
  "effect": "4.0.0-rc.115"
13
13
  },
14
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.",
15
15
  "devDependencies": {
16
- "@agentxm/specification-metadata": "^0.29.4",
16
+ "@agentxm/specification-metadata": "^0.30.1",
17
17
  "@effect/platform-node": "4.0.0-rc.115",
18
18
  "@effect/vitest": "4.0.0-rc.115",
19
19
  "@typescript/native": "npm:typescript@^7.0.2",
20
20
  "typescript": "npm:@typescript/typescript6@^6.0.2",
21
- "vitest": "^5.0.0",
22
- "yaml": "^2.9.0"
21
+ "vitest": "^5.0.0"
23
22
  },
24
23
  "engines": {
25
24
  "node": ">=22.19.0"
26
25
  },
27
26
  "exports": {
28
27
  ".": {
29
- "axm-source": "./src/index.ts",
30
- "default": "./dist/src/index.js",
31
- "types": "./dist/src/index.d.ts"
28
+ "types": "./dist/src/index.d.ts",
29
+ "default": "./dist/src/index.js"
32
30
  },
33
31
  "./testing": {
34
- "axm-source": "./src/testing.ts",
35
- "default": "./dist/src/testing.js",
36
- "types": "./dist/src/testing.d.ts"
32
+ "types": "./dist/src/testing.d.ts",
33
+ "default": "./dist/src/testing.js"
37
34
  }
38
35
  },
39
36
  "files": [
@@ -56,5 +53,5 @@
56
53
  },
57
54
  "sideEffects": false,
58
55
  "type": "module",
59
- "version": "0.29.4"
56
+ "version": "0.30.1"
60
57
  }