@abelxiaoxing/cadence 1.0.10 → 1.0.12

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.
@@ -46,6 +46,7 @@ export class ParentPayloadBridgeError extends Error {
46
46
 
47
47
  export interface ParentProviderRegistry {
48
48
  getProvider(provider: string): Provider | undefined;
49
+ getRegisteredNativeProvider?(provider: string): Provider | undefined;
49
50
  registerProvider(provider: Provider): void;
50
51
  }
51
52
 
@@ -198,9 +199,12 @@ export class ParentPayloadBridge {
198
199
  model: Model<string>,
199
200
  registry: ParentProviderRegistry,
200
201
  ): Provider | undefined {
201
- const current = registry.getProvider(model.provider);
202
+ const current = this.nativeCarrier(model.provider, registry);
202
203
  if (!current) return undefined;
203
204
  const delegate = this.unwrapProvider(current);
205
+ const wrapped = this.isWrappedProvider(current)
206
+ ? current
207
+ : this.wrapProvider(delegate);
204
208
  const state = this.state;
205
209
  if (state?.active) {
206
210
  const key = modelKeyId(modelKeyFor(model));
@@ -210,14 +214,18 @@ export class ParentPayloadBridge {
210
214
  state.ready.delete(key);
211
215
  }
212
216
  }
213
- const wrapped = this.wrapProvider(delegate);
214
- registry.registerProvider(wrapped);
217
+ if (wrapped !== current) {
218
+ registry.registerProvider(wrapped);
219
+ }
215
220
  return wrapped;
216
221
  }
217
222
 
218
223
  capture(
219
224
  modelKey: ParentModelKey,
220
- registry?: Pick<ParentProviderRegistry, "getProvider">,
225
+ registry?: Pick<
226
+ ParentProviderRegistry,
227
+ "getProvider" | "getRegisteredNativeProvider"
228
+ >,
221
229
  ): ParentPayloadCapture | undefined {
222
230
  const state = this.state;
223
231
  if (!state?.active) return undefined;
@@ -226,7 +234,7 @@ export class ParentPayloadBridge {
226
234
  return undefined;
227
235
  }
228
236
  if (registry) {
229
- const current = registry.getProvider(modelKey.provider);
237
+ const current = this.nativeCarrier(modelKey.provider, registry);
230
238
  if (!current || this.unwrapProvider(current) !== capture.delegate) {
231
239
  return undefined;
232
240
  }
@@ -236,11 +244,14 @@ export class ParentPayloadBridge {
236
244
 
237
245
  diagnoseCapture(
238
246
  modelKey: ParentModelKey,
239
- registry: Pick<ParentProviderRegistry, "getProvider">,
247
+ registry: Pick<
248
+ ParentProviderRegistry,
249
+ "getProvider" | "getRegisteredNativeProvider"
250
+ >,
240
251
  ): ParentBridgeFailureCode | undefined {
241
252
  const state = this.state;
242
253
  if (!state?.active) return "parent-bridge-session-unavailable";
243
- const current = registry.getProvider(modelKey.provider);
254
+ const current = this.nativeCarrier(modelKey.provider, registry);
244
255
  if (!current || !this.isWrappedProvider(current)) {
245
256
  return "parent-bridge-provider-not-installed";
246
257
  }
@@ -468,6 +479,19 @@ export class ParentPayloadBridge {
468
479
  return state;
469
480
  }
470
481
 
482
+ private nativeCarrier(
483
+ providerId: string,
484
+ registry: Pick<
485
+ ParentProviderRegistry,
486
+ "getProvider" | "getRegisteredNativeProvider"
487
+ >,
488
+ ): Provider | undefined {
489
+ const registered = registry.getRegisteredNativeProvider?.(providerId);
490
+ return registered && this.isWrappedProvider(registered)
491
+ ? registered
492
+ : registry.getProvider(providerId);
493
+ }
494
+
471
495
  private isWrappedProvider(provider: Provider): boolean {
472
496
  return Reflect.get(provider, PROVIDER_WRAPPER) !== undefined;
473
497
  }
package/src/patch.ts CHANGED
@@ -48,6 +48,11 @@ async function git(
48
48
  settled = true;
49
49
  resolve(result);
50
50
  };
51
+ const fail = (error: Error) => {
52
+ if (settled) return;
53
+ settled = true;
54
+ reject(error);
55
+ };
51
56
  child.stdout.on("data", (b: Buffer) => stdout.push(b));
52
57
  child.stderr.on("data", (b: Buffer) => stderr.push(b));
53
58
  child.on("error", (error) => {
@@ -59,7 +64,7 @@ async function git(
59
64
  cancelled: true,
60
65
  });
61
66
  } else {
62
- reject(error);
67
+ fail(error);
63
68
  }
64
69
  });
65
70
  child.on("close", (code) =>
@@ -70,6 +75,11 @@ async function git(
70
75
  cancelled: signal?.aborted ?? false,
71
76
  }),
72
77
  );
78
+ child.stdin.on("error", (error: NodeJS.ErrnoException) => {
79
+ // A command may reject its input and exit before Node finishes writing it.
80
+ // Its exit status remains the authoritative command result.
81
+ if (error.code !== "EPIPE") fail(error);
82
+ });
73
83
  child.stdin.end(input);
74
84
  });
