@abelxiaoxing/cadence 1.5.3 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -1
- package/config/plan-draft.example.json +3 -0
- package/config/plan-draft.multiple-tasks.example.json +30 -0
- package/package.json +1 -1
- package/prompts/abel-design.md +33 -3
- package/prompts/abel-implement.md +36 -4
- package/src/apply-transaction.ts +1 -9
- package/src/artifact-store.ts +1 -9
- package/src/change-verification.ts +758 -65
- package/src/contracts.ts +8 -0
- package/src/delivery-compiler.ts +452 -9
- package/src/design-control.ts +2 -2
- package/src/design-diagnostics.ts +6 -4
- package/src/directory-sync.ts +36 -0
- package/src/durable-contracts.ts +19 -3
- package/src/durable-workflow.ts +47 -38
- package/src/implement-continuation.ts +559 -0
- package/src/implement-graph.ts +114 -0
- package/src/implement-plan.ts +2 -0
- package/src/index.ts +179 -1
- package/src/operator-cli.mjs +12 -7
- package/src/package-state.ts +309 -0
- package/src/package-verification.ts +17 -1
- package/src/package-workflow.ts +219 -171
- package/src/phase-execution.ts +7 -1
- package/src/plan-draft-summary.ts +385 -7
- package/src/plan-draft.ts +9 -0
- package/src/run-store.ts +39 -15
- package/src/storage-schema.ts +14 -6
- package/src/subagent-activity.ts +3 -1
- package/src/verification-capability.ts +17 -5
- package/src/verification-environment.ts +20 -2
- package/src/workflow-policy.ts +296 -5
- package/src/workflow-recovery-policy.ts +2 -0
- package/src/workflow-state-machine.ts +400 -131
- package/src/workflow-status.ts +251 -59
- package/src/workspace-io-worker.mjs +48 -42
- package/src/workspace-store.ts +1 -9
package/src/package-workflow.ts
CHANGED
|
@@ -14,6 +14,7 @@ import type { PackageContext } from "./model-source.ts";
|
|
|
14
14
|
import { inspectOpenSpecDelivery } from "./openspec-cli.ts";
|
|
15
15
|
import { proposePackageCandidate } from "./package-candidate.ts";
|
|
16
16
|
import { packageDeliverySource } from "./package-delivery.ts";
|
|
17
|
+
import { acquirePackageState } from "./package-state.ts";
|
|
17
18
|
import {
|
|
18
19
|
changeVerificationResult,
|
|
19
20
|
executePackageVerification,
|
|
@@ -79,6 +80,42 @@ function affectedVerification(
|
|
|
79
80
|
|
|
80
81
|
export function openPackageWorkflowService(
|
|
81
82
|
initialContext: PackageContext,
|
|
83
|
+
): PackageWorkflowService {
|
|
84
|
+
const state = acquirePackageState(
|
|
85
|
+
resolveStateRoot({
|
|
86
|
+
consumerRoot: path.resolve(initialContext.cwd),
|
|
87
|
+
xdgStateHome: process.env.XDG_STATE_HOME,
|
|
88
|
+
}),
|
|
89
|
+
);
|
|
90
|
+
try {
|
|
91
|
+
const service = openPreparedPackageWorkflowService(initialContext);
|
|
92
|
+
const notice = (result: Record<string, unknown>) =>
|
|
93
|
+
state.notice ? { ...result, packageStateReset: state.notice } : result;
|
|
94
|
+
return {
|
|
95
|
+
...service,
|
|
96
|
+
async execute(...args) {
|
|
97
|
+
return notice(await service.execute(...args));
|
|
98
|
+
},
|
|
99
|
+
async executeDesign(...args) {
|
|
100
|
+
return notice(await service.executeDesign(...args));
|
|
101
|
+
},
|
|
102
|
+
async executeAmendment(...args) {
|
|
103
|
+
return notice(await service.executeAmendment(...args));
|
|
104
|
+
},
|
|
105
|
+
async close() {
|
|
106
|
+
// Never release ownership while an executor or storage connection may survive.
|
|
107
|
+
await service.close();
|
|
108
|
+
state.close();
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
} catch (error) {
|
|
112
|
+
state.close();
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function openPreparedPackageWorkflowService(
|
|
118
|
+
initialContext: PackageContext,
|
|
82
119
|
): PackageWorkflowService {
|
|
83
120
|
const consumerRoot = path.resolve(initialContext.cwd);
|
|
84
121
|
const routeResolution = loadRoutePolicy({
|
|
@@ -102,180 +139,191 @@ export function openPackageWorkflowService(
|
|
|
102
139
|
stateRoot,
|
|
103
140
|
inspectOpenSpec: inspectOpenSpecDelivery,
|
|
104
141
|
});
|
|
105
|
-
|
|
106
|
-
(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
...
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
verifyFinalizedDelivery: (input) => design.verifyFinalizedDelivery(input),
|
|
151
|
-
}),
|
|
152
|
-
routePolicy: routeResolution.ok
|
|
153
|
-
? routeResolution.policy
|
|
154
|
-
: unavailableRoutePolicy(),
|
|
155
|
-
proposeCandidate: (input) =>
|
|
156
|
-
proposePackageCandidate(
|
|
157
|
-
input,
|
|
158
|
-
contexts.getStore(),
|
|
159
|
-
implementationAgent,
|
|
160
|
-
feedback.getStore()?.current(),
|
|
161
|
-
),
|
|
162
|
-
verifyPhase: async (input) =>
|
|
163
|
-
phaseVerificationResult(
|
|
164
|
-
await verify({
|
|
165
|
-
maxReportBytes,
|
|
166
|
-
executionWritePaths: input.executionWritePaths,
|
|
167
|
-
root: input.root,
|
|
168
|
-
dependencyOwner: consumerRoot,
|
|
169
|
-
verification: input.verification,
|
|
170
|
-
signal: input.signal,
|
|
171
|
-
}),
|
|
172
|
-
),
|
|
173
|
-
verifyChange: async (input) => {
|
|
174
|
-
const verifications = input.verification
|
|
175
|
-
? [input.verification]
|
|
176
|
-
: input.plan.tasks.map((task) => affectedVerification(task));
|
|
177
|
-
let failure: ReturnType<typeof changeVerificationResult> | undefined;
|
|
178
|
-
for (const verification of verifications) {
|
|
179
|
-
const result = await verify({
|
|
180
|
-
maxReportBytes,
|
|
181
|
-
executionWritePaths: input.plan.tasks.flatMap((task) =>
|
|
182
|
-
Object.values(task.phases).flatMap((phase) => [
|
|
183
|
-
...phase.write,
|
|
184
|
-
...phase.delete,
|
|
185
|
-
]),
|
|
142
|
+
try {
|
|
143
|
+
const implementationAgent = loadAgentDefinitions().find(
|
|
144
|
+
(agent) => agent.role === "implementation-worker",
|
|
145
|
+
);
|
|
146
|
+
if (!implementationAgent) {
|
|
147
|
+
throw new Error("implementation-worker-agent-unavailable");
|
|
148
|
+
}
|
|
149
|
+
const hostLimit = (name: string, fallback: number): number => {
|
|
150
|
+
const value =
|
|
151
|
+
process.env[name] === undefined ? fallback : Number(process.env[name]);
|
|
152
|
+
if (!Number.isSafeInteger(value) || value < 1)
|
|
153
|
+
throw new Error("verification-host-limit-invalid");
|
|
154
|
+
return value;
|
|
155
|
+
};
|
|
156
|
+
const maxReportBytes = hostLimit(
|
|
157
|
+
"ABEL_VERIFICATION_MAX_REPORT_BYTES",
|
|
158
|
+
64 * 1024 * 1024,
|
|
159
|
+
);
|
|
160
|
+
const workHardLimit = hostLimit("ABEL_WORK_MAX_UNITS", 512);
|
|
161
|
+
const engine = openDurableWorkflowEngine({
|
|
162
|
+
workHardLimit,
|
|
163
|
+
verificationPolicy: `report-file-v5:${JSON.stringify(executionProfile())}`,
|
|
164
|
+
verificationEnvironment: coalesceVerificationScans(
|
|
165
|
+
(plan: import("./implement-plan.ts").ImplementPlan, signal) =>
|
|
166
|
+
captureVerificationEnvironmentIdentity(
|
|
167
|
+
consumerRoot,
|
|
168
|
+
[
|
|
169
|
+
...plan.tasks.flatMap((task) => [
|
|
170
|
+
...Object.values(task.phases).map(
|
|
171
|
+
(phase) => phase.verification,
|
|
172
|
+
),
|
|
173
|
+
task.affectedVerification,
|
|
174
|
+
...(task.baselineVerification
|
|
175
|
+
? [task.baselineVerification]
|
|
176
|
+
: []),
|
|
177
|
+
task.repairVerification,
|
|
178
|
+
]),
|
|
179
|
+
plan.verification.baseline.fullSuite,
|
|
180
|
+
plan.verification.change.fullSuite,
|
|
181
|
+
plan.verification.change.postApply,
|
|
182
|
+
...(plan.verification.agentsCheckpoint.verification
|
|
183
|
+
? [plan.verification.agentsCheckpoint.verification]
|
|
184
|
+
: []),
|
|
185
|
+
],
|
|
186
|
+
signal,
|
|
186
187
|
),
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
188
|
+
),
|
|
189
|
+
consumerRoot,
|
|
190
|
+
stateRoot,
|
|
191
|
+
deliverySource: packageDeliverySource(consumerRoot, {
|
|
192
|
+
verifyGateProof: (input) => design.verifyGateProof(input),
|
|
193
|
+
verifyFinalizedDelivery: (input) =>
|
|
194
|
+
design.verifyFinalizedDelivery(input),
|
|
195
|
+
}),
|
|
196
|
+
routePolicy: routeResolution.ok
|
|
197
|
+
? routeResolution.policy
|
|
198
|
+
: unavailableRoutePolicy(),
|
|
199
|
+
proposeCandidate: (input) =>
|
|
200
|
+
proposePackageCandidate(
|
|
201
|
+
input,
|
|
202
|
+
contexts.getStore(),
|
|
203
|
+
implementationAgent,
|
|
204
|
+
feedback.getStore()?.current(),
|
|
205
|
+
),
|
|
206
|
+
verifyPhase: async (input) =>
|
|
207
|
+
phaseVerificationResult(
|
|
208
|
+
await verify({
|
|
209
|
+
maxReportBytes,
|
|
210
|
+
executionWritePaths: input.executionWritePaths,
|
|
211
|
+
root: input.root,
|
|
212
|
+
dependencyOwner: consumerRoot,
|
|
213
|
+
verification: input.verification,
|
|
214
|
+
signal: input.signal,
|
|
215
|
+
}),
|
|
216
|
+
),
|
|
217
|
+
verifyChange: async (input) => {
|
|
218
|
+
const verifications = input.verification
|
|
219
|
+
? [input.verification]
|
|
220
|
+
: input.plan.tasks.map((task) => affectedVerification(task));
|
|
221
|
+
let failure: ReturnType<typeof changeVerificationResult> | undefined;
|
|
222
|
+
for (const verification of verifications) {
|
|
223
|
+
const result = await verify({
|
|
224
|
+
maxReportBytes,
|
|
225
|
+
executionWritePaths: input.plan.tasks.flatMap((task) =>
|
|
226
|
+
Object.values(task.phases).flatMap((phase) => [
|
|
227
|
+
...phase.write,
|
|
228
|
+
...phase.delete,
|
|
200
229
|
]),
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
230
|
+
),
|
|
231
|
+
root: input.root,
|
|
232
|
+
dependencyOwner: consumerRoot,
|
|
233
|
+
verification,
|
|
234
|
+
signal: input.signal,
|
|
235
|
+
});
|
|
236
|
+
const observed = changeVerificationResult(result);
|
|
237
|
+
if (!observed.ok) {
|
|
238
|
+
if (observed.kind !== "verification") return observed;
|
|
239
|
+
if (failure && !failure.ok && failure.kind === "verification") {
|
|
240
|
+
failure.failureIdentities = [
|
|
241
|
+
...new Set([
|
|
242
|
+
...(failure.failureIdentities ?? []),
|
|
243
|
+
...(observed.failureIdentities ?? []),
|
|
244
|
+
]),
|
|
245
|
+
];
|
|
246
|
+
failure.attributionReliable =
|
|
247
|
+
failure.attributionReliable !== false &&
|
|
248
|
+
observed.attributionReliable !== false;
|
|
249
|
+
} else failure = observed;
|
|
250
|
+
}
|
|
206
251
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
}
|
|
252
|
+
if (failure) return failure;
|
|
253
|
+
return {
|
|
254
|
+
ok: true,
|
|
255
|
+
exitCode: 0,
|
|
256
|
+
classification: "expected-green",
|
|
257
|
+
};
|
|
258
|
+
},
|
|
259
|
+
});
|
|
260
|
+
return {
|
|
261
|
+
async execute(
|
|
262
|
+
command: unknown,
|
|
263
|
+
context = initialContext,
|
|
264
|
+
signal,
|
|
265
|
+
onActivity,
|
|
266
|
+
) {
|
|
267
|
+
const operationRouteResolution = loadRoutePolicy({
|
|
268
|
+
cwd: consumerRoot,
|
|
269
|
+
home: homedir(),
|
|
270
|
+
...(context.model ? { parentModel: context.model } : {}),
|
|
271
|
+
});
|
|
272
|
+
engine.updateRoutePolicy(
|
|
273
|
+
operationRouteResolution.ok
|
|
274
|
+
? operationRouteResolution.policy
|
|
275
|
+
: unavailableRoutePolicy(),
|
|
276
|
+
);
|
|
277
|
+
const validation = validateControlCommand(command);
|
|
278
|
+
if (!validation.ok) {
|
|
279
|
+
const error = new Error(validation.code);
|
|
280
|
+
error.name = "ControlCommandError";
|
|
281
|
+
throw error;
|
|
282
|
+
}
|
|
283
|
+
return feedback.run(new VerificationFeedback(), () =>
|
|
284
|
+
contexts.run(context, async () => {
|
|
285
|
+
const outcome = await engine.execute(
|
|
286
|
+
validation.value,
|
|
287
|
+
signal,
|
|
288
|
+
onActivity,
|
|
289
|
+
);
|
|
290
|
+
const routePolicy = visibleRoutePolicyStatus(
|
|
291
|
+
operationRouteResolution,
|
|
292
|
+
engine.routePolicyStatus(),
|
|
293
|
+
);
|
|
294
|
+
return {
|
|
295
|
+
...outcome,
|
|
296
|
+
routePolicy,
|
|
297
|
+
verificationDiagnostics: feedback.getStore()?.current() ?? [],
|
|
298
|
+
};
|
|
299
|
+
}),
|
|
300
|
+
);
|
|
301
|
+
},
|
|
302
|
+
executeDesign(request: unknown) {
|
|
303
|
+
return design.execute(request);
|
|
304
|
+
},
|
|
305
|
+
executeAmendment(change: string, batchId: string, request: unknown) {
|
|
306
|
+
return engine.amend(change, batchId, request, (assertAuthority) =>
|
|
307
|
+
design.executeWithAuthority(request, assertAuthority),
|
|
308
|
+
);
|
|
309
|
+
},
|
|
310
|
+
assertDesignRun(runId: string) {
|
|
311
|
+
design.assertDesignRun(runId);
|
|
312
|
+
},
|
|
313
|
+
recordDesignEvidence(input) {
|
|
314
|
+
return design.recordEvidence(input);
|
|
315
|
+
},
|
|
316
|
+
async close() {
|
|
317
|
+
contexts.disable();
|
|
318
|
+
await engine.close();
|
|
319
|
+
feedback.disable();
|
|
320
|
+
design.close();
|
|
321
|
+
},
|
|
322
|
+
};
|
|
323
|
+
} catch (error) {
|
|
324
|
+
design.close();
|
|
325
|
+
throw error;
|
|
326
|
+
}
|
|
279
327
|
}
|
|
280
328
|
|
|
281
329
|
function visibleRoutePolicyStatus(
|
package/src/phase-execution.ts
CHANGED
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
LOCKFILES,
|
|
44
44
|
SHA256,
|
|
45
45
|
semanticRouteFailure,
|
|
46
|
+
taskExecutionContract,
|
|
46
47
|
type WorkflowAttemptOutcome,
|
|
47
48
|
type WorkflowRouteFacts,
|
|
48
49
|
type WorkflowWorker,
|
|
@@ -60,6 +61,7 @@ export interface PhaseExecutionServices {
|
|
|
60
61
|
resources: PhaseResources;
|
|
61
62
|
ledger: TaskLedger;
|
|
62
63
|
signal: AbortSignal;
|
|
64
|
+
taskId?: string;
|
|
63
65
|
}): Promise<DurableBaselineResult>;
|
|
64
66
|
verifyTaskAffected(input: {
|
|
65
67
|
resources: PhaseResources;
|
|
@@ -197,7 +199,10 @@ export class PhaseExecution {
|
|
|
197
199
|
runId: input.runId,
|
|
198
200
|
deliveryRevision: input.deliveryRevision,
|
|
199
201
|
taskId: input.taskId,
|
|
200
|
-
boundaryHash: hash(
|
|
202
|
+
boundaryHash: hash(
|
|
203
|
+
"durable-task-boundary",
|
|
204
|
+
JSON.stringify(taskExecutionContract(input.task)),
|
|
205
|
+
),
|
|
201
206
|
objective: input.task.objective,
|
|
202
207
|
contextRefs,
|
|
203
208
|
initialPhase:
|
|
@@ -1562,6 +1567,7 @@ export class PhaseExecution {
|
|
|
1562
1567
|
resources,
|
|
1563
1568
|
ledger,
|
|
1564
1569
|
signal: input.signal,
|
|
1570
|
+
taskId: input.taskId,
|
|
1565
1571
|
});
|
|
1566
1572
|
if (!captured.ok) {
|
|
1567
1573
|
const outcome = captured.outcome;
|