@astrosheep/keiyaku 4.6.11 → 4.6.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 (138) hide show
  1. package/build/plugins/claude/skills/keiyaku/SKILL.md +3 -1
  2. package/build/plugins/claude/skills/keiyaku-babysit/SKILL.md +1 -1
  3. package/build/plugins/claude/skills/keiyaku-bind/SKILL.md +3 -2
  4. package/build/plugins/claude/skills/keiyaku-workflow/SKILL.md +9 -8
  5. package/build/plugins/codex/skills/keiyaku/SKILL.md +3 -1
  6. package/build/plugins/codex/skills/keiyaku-babysit/SKILL.md +1 -1
  7. package/build/plugins/codex/skills/keiyaku-bind/SKILL.md +3 -2
  8. package/build/plugins/codex/skills/keiyaku-workflow/SKILL.md +9 -8
  9. package/build/plugins/opencode/skills/keiyaku/SKILL.md +3 -1
  10. package/build/plugins/opencode/skills/keiyaku-babysit/SKILL.md +1 -1
  11. package/build/plugins/opencode/skills/keiyaku-bind/SKILL.md +3 -2
  12. package/build/plugins/opencode/skills/keiyaku-workflow/SKILL.md +9 -8
  13. package/build/skills/keiyaku/SKILL.md +3 -1
  14. package/build/skills/keiyaku-babysit/SKILL.md +1 -1
  15. package/build/skills/keiyaku-bind/SKILL.md +3 -2
  16. package/build/skills/keiyaku-workflow/SKILL.md +9 -8
  17. package/build/src/akuma/akuma-errors.d.ts +5 -0
  18. package/build/src/akuma/akuma-errors.js +9 -0
  19. package/build/src/akuma/akuma-owner.d.ts +14 -19
  20. package/build/src/akuma/akuma-owner.js +56 -54
  21. package/build/src/akuma/akuma-selection-execution.d.ts +5 -4
  22. package/build/src/akuma/akuma-selection-execution.js +59 -17
  23. package/build/src/akuma/akuma.d.ts +1 -2
  24. package/build/src/akuma/allowed.d.ts +2 -3
  25. package/build/src/akuma/allowed.js +1 -3
  26. package/build/src/akuma/body.js +17 -7
  27. package/build/src/akuma/call-initial-tell.d.ts +18 -0
  28. package/build/src/akuma/call-initial-tell.js +18 -0
  29. package/build/src/akuma/call-request.d.ts +20 -4
  30. package/build/src/akuma/heart/facts.d.ts +13 -0
  31. package/build/src/akuma/heart/facts.js +6 -0
  32. package/build/src/akuma/heart/index.d.ts +29 -14
  33. package/build/src/akuma/heart/index.js +75 -29
  34. package/build/src/akuma/heart/rows.d.ts +9 -2
  35. package/build/src/akuma/heart/rows.js +72 -11
  36. package/build/src/akuma/heart/storage.d.ts +2 -8
  37. package/build/src/akuma/heart/storage.js +13 -13
  38. package/build/src/akuma/heart/tells.d.ts +3 -1
  39. package/build/src/akuma/heart/tells.js +18 -2
  40. package/build/src/akuma/provider.d.ts +2 -4
  41. package/build/src/akuma/provider.js +29 -6
  42. package/build/src/akuma/providers/acp/core.js +23 -21
  43. package/build/src/akuma/providers/claude/index.js +0 -8
  44. package/build/src/akuma/providers/codex-app-server/index.js +9 -8
  45. package/build/src/akuma/providers/execution-environment.d.ts +1 -1
  46. package/build/src/akuma/providers/execution-environment.js +1 -0
  47. package/build/src/akuma/providers/opencode-sdk/events.js +111 -81
  48. package/build/src/akuma/providers/opencode-sdk/index.js +179 -150
  49. package/build/src/akuma/providers/opencode-sdk/native-http.js +7 -3
  50. package/build/src/akuma/providers/opencode-sdk/session.d.ts +5 -3
  51. package/build/src/akuma/providers/opencode-sdk/session.js +32 -27
  52. package/build/src/akuma/providers/paseo/index.js +0 -2
  53. package/build/src/akuma/providers/pi/index.js +23 -20
  54. package/build/src/akuma/selection-observation.d.ts +78 -9
  55. package/build/src/akuma/selection-owner-port.d.ts +2 -1
  56. package/build/src/akuma/selection-owner-port.js +6 -1
  57. package/build/src/akuma/selection-request.d.ts +1 -1
  58. package/build/src/akuma/selection-request.js +8 -3
  59. package/build/src/akuma/turn-drive.js +79 -48
  60. package/build/src/akuma-body.js +5 -3
  61. package/build/src/cli/commands/akuma-grammar.js +2 -2
  62. package/build/src/cli/commands/akuma.js +24 -16
  63. package/build/src/cli/commands/contract-grammar.d.ts +3 -7
  64. package/build/src/cli/commands/contract-grammar.js +12 -10
  65. package/build/src/cli/commands/contract-help.d.ts +3 -13
  66. package/build/src/cli/commands/contract-help.js +7 -16
  67. package/build/src/cli/commands/contract.js +19 -35
  68. package/build/src/cli/commands/debt.js +30 -29
  69. package/build/src/cli/parse.js +0 -1
  70. package/build/src/cli/render/akuma-activity.d.ts +36 -9
  71. package/build/src/cli/render/akuma-activity.js +142 -65
  72. package/build/src/cli/render/akuma.d.ts +6 -0
  73. package/build/src/cli/render/akuma.js +67 -24
  74. package/build/src/cli/render/catalog.js +0 -1
  75. package/build/src/cli/render/contract-observation.d.ts +16 -3
  76. package/build/src/cli/render/contract-observation.js +3 -0
  77. package/build/src/cli/render/contract.d.ts +2 -2
  78. package/build/src/cli/render/contract.js +4 -4
  79. package/build/src/cli/render/delivery-preview.d.ts +7 -0
  80. package/build/src/cli/render/{audit.js → delivery-preview.js} +29 -27
  81. package/build/src/cli/render/kanshi-akuma.d.ts +3 -1
  82. package/build/src/cli/render/kanshi-akuma.js +23 -8
  83. package/build/src/cli/render/kanshi.js +4 -1
  84. package/build/src/cli/render/receipt.js +3 -3
  85. package/build/src/cli/render/refusal.js +2 -2
  86. package/build/src/cli/render/terminal.d.ts +0 -1
  87. package/build/src/cli/render/terminal.js +1 -1
  88. package/build/src/cli/square-identity.d.ts +15 -0
  89. package/build/src/cli/square-identity.js +180 -0
  90. package/build/src/contract-worktree.js +1 -1
  91. package/build/src/core/verbs/placement.d.ts +2 -1
  92. package/build/src/core/verbs/placement.js +1 -1
  93. package/build/src/debt/context.d.ts +0 -5
  94. package/build/src/debt/context.js +32 -44
  95. package/build/src/git/process.d.ts +1 -0
  96. package/build/src/git/process.js +18 -1
  97. package/build/src/git/read-observation.js +2 -1
  98. package/build/src/git/scratch.d.ts +5 -1
  99. package/build/src/git/scratch.js +41 -12
  100. package/build/src/git/target-placement.d.ts +22 -4
  101. package/build/src/git/target-placement.js +44 -20
  102. package/build/src/index.d.ts +2 -2
  103. package/build/src/kanshi/read.js +187 -105
  104. package/build/src/kanshi/report.d.ts +5 -0
  105. package/build/src/library/address.d.ts +18 -4
  106. package/build/src/library/address.js +27 -6
  107. package/build/src/library/contract-address.d.ts +6 -0
  108. package/build/src/library/contract-address.js +12 -1
  109. package/build/src/library/contract-execution.d.ts +2 -2
  110. package/build/src/library/contract-execution.js +13 -17
  111. package/build/src/library/contract-operations.d.ts +59 -94
  112. package/build/src/library/contract-operations.js +23 -19
  113. package/build/src/library/contract-outcomes.d.ts +3 -3
  114. package/build/src/library/contract-settings.d.ts +1 -0
  115. package/build/src/library/contract-settings.js +1 -1
  116. package/build/src/library/invocation.d.ts +2 -2
  117. package/build/src/library/invocation.js +1 -1
  118. package/build/src/library/keiyaku.d.ts +2 -2
  119. package/build/src/library/keiyaku.js +2 -2
  120. package/build/src/library/outcome.d.ts +148 -268
  121. package/build/src/library/outcome.js +4 -8
  122. package/build/src/library/refusal.d.ts +2 -2
  123. package/build/src/library/refusal.js +2 -2
  124. package/build/src/plugin/runtime.js +15 -19
  125. package/build/src/protocol/{audit.d.ts → delivery-preview.d.ts} +62 -97
  126. package/build/src/protocol/delivery-preview.js +167 -0
  127. package/build/src/protocol/progress.d.ts +1 -1
  128. package/build/src/runtime/proc/run.js +22 -4
  129. package/build/src/runtime/proc/windows-launch.exe +0 -0
  130. package/build/src/verification/execution.d.ts +1 -1
  131. package/build/src/verification/execution.js +5 -3
  132. package/package.json +5 -2
  133. package/skills/keiyaku/SKILL.md +3 -1
  134. package/skills/keiyaku-babysit/SKILL.md +1 -1
  135. package/skills/keiyaku-bind/SKILL.md +3 -2
  136. package/skills/keiyaku-workflow/SKILL.md +9 -8
  137. package/build/src/cli/render/audit.d.ts +0 -7
  138. package/build/src/protocol/audit.js +0 -203