75
85
  }
@@ -349,6 +359,8 @@ export async function applyRetainedPatch(input: {
349
359
  return failure({ kind: preflight.kind, code: preflight.code });
350
360
  case "environment":
351
361
  return failure({ kind: preflight.kind, code: preflight.code });
362
+ case "verification-adapter":
363
+ return failure({ kind: preflight.kind, code: preflight.code });
352
364
  case "approval-boundary":
353
365
  return failure({ kind: preflight.kind, code: preflight.code });
354
366
  case "cancelled":
@@ -4,7 +4,10 @@ import type {
4
4
  BaselineEntry,
5
5
  VerificationContract,
6
6
  } from "./candidate-preflight.ts";
7
- import type { ImplementationPhase } from "./contracts.ts";
7
+ import {
8
+ cloneVerificationContract,
9
+ type ImplementationPhase,
10
+ } from "./contracts.ts";
8
11
  import type { Bound, DirBound, FileBound } from "./file-snapshot.ts";
9
12
  import { snapshotFiles } from "./file-snapshot.ts";
10
13
 
@@ -105,10 +108,7 @@ function cloneRetained(retained: RetainedResult): RetainedResult {
105
108
  baseline: retained.baseline.map((entry) => ({ ...entry })),
106
109
  };
107
110
  if (retained.verification) {
108
- clone.verification = {
109
- ...retained.verification,
110
- argv: [...retained.verification.argv],
111
- };
111
+ clone.verification = cloneVerificationContract(retained.verification);
112
112
  }
113
113
  if (retained.packageManifest) {
114
114
  clone.packageManifest = { ...retained.packageManifest };
@@ -147,10 +147,7 @@ export class ResultStore {
147
147
  ...(input.verification === undefined
148
148
  ? {}
149
149
  : {
150
- verification: {
151
- ...input.verification,
152
- argv: [...input.verification.argv],
153
- },
150
+ verification: cloneVerificationContract(input.verification),
154
151
  }),
155
152
  ...(input.packageManifest === undefined
156
153
  ? {}
package/src/runtime.ts CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  type AgentsCheckpointRequest,
13
13
  type CandidateFailure,
14
14
  type ChildFailure,
15
+ cloneVerificationContract,
15
16
  type DiffResult,
16
17
  type ImplementApplyOperation,
17
18
  type ImplementationPhase,
@@ -29,6 +30,7 @@ import {
29
30
  validateImplementDiscardOperation,
30
31
  validatePhaseAttemptAgainstBoundary,
31
32
  validateRequestEnvelope,
33
+ verificationInputPaths,
32
34
  } from "./contracts.ts";
33
35
  import { drainStage } from "./drain.ts";
34
36
  import {
@@ -56,6 +58,7 @@ import {
56
58
  resolveSubagentEndpoint,
57
59
  type SubagentEndpoint,
58
60
  } from "./subagent-endpoint.ts";
61
+ import { assessVerificationReadiness } from "./verification-capability.ts";
59
62
  import {
60
63
  type TaskRecord,
61
64
  taskConflictOf,
@@ -119,10 +122,7 @@ function cloneLegacyEnvelope(request: RequestEnvelope): RequestEnvelope {
119
122
  ...(request.verification === undefined
120
123
  ? {}
121
124
  : {
122
- verification: {
123
- ...request.verification,
124
- argv: [...request.verification.argv],
125
- },
125
+ verification: cloneVerificationContract(request.verification),
126
126
  }),
127
127
  ...(request.snapshot === undefined
128
128
  ? {}
@@ -163,10 +163,7 @@ function deriveImplementEnvelope(
163
163
  agentsManagedOnly: true,
164
164
  approvedDependencies: [...boundary.approvedDependencies],
165
165
  impactClosure: structuredClone(boundary.impactClosure),
166
- verification: {
167
- ...phase.verification,
168
- argv: [...phase.verification.argv],
169
- },
166
+ verification: cloneVerificationContract(phase.verification),
170
167
  snapshot: structuredClone(attempt.snapshot),
171
168
  };
172
169
  }
@@ -318,7 +315,7 @@ function preparePreflight(
318
315
  ...envelope.declared.write,
319
316
  "package.json",
320
317
  lockPath,
321
- ...envelope.verification.argv.slice(3),
318
+ ...verificationInputPaths(envelope.verification),
322
319
  ]);
323
320
  const entries = new Map<string, BaselineEntry>();
324
321
  const observed: Bound = {};
@@ -446,6 +443,7 @@ function failureClassOf(failure: ChildFailure): FailureClass | undefined {
446
443
  return "transport";
447
444
  case "stale":
448
445
  case "approval-boundary":
446
+ case "verification-adapter":
449
447
  case "cancelled":
450
448
  case "result-limit":
451
449
  return undefined;
@@ -465,6 +463,7 @@ function childFailureOf(result: InternalFailureResult): ChildFailure {
465
463
  case "stale":
466
464
  case "environment":
467
465
  case "approval-boundary":
466
+ case "verification-adapter":
468
467
  case "cancelled":
469
468
  case "result-limit":
470
469
  case "transport":
@@ -495,6 +494,7 @@ function terminalTaskFailure(failure: ChildFailure): TaskFailure | undefined {
495
494
  switch (failure.kind) {
496
495
  case "approval-boundary":
497
496
  case "environment":
497
+ case "verification-adapter":
498
498
  case "result-limit":
499
499
  return failure;
500
500
  case "artifact":
@@ -515,6 +515,7 @@ function attemptFailureCause(
515
515
  return failure.kind;
516
516
  case "approval-boundary":
517
517
  case "environment":
518
+ case "verification-adapter":
518
519
  case "result-limit":
519
520
  case "cancelled":
520
521
  throw new Error("non-retryable failure reached the launch budget");
@@ -992,6 +993,15 @@ export class Runtime {
992
993
  };
993
994
  return blockedOutcome(identity, taskFailure);
994
995
  }
996
+ case "verification-adapter": {
997
+ const taskFailure: TaskFailure = failure;
998
+ worker.state = {
999
+ kind: "blocked",
1000
+ phase,
1001
+ failure: structuredClone(taskFailure),
1002
+ };
1003
+ return blockedOutcome(identity, taskFailure);
1004
+ }
995
1005
  case "cancelled":
996
1006
  return cancelledOutcome(identity);
997
1007
  case "result-limit": {
@@ -1260,6 +1270,15 @@ export class Runtime {
1260
1270
  };
1261
1271
  return blockedOutcome(outcomeIdentity, failure);
1262
1272
  }
1273
+ case "verification-adapter": {
1274
+ this.results.discard(resultId);
1275
+ worker.state = {
1276
+ kind: "blocked",
1277
+ phase: identity.phase,
1278
+ failure: structuredClone(failure),
1279
+ };
1280
+ return blockedOutcome(outcomeIdentity, failure);
1281
+ }
1263
1282
  case "stale": {
1264
1283
  this.results.discard(resultId);
1265
1284
  if (identity.launchIndex === 0) {
@@ -1562,6 +1581,42 @@ export class Runtime {
1562
1581
  attempt.changeId,
1563
1582
  attempt.taskId,
1564
1583
  );
1584
+ if (runRequest.kind === "open-task") {
1585
+ const phases = runRequest.boundary.phases;
1586
+ const readiness = assessVerificationReadiness(
1587
+ workspaceRoot,
1588
+ [
1589
+ phases.red.verification,
1590
+ phases.green.verification,
1591
+ ...(phases.refactor ? [phases.refactor.verification] : []),
1592
+ ],
1593
+ {
1594
+ allowedMissingInputs: [
1595
+ ...new Set([
1596
+ ...phases.red.write,
1597
+ ...phases.green.write,
1598
+ ...(phases.refactor?.write ?? []),
1599
+ ]),
1600
+ ],
1601
+ },
1602
+ );
1603
+ const diagnostic = readiness.diagnostics[0];
1604
+ if (diagnostic) {
1605
+ if (diagnostic.kind === "design-readiness") {
1606
+ throw new Error(
1607
+ `Implement protocol error: ${diagnostic.code}: ${diagnostic.message}`,
1608
+ );
1609
+ }
1610
+ return {
1611
+ ok: false,
1612
+ error: `${diagnostic.kind}/${diagnostic.code}: ${diagnostic.message}`,
1613
+ failure: {
1614
+ kind: diagnostic.kind,
1615
+ code: diagnostic.code,
1616
+ },
1617
+ };
1618
+ }
1619
+ }
1565
1620
  if (
1566
1621
  runRequest.kind === "open-task" &&
1567
1622
  this.registry