@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.
package/src/contracts.ts CHANGED
@@ -133,6 +133,14 @@ export const APPROVAL_BOUNDARY_CODES = [
133
133
  "verification-contract-insufficient",
134
134
  "agents-contract-insufficient",
135
135
  ] as const;
136
+ export const VERIFICATION_ADAPTER_CODES = [
137
+ "input-missing",
138
+ "local-executable-missing",
139
+ "runner-missing",
140
+ "script-command-mismatch",
141
+ "script-missing",
142
+ "script-unsafe",
143
+ ] as const;
136
144
  export const CHILD_TRANSPORT_CODES = [
137
145
  "child-no-final-assistant",
138
146
  "child-provider-stream-aborted",
@@ -153,6 +161,8 @@ export type ArtifactFailureCode = (typeof ARTIFACT_FAILURE_CODES)[number];
153
161
  export type StaleFailureCode = (typeof STALE_FAILURE_CODES)[number];
154
162
  export type EnvironmentFailureCode = (typeof ENVIRONMENT_FAILURE_CODES)[number];
155
163
  export type ApprovalBoundaryCode = (typeof APPROVAL_BOUNDARY_CODES)[number];
164
+ export type VerificationAdapterCode =
165
+ (typeof VERIFICATION_ADAPTER_CODES)[number];
156
166
  export type ChildTransportCode = (typeof CHILD_TRANSPORT_CODES)[number];
157
167
  export type FailureStage = (typeof FAILURE_STAGES)[number];
158
168
 
@@ -172,6 +182,7 @@ export type CandidateFailure =
172
182
  | { kind: "artifact"; code: ArtifactFailureCode; evidence?: string[] }
173
183
  | { kind: "stale"; code: StaleFailureCode }
174
184
  | EnvironmentFailure
185
+ | { kind: "verification-adapter"; code: VerificationAdapterCode }
175
186
  | { kind: "approval-boundary"; code: ApprovalBoundaryCode }
176
187
  | { kind: "cancelled"; code: "cancelled" }
177
188
  | { kind: "result-limit"; limitBytes: number };
@@ -194,6 +205,7 @@ export type CandidateRejection =
194
205
 
195
206
  export type TaskFailure =
196
207
  | { kind: "approval-boundary"; code: ApprovalBoundaryCode }
208
+ | { kind: "verification-adapter"; code: VerificationAdapterCode }
197
209
  | {
198
210
  kind: "attempts-exhausted";
199
211
  cause: "artifact" | "stale" | "transport";
@@ -219,14 +231,84 @@ export type ApplyCandidateResult =
219
231
  const NONCANONICAL = /(^|\/)\.\.(\/|$)|(^|\/)\/|^\//;
220
232
  const SNAPSHOT_SHA256 = /^[a-f0-9]{64}$/;
221
233
 
222
- export interface VerificationContract {
234
+ export type VerificationClassification =
235
+ | "expected-red"
236
+ | "expected-green"
237
+ | "expected-refactor";
238
+
239
+ interface VerificationBase {
223
240
  id: string;
224
- argv: string[];
225
- classification: "expected-red" | "expected-green" | "expected-refactor";
241
+ classification: VerificationClassification;
226
242
  expectedFailure?: string;
243
+ /** Internal marker retained only for normalized 1.0.x argv compatibility. */
244
+ legacy?: true;
245
+ }
246
+
247
+ export type PackageManager = "bun" | "npm" | "pnpm" | "yarn";
248
+
249
+ export interface PackageScriptRunner {
250
+ kind: "package-script";
251
+ packageManager: PackageManager;
252
+ script: string;
253
+ /** Exact Gate-B-approved package.json script value. Omitted only for legacy input. */
254
+ command?: string;
255
+ }
256
+
257
+ export type ExecutableRunner =
258
+ | PackageScriptRunner
259
+ | { kind: "local-binary"; executable: string }
260
+ | { kind: "npx"; executable: string; noInstall: true };
261
+
262
+ export interface VitestVerificationContract extends VerificationBase {
263
+ kind: "vitest";
264
+ runner: ExecutableRunner;
265
+ testFiles: string[];
266
+ args: string[];
227
267
  minTests: number;
228
268
  }
229
269
 
270
+ export interface PackageScriptVerificationContract extends VerificationBase {
271
+ kind: "package-script";
272
+ packageManager: PackageManager;
273
+ script: string;
274
+ /** Exact Gate-B-approved package.json script value. Omitted only for legacy input. */
275
+ command?: string;
276
+ args: string[];
277
+ }
278
+
279
+ export interface StaticCheckVerificationContract extends VerificationBase {
280
+ kind: "static-check";
281
+ runner: ExecutableRunner | { kind: "node"; script: string };
282
+ args: string[];
283
+ }
284
+
285
+ export type AtomicVerificationContract =
286
+ | VitestVerificationContract
287
+ | PackageScriptVerificationContract
288
+ | StaticCheckVerificationContract;
289
+
290
+ export interface VerificationStepsContract {
291
+ kind: "steps";
292
+ id: string;
293
+ classification: VerificationClassification;
294
+ steps: AtomicVerificationContract[];
295
+ }
296
+
297
+ /** @deprecated Accepted only as 1.0.x compatibility input and normalized immediately. */
298
+ export interface LegacyVerificationContract extends VerificationBase {
299
+ argv: string[];
300
+ minTests: number;
301
+ kind?: never;
302
+ }
303
+
304
+ export type StructuredVerificationContract =
305
+ | AtomicVerificationContract
306
+ | VerificationStepsContract;
307
+
308
+ export type VerificationContract =
309
+ | StructuredVerificationContract
310
+ | LegacyVerificationContract;
311
+
230
312
  export interface ImpactClosureContract {
231
313
  changedSurfaces: ImpactSurface[];
232
314
  searchEvidence: string[];
@@ -367,57 +449,387 @@ export function isAgentsPath(p: unknown): p is string {
367
449
  return isValidRelativePath(p) && /(?:^|\/)AGENTS\.md$/u.test(p);
368
450
  }
369
451
 
370
- export function validateVerificationContract(
452
+ const UNSAFE_VERIFICATION_TOKEN = /[;&|`$<>\n\r\0]/u;
453
+ const VERIFICATION_NAME = /^[a-z0-9][a-z0-9._:@/-]*$/iu;
454
+ const EXECUTABLE_NAME = /^[a-z0-9][a-z0-9._-]*$/iu;
455
+
456
+ function validVerificationToken(value: unknown): value is string {
457
+ const optionValue =
458
+ typeof value === "string" && value.includes("=")
459
+ ? value.slice(value.indexOf("=") + 1)
460
+ : value;
461
+ return (
462
+ typeof value === "string" &&
463
+ value.length > 0 &&
464
+ value.length <= 512 &&
465
+ value.trim() === value &&
466
+ !UNSAFE_VERIFICATION_TOKEN.test(value) &&
467
+ !value.includes("\\") &&
468
+ !value.startsWith("/") &&
469
+ !/^[a-z]:\//iu.test(value) &&
470
+ !/(^|\/)\.\.(\/|$)/u.test(value) &&
471
+ typeof optionValue === "string" &&
472
+ !optionValue.startsWith("/") &&
473
+ !/^[a-z]:\//iu.test(optionValue) &&
474
+ !/(^|\/)\.\.(\/|$)/u.test(optionValue)
475
+ );
476
+ }
477
+
478
+ function validVerificationArgs(value: unknown): value is string[] {
479
+ return (
480
+ Array.isArray(value) &&
481
+ value.length <= 128 &&
482
+ value.every(validVerificationToken)
483
+ );
484
+ }
485
+
486
+ function validScriptCommand(value: unknown): value is string {
487
+ return (
488
+ typeof value === "string" &&
489
+ value.length > 0 &&
490
+ value.length <= 1024 &&
491
+ value.trim() === value &&
492
+ !UNSAFE_VERIFICATION_TOKEN.test(value)
493
+ );
494
+ }
495
+
496
+ function validVerificationIdentity(contract: Record<string, unknown>): boolean {
497
+ if (
498
+ typeof contract.id !== "string" ||
499
+ contract.id.length === 0 ||
500
+ contract.id.length > 128 ||
501
+ !["expected-red", "expected-green", "expected-refactor"].includes(
502
+ String(contract.classification),
503
+ )
504
+ ) {
505
+ return false;
506
+ }
507
+ return contract.classification === "expected-red"
508
+ ? typeof contract.expectedFailure === "string" &&
509
+ contract.expectedFailure.length > 0 &&
510
+ contract.expectedFailure.length <= 512
511
+ : contract.expectedFailure === undefined;
512
+ }
513
+
514
+ function validatePackageScriptRunner(
515
+ value: unknown,
516
+ requireCommand: boolean,
517
+ ): value is PackageScriptRunner {
518
+ if (
519
+ !hasExactKeys(
520
+ value,
521
+ requireCommand
522
+ ? ["kind", "packageManager", "script", "command"]
523
+ : ["kind", "packageManager", "script"],
524
+ requireCommand ? [] : ["command"],
525
+ ) ||
526
+ value.kind !== "package-script" ||
527
+ !["bun", "npm", "pnpm", "yarn"].includes(String(value.packageManager)) ||
528
+ typeof value.script !== "string" ||
529
+ !VERIFICATION_NAME.test(value.script) ||
530
+ value.script.includes("/") ||
531
+ (value.command !== undefined && !validScriptCommand(value.command))
532
+ ) {
533
+ return false;
534
+ }
535
+ return !requireCommand || value.command !== undefined;
536
+ }
537
+
538
+ function validateExecutableRunner(
539
+ value: unknown,
540
+ requirePackageCommand: boolean,
541
+ ): value is ExecutableRunner {
542
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
543
+ const runner = value as Record<string, unknown>;
544
+ if (runner.kind === "package-script") {
545
+ return validatePackageScriptRunner(runner, requirePackageCommand);
546
+ }
547
+ if (
548
+ runner.kind === "local-binary" &&
549
+ hasExactKeys(runner, ["kind", "executable"])
550
+ ) {
551
+ return (
552
+ typeof runner.executable === "string" &&
553
+ EXECUTABLE_NAME.test(runner.executable)
554
+ );
555
+ }
556
+ return (
557
+ runner.kind === "npx" &&
558
+ hasExactKeys(runner, ["kind", "executable", "noInstall"]) &&
559
+ typeof runner.executable === "string" &&
560
+ EXECUTABLE_NAME.test(runner.executable) &&
561
+ runner.noInstall === true
562
+ );
563
+ }
564
+
565
+ function validateVitestRunner(
566
+ value: ExecutableRunner,
567
+ legacy: boolean,
568
+ ): boolean {
569
+ if (legacy) return true;
570
+ if (value.kind === "package-script") {
571
+ const tokens = value.command?.split(/\s+/u) ?? [];
572
+ return (
573
+ tokens[0] === "vitest" ||
574
+ (tokens[0] === "npx" &&
575
+ tokens[1] === "--no-install" &&
576
+ tokens[2] === "vitest")
577
+ );
578
+ }
579
+ return value.executable === "vitest";
580
+ }
581
+
582
+ function validateAtomicVerification(
583
+ value: unknown,
584
+ requirePackageCommand: boolean,
585
+ ): value is AtomicVerificationContract {
586
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
587
+ const contract = value as Record<string, unknown>;
588
+ const legacy = contract.legacy === true;
589
+ const packageCommandRequired = requirePackageCommand && !legacy;
590
+ const expectedFailure =
591
+ contract.classification === "expected-red" ? ["expectedFailure"] : [];
592
+ if (contract.kind === "vitest") {
593
+ const legacyRunner = contract.runner as Record<string, unknown>;
594
+ const executableRunner = contract.runner as ExecutableRunner;
595
+ return (
596
+ hasExactKeys(contract, [
597
+ "kind",
598
+ "id",
599
+ "runner",
600
+ "testFiles",
601
+ "args",
602
+ "classification",
603
+ ...expectedFailure,
604
+ "minTests",
605
+ ...(legacy ? ["legacy"] : []),
606
+ ]) &&
607
+ validVerificationIdentity(contract) &&
608
+ validateExecutableRunner(contract.runner, packageCommandRequired) &&
609
+ validateVitestRunner(executableRunner, legacy) &&
610
+ Array.isArray(contract.testFiles) &&
611
+ contract.testFiles.length > 0 &&
612
+ contract.testFiles.length <= 64 &&
613
+ contract.testFiles.every(isValidRelativePath) &&
614
+ new Set(contract.testFiles).size === contract.testFiles.length &&
615
+ validVerificationArgs(contract.args) &&
616
+ Number.isSafeInteger(contract.minTests) &&
617
+ (contract.minTests as number) >= 1 &&
618
+ (!legacy ||
619
+ (hasExactKeys(legacyRunner, ["kind", "packageManager", "script"]) &&
620
+ legacyRunner.kind === "package-script" &&
621
+ legacyRunner.packageManager === "bun" &&
622
+ legacyRunner.script === "test:target" &&
623
+ contract.testFiles.every((part) => part.startsWith("test/")) &&
624
+ contract.args.length === 0))
625
+ );
626
+ }
627
+ if (contract.kind === "package-script") {
628
+ const runner = {
629
+ kind: "package-script",
630
+ packageManager: contract.packageManager,
631
+ script: contract.script,
632
+ ...(contract.command === undefined ? {} : { command: contract.command }),
633
+ };
634
+ return (
635
+ hasExactKeys(
636
+ contract,
637
+ [
638
+ "kind",
639
+ "id",
640
+ "packageManager",
641
+ "script",
642
+ ...(packageCommandRequired ? ["command"] : []),
643
+ "args",
644
+ "classification",
645
+ ...expectedFailure,
646
+ ...(legacy ? ["legacy"] : []),
647
+ ],
648
+ packageCommandRequired ? [] : ["command"],
649
+ ) &&
650
+ validVerificationIdentity(contract) &&
651
+ validatePackageScriptRunner(runner, packageCommandRequired) &&
652
+ validVerificationArgs(contract.args) &&
653
+ (!legacy ||
654
+ (contract.packageManager === "bun" &&
655
+ contract.script === "check" &&
656
+ contract.command === undefined &&
657
+ contract.args.length === 0))
658
+ );
659
+ }
660
+ if (contract.kind !== "static-check") return false;
661
+ const runner = contract.runner as Record<string, unknown> | undefined;
662
+ const validRunner =
663
+ validateExecutableRunner(runner, requirePackageCommand) ||
664
+ (hasExactKeys(runner, ["kind", "script"]) &&
665
+ runner.kind === "node" &&
666
+ isValidRelativePath(runner.script));
667
+ return (
668
+ hasExactKeys(contract, [
669
+ "kind",
670
+ "id",
671
+ "runner",
672
+ "args",
673
+ "classification",
674
+ ...expectedFailure,
675
+ ]) &&
676
+ validVerificationIdentity(contract) &&
677
+ validRunner &&
678
+ validVerificationArgs(contract.args)
679
+ );
680
+ }
681
+
682
+ function validateStructuredVerification(
371
683
  value: unknown,
372
- ): { ok: true; value: VerificationContract } | { ok: false; reason: string } {
373
- if (value === null || typeof value !== "object" || Array.isArray(value))
374
- return { ok: false, reason: "invalid verification contract" };
684
+ ): value is StructuredVerificationContract {
685
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
375
686
  const contract = value as Record<string, unknown>;
687
+ if (contract.kind !== "steps") {
688
+ return validateAtomicVerification(contract, true);
689
+ }
376
690
  if (
691
+ !hasExactKeys(contract, ["kind", "id", "classification", "steps"]) ||
377
692
  typeof contract.id !== "string" ||
378
693
  contract.id.length === 0 ||
379
694
  contract.id.length > 128 ||
380
- !Array.isArray(contract.argv) ||
381
- contract.argv.some(
382
- (part) =>
383
- typeof part !== "string" ||
384
- part.length === 0 ||
385
- /[;&|`$<>\n\r]/u.test(part) ||
386
- part.includes("\0"),
387
- ) ||
388
695
  !["expected-red", "expected-green", "expected-refactor"].includes(
389
696
  String(contract.classification),
390
697
  ) ||
698
+ !Array.isArray(contract.steps) ||
699
+ contract.steps.length === 0 ||
700
+ contract.steps.length > 8 ||
701
+ !contract.steps.every((step) => validateAtomicVerification(step, true))
702
+ ) {
703
+ return false;
704
+ }
705
+ const steps = contract.steps as AtomicVerificationContract[];
706
+ return (
707
+ steps
708
+ .slice(0, -1)
709
+ .every((step) => step.classification === "expected-green") &&
710
+ steps.at(-1)?.classification === contract.classification &&
711
+ new Set(steps.map((step) => step.id)).size === steps.length
712
+ );
713
+ }
714
+
715
+ function normalizeLegacyVerification(
716
+ contract: Record<string, unknown>,
717
+ ): StructuredVerificationContract | null {
718
+ if (
719
+ !hasExactKeys(
720
+ contract,
721
+ ["id", "argv", "classification", "minTests"],
722
+ ["expectedFailure"],
723
+ ) ||
724
+ !validVerificationIdentity(contract) ||
391
725
  !Number.isSafeInteger(contract.minTests) ||
392
- (contract.minTests as number) < 1
726
+ (contract.minTests as number) < 1 ||
727
+ !Array.isArray(contract.argv) ||
728
+ !contract.argv.every(validVerificationToken)
393
729
  ) {
394
- return { ok: false, reason: "invalid verification contract" };
730
+ return null;
395
731
  }
396
732
  const argv = contract.argv as string[];
397
- const check =
398
- argv.length === 3 &&
399
- argv[0] === "bun" &&
400
- argv[1] === "run" &&
401
- argv[2] === "check";
402
- const target =
733
+ const base = {
734
+ id: contract.id as string,
735
+ classification: contract.classification as VerificationClassification,
736
+ ...(contract.expectedFailure === undefined
737
+ ? {}
738
+ : { expectedFailure: contract.expectedFailure as string }),
739
+ };
740
+ if (
403
741
  argv.length >= 4 &&
404
742
  argv[0] === "bun" &&
405
743
  argv[1] === "run" &&
406
744
  argv[2] === "test:target" &&
407
745
  argv
408
746
  .slice(3)
409
- .every((part) => part.startsWith("test/") && isValidRelativePath(part));
410
- if (!check && !target)
411
- return { ok: false, reason: "verification argv is not approved" };
747
+ .every((part) => part.startsWith("test/") && isValidRelativePath(part))
748
+ ) {
749
+ return {
750
+ ...base,
751
+ kind: "vitest",
752
+ runner: {
753
+ kind: "package-script",
754
+ packageManager: "bun",
755
+ script: "test:target",
756
+ },
757
+ testFiles: argv.slice(3),
758
+ args: [],
759
+ minTests: contract.minTests as number,
760
+ legacy: true,
761
+ };
762
+ }
412
763
  if (
413
- contract.classification === "expected-red"
414
- ? typeof contract.expectedFailure !== "string" ||
415
- contract.expectedFailure.length === 0
416
- : contract.expectedFailure !== undefined
764
+ argv.length === 3 &&
765
+ argv[0] === "bun" &&
766
+ argv[1] === "run" &&
767
+ argv[2] === "check"
417
768
  ) {
418
- return { ok: false, reason: "invalid expected failure identity" };
769
+ return {
770
+ ...base,
771
+ kind: "package-script",
772
+ packageManager: "bun",
773
+ script: "check",
774
+ args: [],
775
+ legacy: true,
776
+ };
777
+ }
778
+ return null;
779
+ }
780
+
781
+ export function validateVerificationContract(
782
+ value: unknown,
783
+ ):
784
+ | { ok: true; value: StructuredVerificationContract }
785
+ | { ok: false; reason: string } {
786
+ if (validateStructuredVerification(value)) {
787
+ return { ok: true, value: structuredClone(value) };
419
788
  }
420
- return { ok: true, value: contract as unknown as VerificationContract };
789
+ if (value && typeof value === "object" && !Array.isArray(value)) {
790
+ const legacy = normalizeLegacyVerification(
791
+ value as Record<string, unknown>,
792
+ );
793
+ if (legacy) return { ok: true, value: legacy };
794
+ }
795
+ return {
796
+ ok: false,
797
+ reason: "verification contract is unsupported by the Implement runtime",
798
+ };
799
+ }
800
+
801
+ export function verificationSteps(
802
+ verification: VerificationContract,
803
+ ): AtomicVerificationContract[] {
804
+ const normalized = validateVerificationContract(verification);
805
+ if (!normalized.ok) return [];
806
+ return normalized.value.kind === "steps"
807
+ ? structuredClone(normalized.value.steps)
808
+ : [structuredClone(normalized.value)];
809
+ }
810
+
811
+ export function verificationInputPaths(
812
+ verification: VerificationContract,
813
+ ): string[] {
814
+ return [
815
+ ...new Set(
816
+ verificationSteps(verification).flatMap((step) =>
817
+ step.kind === "vitest"
818
+ ? step.testFiles
819
+ : step.kind === "static-check" && step.runner.kind === "node"
820
+ ? [step.runner.script]
821
+ : [],
822
+ ),
823
+ ),
824
+ ];
825
+ }
826
+
827
+ export function cloneVerificationContract(
828
+ verification: VerificationContract,
829
+ ): StructuredVerificationContract {
830
+ const normalized = validateVerificationContract(verification);
831
+ if (!normalized.ok) throw new Error(normalized.reason);
832
+ return structuredClone(normalized.value);
421
833
  }
422
834
 
423
835
  function validateImplementationSnapshot(
@@ -830,11 +1242,6 @@ function validatePhaseBoundary(
830
1242
  ) {
831
1243
  return false;
832
1244
  }
833
- const verificationKeys =
834
- phase === "red"
835
- ? ["id", "argv", "classification", "expectedFailure", "minTests"]
836
- : ["id", "argv", "classification", "minTests"];
837
- if (!hasExactKeys(value.verification, verificationKeys)) return false;
838
1245
  const verification = validateVerificationContract(value.verification);
839
1246
  if (!verification.ok) return false;
840
1247
  const classification = {
@@ -903,13 +1310,26 @@ function validateTaskBoundary(
903
1310
  const roots = value.roots as string[];
904
1311
  if (
905
1312
  phases.some((phase) =>
906
- [...phase.read, ...phase.write].some(
907
- (path) => !isWithinRoots(path, roots),
908
- ),
1313
+ [
1314
+ ...phase.read,
1315
+ ...phase.write,
1316
+ ...verificationInputPaths(phase.verification),
1317
+ ].some((path) => !isWithinRoots(path, roots)),
909
1318
  )
910
1319
  ) {
911
1320
  return false;
912
1321
  }
1322
+ if (
1323
+ phases.some((phase) => {
1324
+ if (phase.verification.kind === undefined) return false;
1325
+ const declared = new Set([...phase.read, ...phase.write]);
1326
+ return verificationInputPaths(phase.verification).some(
1327
+ (input) => !declared.has(input),
1328
+ );
1329
+ })
1330
+ ) {
1331
+ return false;
1332
+ }
913
1333
  const declared = {
914
1334
  read: [...new Set(phases.flatMap((entry) => entry.read))],
915
1335
  write: [...new Set(phases.flatMap((entry) => entry.write))],
@@ -919,6 +1339,22 @@ function validateTaskBoundary(
919
1339
  );
920
1340
  }
921
1341
 
1342
+ function normalizedTaskBoundary(value: TaskBoundary): TaskBoundary {
1343
+ const clone = structuredClone(value);
1344
+ clone.phases.red.verification = cloneVerificationContract(
1345
+ clone.phases.red.verification,
1346
+ );
1347
+ clone.phases.green.verification = cloneVerificationContract(
1348
+ clone.phases.green.verification,
1349
+ );
1350
+ if (clone.phases.refactor) {
1351
+ clone.phases.refactor.verification = cloneVerificationContract(
1352
+ clone.phases.refactor.verification,
1353
+ );
1354
+ }
1355
+ return clone;
1356
+ }
1357
+
922
1358
  function validatePhaseAttemptShape(value: unknown): value is PhaseAttempt {
923
1359
  if (
924
1360
  !hasExactKeys(value, [
@@ -1026,7 +1462,12 @@ function validateImplementRunRequest(
1026
1462
  }
1027
1463
  return {
1028
1464
  ok: true,
1029
- value: structuredClone(request) as ImplementRunRequest,
1465
+ value: {
1466
+ stage: "abel-implement",
1467
+ kind: "open-task",
1468
+ boundary: normalizedTaskBoundary(boundary),
1469
+ attempt: structuredClone(attempt),
1470
+ },
1030
1471
  };
1031
1472
  }
1032
1473
  if (request.kind === "phase-attempt") {
package/src/index.ts CHANGED
@@ -232,6 +232,7 @@ export default function register(pi: ExtensionAPI): void {
232
232
  ? "Run exactly one bounded read-only design-explorer packet. When parallel packets are required, emit every sibling abel_dispatch call together in one assistant response before waiting for any result."
233
233
  : "Private Abel workflow delegation: run bounded read-only evidence or Worker phase requests, apply or discard retained results, apply a parent-only stable AGENTS checkpoint, cancel work, or finish the stage. Inactive unless an eligible Abel stage verified its invocation.",
234
234
  executionMode: "parallel",
235
+ renderShell: "self",
235
236
  parameters: {
236
237
  type: "object",
237
238
  properties: {
@@ -304,16 +305,25 @@ export default function register(pi: ExtensionAPI): void {
304
305
  ...(usage === undefined ? {} : { usage }),
305
306
  };
306
307
  },
307
- renderCall(args: unknown, theme: Theme, _context: unknown) {
308
- return renderActivityCall(args, theme);
308
+ renderCall(args: unknown, theme: Theme, context: unknown) {
309
+ return renderActivityCall(
310
+ args,
311
+ theme,
312
+ context as Parameters<typeof renderActivityCall>[2],
313
+ );
309
314
  },
310
315
  renderResult(
311
316
  result: AgentToolResult<unknown>,
312
317
  options: ToolRenderResultOptions,
313
318
  theme: Theme,
314
- _context: unknown,
319
+ context: unknown,
315
320
  ) {
316
- return renderActivityResult(result, options, theme);
321
+ return renderActivityResult(
322
+ result,
323
+ options,
324
+ theme,
325
+ context as Parameters<typeof renderActivityResult>[3],
326
+ );
317
327
  },
318
328
  } as never);
319
329
  };