@@ -15,6 +15,21 @@ export class GitPlumbingError extends Error {
15
15
  }
16
16
  }
17
17
  const GIT_STDERR_BYTES = 16 * 1024;
18
+ export function gitChildEnvironment(environment) {
19
+ const inherited = { ...process.env };
20
+ for (const variable of [
21
+ "GIT_DIR",
22
+ "GIT_WORK_TREE",
23
+ "GIT_INDEX_FILE",
24
+ "GIT_OBJECT_DIRECTORY",
25
+ "GIT_ALTERNATE_OBJECT_DIRECTORIES",
26
+ "GIT_COMMON_DIR",
27
+ "GIT_NAMESPACE",
28
+ ]) {
29
+ delete inherited[variable];
30
+ }
31
+ return { ...inherited, ...environment };
32
+ }
18
33
  function commandError(command, error) {
19
34
  const candidate = error;
20
35
  const stderr = candidate.stderr === undefined ? Buffer.alloc(0) : Buffer.from(candidate.stderr);
@@ -39,7 +54,7 @@ export async function executeGit(repository, args, input, environment) {
39
54
  const owned = spawnCancellableProcess({
40
55
  argv: [repository.gitPath, ...args],
41
56
  cwd: repository.effectiveCwd,
42
- ...(environment === undefined ? {} : { env: { ...process.env, ...environment } }),
57
+ env: gitChildEnvironment(environment),
43
58
  ...(repository.signal === undefined ? {} : { signal: repository.signal }),
44
59
  });
45
60
  const child = owned.child;
@@ -115,6 +130,7 @@ export async function runGitPipe(repository, sourceArgs, sinkArgs) {
115
130
  const owned = spawnCancellableProcess({
116
131
  argv: [repository.gitPath, ...args],
117
132
  cwd: repository.effectiveCwd,
133
+ env: gitChildEnvironment(),
118
134
  ...(repository.signal === undefined ? {} : { signal: repository.signal }),
119
135
  });
120
136
  processes.push(owned);
@@ -186,6 +202,7 @@ export async function consumeGitStdout(repository, args, consume) {
186
202
  const result = await consumeProcessStdout({
187
203
  argv: [repository.gitPath, ...args],
188
204
  cwd: repository.effectiveCwd,
205
+ env: gitChildEnvironment(),
189
206
  ...(repository.signal === undefined ? {} : { signal: repository.signal }),
190
207
  }, consume);
191
208
  const { outcome } = result;
@@ -3,7 +3,7 @@ import { spawnCancellableProcess } from "../runtime/proc/run.js";
3
3
  import { gitObjectId } from "./identity.js";
4
4
  import { parseTreeObject, validPath } from "./tree.js";
5
5
  import { GIT_FORMAT_BYTES, GIT_FORMAT_PATH, GIT_REF, readRef } from "./repository.js";
6
- import { GitPlumbingError } from "./process.js";
6
+ import { gitChildEnvironment, GitPlumbingError } from "./process.js";
7
7
  const gitReadObservationBrand = Symbol("GitReadObservation");
8
8
  const gitDecodeChannelBrand = Symbol("GitDecodeChannel");
9
9
  const BATCH_RETIREMENT_GRACE_MS = 5_000;
@@ -54,6 +54,7 @@ function batchChild(repository) {
54
54
  return spawnCancellableProcess({
55
55
  argv: [repository.gitPath, "cat-file", "--batch"],
56
56
  cwd: repository.effectiveCwd,
57
+ env: gitChildEnvironment(),
57
58
  ...(repository.signal === undefined ? {} : { signal: repository.signal }),
58
59
  });
59
60
  }
@@ -10,9 +10,13 @@ export declare const worktreeLeakSchema: z.ZodObject<{
10
10
  diagnostic: z.ZodString;
11
11
  }, z.core.$strict>;
12
12
  export type WorktreeLeak = z.infer<typeof worktreeLeakSchema>;
13
+ export declare class ScratchMaterializationError extends Error {
14
+ readonly leak: WorktreeLeak;
15
+ constructor(cause: unknown, leak: WorktreeLeak);
16
+ }
13
17
  type CollectableScratchRemoval = Readonly<{
14
18
  path: string;
15
- /** False only when Git removed the path and absence was confirmed; retained removals own a diagnostic. */
19
+ /** False only when scratch custody is confirmed absent; retained removals own a diagnostic. */
16
20
  retained: boolean;
17
21
  diagnostic?: string;
18
22
  }>;
@@ -6,12 +6,21 @@ import { basename, dirname, join } from "node:path";
6
6
  import { acquireSqliteTransactionLock, tryAcquireSqliteTransactionLock, } from "../coordination/sqlite-transaction-lock.js";
7
7
  import { contractLocator, gitRefLocator, gitObjectIdForSnapshot } from "./identity.js";
8
8
  import { executeGit } from "./process.js";
9
+ import { registeredWorktreePaths } from "./repository.js";
9
10
  const SCRATCH_PREFIX = "keiyaku-v4-verify-";
10
11
  const SCRATCH_ROOT = await realpath(tmpdir());
11
12
  const SCRATCH_PATTERN = /^keiyaku-v4-verify-([0-9a-f]{24}|[0-9a-f]{64}-[0-9a-f]{64})$/;
12
13
  /** One bounded removal attempt per scratch; expiry is reported, never retried inside this call. */
13
14
  const SCRATCH_REMOVAL_TIMEOUT_MS = 120_000;
14
15
  export const worktreeLeakSchema = z.object({ path: z.string().optional(), diagnostic: z.string() }).strict();
16
+ export class ScratchMaterializationError extends Error {
17
+ leak;
18
+ constructor(cause, leak) {
19
+ super(`${cause instanceof Error ? cause.message : String(cause)}; scratch cleanup failed at ${leak.path}: ${leak.diagnostic}`, { cause });
20
+ this.name = "ScratchMaterializationError";
21
+ this.leak = { ...leak, diagnostic: this.message };
22
+ }
23
+ }
15
24
  function scratchPath() {
16
25
  return join(SCRATCH_ROOT, `${SCRATCH_PREFIX}${randomBytes(12).toString("hex")}`);
17
26
  }
@@ -58,22 +67,34 @@ async function pathExists(path) {
58
67
  }
59
68
  async function removeScratch(repository, path) {
60
69
  const removal = AbortSignal.timeout(SCRATCH_REMOVAL_TIMEOUT_MS);
70
+ const retirementRepository = { ...repository, signal: removal };
71
+ let present = true;
72
+ let absenceDiagnostic;
73
+ try {
74
+ present = await pathExists(path);
75
+ if (!present && !(await registeredWorktreePaths(retirementRepository)).includes(path)) {
76
+ present = await pathExists(path);
77
+ if (!present)
78
+ return null;
79
+ }
80
+ }
81
+ catch (error) {
82
+ absenceDiagnostic = `scratch absence could not be confirmed: ${error instanceof Error ? error.message : String(error)}`;
83
+ }
84
+ let diagnostic;
61
85
  try {
62
- const present = await pathExists(path);
63
- await executeGit({ ...repository, signal: removal }, ["worktree", "remove", ...(present ? ["--force"] : []), path]);
64
- return (await pathExists(path))
65
- ? { path, diagnostic: `Git reported scratch worktree removal but the path remains: ${path}` }
66
- : null;
86
+ await executeGit(retirementRepository, ["worktree", "remove", ...(present ? ["--force"] : []), path]);
87
+ if (!(await pathExists(path)))
88
+ return null;
89
+ diagnostic = `Git reported scratch worktree removal but the path remains: ${path}`;
67
90
  }
68
91
  catch (error) {
69
92
  const original = error instanceof Error ? error.message : String(error);
70
- return {
71
- path,
72
- diagnostic: removal.aborted
73
- ? `scratch worktree removal timed out after ${SCRATCH_REMOVAL_TIMEOUT_MS}ms: ${original}`
74
- : original,
75
- };
93
+ diagnostic = removal.aborted
94
+ ? `scratch worktree removal timed out after ${SCRATCH_REMOVAL_TIMEOUT_MS}ms: ${original}`
95
+ : original;
76
96
  }
97
+ return { path, diagnostic: absenceDiagnostic === undefined ? diagnostic : `${absenceDiagnostic}; ${diagnostic}` };
77
98
  }
78
99
  /** Remove only abandoned Verification scratch worktrees whose ownership locks are held. */
79
100
  export async function removeCollectableScratchWorktrees(repository, paths, terminalContract) {
@@ -158,7 +179,15 @@ export async function materializeScratchCandidate(repository, candidate, contrac
158
179
  await executeGit(repository, ["worktree", "add", "--detach", cwd, gitObjectIdForSnapshot(candidate)]);
159
180
  }
160
181
  catch (error) {
161
- ownership.close();
182
+ let leak;
183
+ try {
184
+ leak = await removeScratch(repository, cwd);
185
+ }
186
+ finally {
187
+ ownership.close();
188
+ }
189
+ if (leak !== null)
190
+ throw new ScratchMaterializationError(error, leak);
162
191
  await removeOwnershipLock(lockPath);
163
192
  throw error;
164
193
  }
@@ -72,19 +72,37 @@ type TargetPlacementObservationInput = Readonly<{
72
72
  predecessor: SnapshotId;
73
73
  candidate: SnapshotId;
74
74
  }>;
75
+ declare const targetCheckoutObservationSchema: z.ZodUnion<readonly [z.ZodObject<{
76
+ kind: z.ZodLiteral<"followable">;
77
+ path: z.ZodString;
78
+ }, z.core.$strict>, z.ZodObject<{
79
+ kind: z.ZodLiteral<"not-followable">;
80
+ path: z.ZodString;
81
+ diagnostic: z.ZodString;
82
+ }, z.core.$strict>]>;
83
+ type TargetCheckoutObservation = z.infer<typeof targetCheckoutObservationSchema>;
75
84
  type TargetPlacementObservation = Readonly<{
76
85
  kind: "ready";
77
86
  arms: readonly FollowArm[];
87
+ checkouts: readonly TargetCheckoutObservation[];
78
88
  }> | Readonly<{
79
89
  kind: "refused";
80
90
  refusal: TargetPlacementRefusal;
81
91
  }>;
82
92
  /** Observe whether registered target checkouts can follow a predecessor-to-candidate movement. */
83
93
  export declare function observeTargetPlacement(repository: GitRepository, input: TargetPlacementObservationInput, changes?: TargetPlacementChanges): Promise<TargetPlacementObservation>;
84
- export declare const auditTargetAnswerSchema: z.ZodUnion<readonly [z.ZodObject<{
94
+ export declare const previewTargetAnswerSchema: z.ZodUnion<readonly [z.ZodObject<{
85
95
  kind: z.ZodLiteral<"placeable">;
86
96
  ref: z.ZodString;
87
97
  head: z.ZodPipe<z.ZodString, z.ZodTransform<SnapshotId, string>>;
98
+ checkouts: z.ZodReadonly<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
99
+ kind: z.ZodLiteral<"followable">;
100
+ path: z.ZodString;
101
+ }, z.core.$strict>, z.ZodObject<{
102
+ kind: z.ZodLiteral<"not-followable">;
103
+ path: z.ZodString;
104
+ diagnostic: z.ZodString;
105
+ }, z.core.$strict>]>>>;
88
106
  }, z.core.$strict>, z.ZodObject<{
89
107
  kind: z.ZodLiteral<"moved">;
90
108
  ref: z.ZodString;
@@ -104,9 +122,9 @@ export declare const auditTargetAnswerSchema: z.ZodUnion<readonly [z.ZodObject<{
104
122
  kind: z.ZodLiteral<"failed">;
105
123
  diagnostic: z.ZodString;
106
124
  }, z.core.$strict>]>;
107
- type AuditTargetAnswer = z.infer<typeof auditTargetAnswerSchema>;
108
- /** Adjudicate the complete post-Verification audit target answer without placing. */
109
- export declare function adjudicateAuditTarget(repository: GitRepository, input: TargetPlacementObservationInput): Promise<AuditTargetAnswer>;
125
+ type PreviewTargetAnswer = z.infer<typeof previewTargetAnswerSchema>;
126
+ /** Adjudicate prospective target followability without placing or running Verification. */
127
+ export declare function adjudicatePreviewTarget(repository: GitRepository, input: TargetPlacementObservationInput): Promise<PreviewTargetAnswer>;
110
128
  export declare function prepareTargetPlacement(repository: GitRepository, state: ContractState, target: RefOperation, changes?: TargetPlacementChanges): Promise<TargetPlacementPreparation>;
111
129
  export declare function followTargetPlacement(repository: GitRepository, prepared: PreparedTargetPlacement, onPhysical?: (report: TargetPlacementPhysicalResult) => void): Promise<TargetPlacementPhysicalResult>;
112
130
  /** Judge the target-checkout shape without mutating refs, worktrees, or indexes. */
@@ -183,9 +183,8 @@ async function matchesTreeOnPaths(repository, path, command, trees, paths) {
183
183
  return (await gitPaths(repository, path, args)).length === 0;
184
184
  }
185
185
  /**
186
- * A checkout that git cannot carry is judged by the physical follow, which records its own lag.
187
- * The one collision read-tree cannot report is a candidate write over an ignored worktree entry:
188
- * git carries that by silently destroying the entry, so it is refused here instead.
186
+ * Retain the single dry-run's followability observation separately from ref-placement legality.
187
+ * Only a candidate write that silently destroys an ignored entry refuses placement here.
189
188
  */
190
189
  async function ordinaryPrecheck(repository, contractId, target, path, changes) {
191
190
  const predecessor = gitObjectIdForSnapshot(target.expectedOid);
@@ -197,10 +196,11 @@ async function ordinaryPrecheck(repository, contractId, target, path, changes) {
197
196
  catch (error) {
198
197
  if (!(error instanceof GitPlumbingError) || repository.signal?.aborted === true)
199
198
  throw error;
200
- return null;
199
+ return { kind: "not-followable", diagnostic: error.message };
201
200
  }
202
201
  const scopes = await destructionScopes(path, changes.writes);
203
- return await untrackedRefusalWithinScopes(observation, scopes);
202
+ const refusal = await untrackedRefusalWithinScopes(observation, scopes);
203
+ return refusal === null ? { kind: "followable" } : { kind: "refused", refusal };
204
204
  }
205
205
  export async function acquireTargetPlacementFence(repository, target) {
206
206
  const locator = gitRefLocator(target);
@@ -211,6 +211,10 @@ export async function acquireTargetPlacementFence(repository, target) {
211
211
  ...(repository.signal === undefined ? {} : { signal: repository.signal }),
212
212
  });
213
213
  }
214
+ const targetCheckoutObservationSchema = z.union([
215
+ z.object({ kind: z.literal("followable"), path: z.string().min(1) }).strict(),
216
+ z.object({ kind: z.literal("not-followable"), path: z.string().min(1), diagnostic: z.string().min(1) }).strict(),
217
+ ]);
214
218
  /** Observe whether registered target checkouts can follow a predecessor-to-candidate movement. */
215
219
  export async function observeTargetPlacement(repository, input, changes) {
216
220
  const target = {
@@ -225,20 +229,23 @@ export async function observeTargetPlacement(repository, input, changes) {
225
229
  .filter((worktree) => worktree.branch === target.target)
226
230
  .sort((left, right) => left.path.localeCompare(right.path));
227
231
  const arms = [];
232
+ const checkouts = [];
228
233
  for (const worktree of worktrees) {
229
- const refusal = await ordinaryPrecheck(repository, input.contractId, target, worktree.path, changes);
230
- if (refusal !== null)
231
- return { kind: "refused", refusal };
234
+ const precheck = await ordinaryPrecheck(repository, input.contractId, target, worktree.path, changes);
235
+ if (precheck.kind === "refused")
236
+ return precheck;
237
+ checkouts.push({ ...precheck, path: worktree.path });
232
238
  arms.push({ kind: "ordinary", path: worktree.path });
233
239
  }
234
- return { kind: "ready", arms };
240
+ return { kind: "ready", arms, checkouts };
235
241
  }
236
- export const auditTargetAnswerSchema = z.union([
242
+ export const previewTargetAnswerSchema = z.union([
237
243
  z
238
244
  .object({
239
245
  kind: z.literal("placeable"),
240
246
  ref: z.string().refine((value) => value.trim() !== ""),
241
247
  head: snapshotIdSchema,
248
+ checkouts: z.array(targetCheckoutObservationSchema).readonly(),
242
249
  })
243
250
  .strict(),
244
251
  z
@@ -252,8 +259,8 @@ export const auditTargetAnswerSchema = z.union([
252
259
  z.object({ kind: z.literal("refused"), refusal: checkoutNotFollowableRefusalSchema }).strict(),
253
260
  z.object({ kind: z.literal("failed"), diagnostic: z.string().refine((value) => value.trim() !== "") }).strict(),
254
261
  ]);
255
- /** Adjudicate the complete post-Verification audit target answer without placing. */
256
- export async function adjudicateAuditTarget(repository, input) {
262
+ /** Adjudicate prospective target followability without placing or running Verification. */
263
+ export async function adjudicatePreviewTarget(repository, input) {
257
264
  const ref = input.coordinates.target;
258
265
  const expected = input.predecessor;
259
266
  try {
@@ -266,11 +273,12 @@ export async function adjudicateAuditTarget(repository, input) {
266
273
  return { kind: "moved", ref, expected, observed };
267
274
  return follow.kind === "refused"
268
275
  ? { kind: "refused", refusal: follow.refusal }
269
- : { kind: "placeable", ref, head: expected };
276
+ : { kind: "placeable", ref, head: expected, checkouts: follow.checkouts };
270
277
  }
271
278
  catch (error) {
272
279
  if (!(error instanceof GitPlumbingError))
273
280
  throw error;
281
+ repository.signal?.throwIfAborted();
274
282
  return { kind: "failed", diagnostic: error.message };
275
283
  }
276
284
  }
@@ -345,9 +353,9 @@ export async function observeTargetCheckoutShape(repository, input) {
345
353
  async function recoverCheckout(input) {
346
354
  const classified = await classifyCheckout(input);
347
355
  if (classified.kind === "complete")
348
- return "complete";
356
+ return { kind: "complete" };
349
357
  if (classified.kind === "retained")
350
- return "retained";
358
+ return { kind: "retained", diagnostic: "target checkout entries are neither predecessor nor candidate" };
351
359
  const { repository, path, predecessor, candidate } = input;
352
360
  if (classified.action === "index-merge") {
353
361
  await executeGit(repository, [
@@ -359,8 +367,15 @@ async function recoverCheckout(input) {
359
367
  gitObjectIdForSnapshot(predecessor),
360
368
  gitObjectIdForSnapshot(candidate),
361
369
  ]);
362
- return "recovered";
370
+ return { kind: "recovered" };
363
371
  }
372
+ const scopes = await destructionScopes(path, input.changes.writes);
373
+ const refusal = await untrackedRefusalWithinScopes(input, scopes);
374
+ if (refusal !== null)
375
+ return {
376
+ kind: "retained",
377
+ diagnostic: `target checkout would overwrite ignored local entries: ${refusal.paths.join(", ")}`,
378
+ };
364
379
  await executeGit(repository, [
365
380
  "-C",
366
381
  path,
@@ -370,7 +385,7 @@ async function recoverCheckout(input) {
370
385
  gitObjectIdForSnapshot(predecessor),
371
386
  gitObjectIdForSnapshot(candidate),
372
387
  ]);
373
- return "recovered";
388
+ return { kind: "recovered" };
374
389
  }
375
390
  export async function recoverTargetPlacement(repository, state, onPhysical) {
376
391
  const target = state.coordinates.target;
@@ -380,6 +395,12 @@ export async function recoverTargetPlacement(repository, state, onPhysical) {
380
395
  const integration = state.currentIntegration;
381
396
  if (integration === null || (await readRef(repository, target)) !== integration.snapshot)
382
397
  return { effects: [], lag: [] };
398
+ const movement = {
399
+ target,
400
+ expectedOid: integration.predecessor,
401
+ newOid: integration.snapshot,
402
+ };
403
+ const changes = await prepareTargetPlacementChanges(repository, movement);
383
404
  const candidateTree = await commitTree(repository, integration.snapshot);
384
405
  const predecessorTree = await commitTree(repository, integration.predecessor);
385
406
  const worktrees = (await registeredWorktrees(repository))
@@ -392,18 +413,21 @@ export async function recoverTargetPlacement(repository, state, onPhysical) {
392
413
  try {
393
414
  const recovery = await recoverCheckout({
394
415
  repository,
416
+ contractId: state.id,
417
+ target: movement,
418
+ changes,
395
419
  path: worktree.path,
396
420
  predecessor: integration.predecessor,
397
421
  candidate: integration.snapshot,
398
422
  predecessorTree,
399
423
  candidateTree,
400
424
  });
401
- if (recovery === "retained") {
402
- lag.push(recoveryLag(worktree.path, target, "target checkout entries are neither predecessor nor candidate"));
425
+ if (recovery.kind === "retained") {
426
+ lag.push(recoveryLag(worktree.path, target, recovery.diagnostic));
403
427
  onPhysical?.({ effects: [], lag: lag.slice(beforeLag) });
404
428
  continue;
405
429
  }
406
- if (recovery === "recovered") {
430
+ if (recovery.kind === "recovered") {
407
431
  effects.push({ kind: "target-checkout", path: worktree.path, target, action: "recovered" });
408
432
  }
409
433
  }
@@ -54,7 +54,7 @@ export { AkumaAddressError, AkumaWorldScopeError, Akumas } from "./library/akuma
54
54
  export type { AkumaAddressInput, AkumaAskInput, AkumaHistoryInput, AkumaHistoryResult, AkumaKillInput, AkumaKillResult, AkumaList, AkumaListInput, AkumaObservation, AkumaObservationStage, AkumaTellInput, AkumaWaitInput, AkumaWaitResult, AkumaWorldScopeRefusal, CallInput, CallResult, CallWaitHead, CreatedDebtObservation, DispatchAssociation, DispatchStage, ForkInput, ForkResult, TellResult, TellWake, } from "./library/akumas.js";
55
55
  export type { ContinuationReport } from "./library/continuation.js";
56
56
  export type { KeiyakuLibrary, ReconcileInput } from "./library/contract-composition.js";
57
- export type { AbandonOutcome, AmendOutcome, ArcOutcome, AuditOutcome, BindOutcome, BindResult, DeliverOutcome, ReviewOutcome, } from "./library/contract-outcomes.js";
57
+ export type { AbandonOutcome, AmendOutcome, ArcOutcome, DeliveryPreviewInput, DeliveryPreviewOutcome, BindOutcome, BindResult, DeliverOutcome, ReviewOutcome, } from "./library/contract-outcomes.js";
58
58
  export type { AbandonInput, AmendInput, ArcInput, BindInput, ContractHistory, ContractHistoryEvent, ContractList, ContractListInput, ContractObservationInput, ContractResolveInput, ContractResolution, ContractSelectorRefusal, DeliverInput, KeiyakuSelectInput, LocalContractComposition, ReviewInput, } from "./library/contract-types.js";
59
59
  export { nukeKeiyaku as nuke } from "./library/nuke.js";
60
60
  export type { NukeInput, NukeResult } from "./library/nuke.js";
@@ -64,7 +64,7 @@ export type { KeiyakuRefusal, KeiyakuRetryReason, NukeConfirmationRefusal, NukeC
64
64
  export type { RegionOverlap } from "./library/region.js";
65
65
  export type { RepoAtInput } from "./library/repo.js";
66
66
  export type { KeiyakuPlugin, PluginAkumaCaller, PluginAkumaOrigin, PluginBodyEnd, PluginContext, PluginHooks, PluginInstance, PluginManifest, PluginOutcome, PluginSignal, PluginSignalMap, } from "./plugin/public.js";
67
- export type { AuditReport } from "./protocol/audit.js";
67
+ export type { DeliveryPreviewReport } from "./protocol/delivery-preview.js";
68
68
  export type { IntegrationConflictMaterialized, VerificationReuse } from "./protocol/deliver.js";
69
69
  export type { ExecutionObservation, ExecutionObserver } from "./protocol/execution-observation.js";
70
70
  export type { PlacementStop, VerificationStop } from "./protocol/operations.js";