@fitlab-ai/agent-infra 0.9.6 → 0.9.8

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 (178) hide show
  1. package/dist/bin/internal-cli.js +10 -0
  2. package/dist/lib/agent-clients/adapters/claude-code.js +3 -3
  3. package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +47 -5
  4. package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +162 -0
  5. package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +245 -0
  6. package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +398 -0
  7. package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +23 -6
  8. package/dist/lib/decide.js +68 -14
  9. package/dist/lib/defaults.json +10 -2
  10. package/dist/lib/git/workflow.js +30 -3
  11. package/dist/lib/init.js +1 -1
  12. package/dist/lib/internal/codex-lifecycle.js +69 -1
  13. package/dist/lib/internal/codex-sandbox-controller.js +106 -0
  14. package/dist/lib/internal/release-workflow.js +1 -3
  15. package/dist/lib/internal/task-activity.js +57 -7
  16. package/dist/lib/internal/task-event.js +57 -4
  17. package/dist/lib/internal/task-ledger.js +59 -5
  18. package/dist/lib/internal/task-lifecycle.js +59 -8
  19. package/dist/lib/internal/task-orchestration.js +48 -8
  20. package/dist/lib/internal/task-override.js +131 -0
  21. package/dist/lib/internal/task-review.js +64 -6
  22. package/dist/lib/internal/task-verify.js +65 -3
  23. package/dist/lib/internal/task-warning.js +57 -4
  24. package/dist/lib/platform/context.js +6 -4
  25. package/dist/lib/platform/github-client.js +55 -2
  26. package/dist/lib/platform/pr-summary.js +5 -3
  27. package/dist/lib/process-data/checkpoint.js +319 -0
  28. package/dist/lib/process-data/index.js +128 -60
  29. package/dist/lib/process-data/materialize.js +84 -0
  30. package/dist/lib/process-data/normalize.js +34 -1
  31. package/dist/lib/process-data/reconcile.js +55 -1
  32. package/dist/lib/process-data/sources.js +422 -1
  33. package/dist/lib/process-data/store.js +341 -11
  34. package/dist/lib/runtime/agent-runtime.js +56 -0
  35. package/dist/lib/sandbox/commands/create.js +394 -264
  36. package/dist/lib/sandbox/commands/rm.js +64 -15
  37. package/dist/lib/sandbox/commands/start.js +4 -3
  38. package/dist/lib/sandbox/control/container-identity.js +64 -0
  39. package/dist/lib/sandbox/control/executor.js +23 -9
  40. package/dist/lib/sandbox/control/lifecycle.js +590 -61
  41. package/dist/lib/sandbox/control/protocol.js +7 -0
  42. package/dist/lib/sandbox/control/server.js +202 -26
  43. package/dist/lib/sandbox/control/state.js +51 -25
  44. package/dist/lib/sandbox/control/timing.js +8 -0
  45. package/dist/lib/sandbox/engine.js +14 -7
  46. package/dist/lib/sandbox/mounts.js +7 -0
  47. package/dist/lib/sandbox/recovery.js +135 -50
  48. package/dist/lib/sandbox/workspace-view.js +59 -20
  49. package/dist/lib/server/daemon.js +1 -1
  50. package/dist/lib/server/process-control.js +11 -1
  51. package/dist/lib/server/process-state.js +107 -20
  52. package/dist/lib/task/activity-intent.js +4 -1
  53. package/dist/lib/task/artifact-lifecycle.js +82 -11
  54. package/dist/lib/task/artifact-receipts.js +128 -0
  55. package/dist/lib/task/codex-orchestration.js +81 -6
  56. package/dist/lib/task/commands/validate.js +1 -1
  57. package/dist/lib/task/create.js +10 -2
  58. package/dist/lib/task/decision-intents.js +4 -2
  59. package/dist/lib/task/delegation-receipts.js +120 -17
  60. package/dist/lib/task/events.js +148 -7
  61. package/dist/lib/task/guard-override.js +31 -0
  62. package/dist/lib/task/human-override.js +1240 -0
  63. package/dist/lib/task/ledger-intents.js +6 -3
  64. package/dist/lib/task/ledger.js +13 -1
  65. package/dist/lib/task/lifecycle.js +69 -14
  66. package/dist/lib/task/orchestration.js +293 -18
  67. package/dist/lib/task/review-finalization.js +3 -2
  68. package/dist/lib/task/sections.js +5 -1
  69. package/dist/lib/task/task-execution-lock.js +5 -4
  70. package/dist/lib/task/verification-engine.js +80 -22
  71. package/dist/lib/task/verification.js +13 -1
  72. package/dist/lib/task/workflow-warning-intents.js +4 -2
  73. package/dist/lib/task/write.js +2 -1
  74. package/dist/lifecycle-build-manifest.json +6 -0
  75. package/lib/agent-clients/adapters/claude-code.ts +3 -3
  76. package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +62 -4
  77. package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +227 -0
  78. package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +322 -0
  79. package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +26 -0
  80. package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +480 -0
  81. package/lib/agent-clients/adapters/codex-lifecycle/store.ts +35 -5
  82. package/lib/decide.ts +59 -14
  83. package/lib/defaults.json +10 -2
  84. package/lib/git/workflow.ts +25 -2
  85. package/lib/init.ts +1 -1
  86. package/lib/internal/codex-lifecycle.ts +68 -1
  87. package/lib/internal/codex-sandbox-controller.ts +109 -0
  88. package/lib/internal/release-workflow.ts +1 -3
  89. package/lib/internal/task-activity.ts +46 -6
  90. package/lib/internal/task-event.ts +53 -4
  91. package/lib/internal/task-ledger.ts +48 -4
  92. package/lib/internal/task-lifecycle.ts +56 -12
  93. package/lib/internal/task-orchestration.ts +43 -8
  94. package/lib/internal/task-override.ts +138 -0
  95. package/lib/internal/task-review.ts +51 -6
  96. package/lib/internal/task-verify.ts +52 -3
  97. package/lib/internal/task-warning.ts +44 -3
  98. package/lib/platform/context.ts +8 -5
  99. package/lib/platform/github-client.ts +61 -3
  100. package/lib/platform/pr-summary.ts +10 -3
  101. package/lib/process-data/checkpoint.ts +335 -0
  102. package/lib/process-data/index.ts +112 -60
  103. package/lib/process-data/materialize.ts +83 -0
  104. package/lib/process-data/normalize.ts +29 -1
  105. package/lib/process-data/reconcile.ts +64 -2
  106. package/lib/process-data/sources.ts +449 -2
  107. package/lib/process-data/store.ts +304 -11
  108. package/lib/process-data/types.ts +124 -2
  109. package/lib/runtime/agent-runtime.ts +76 -0
  110. package/lib/sandbox/commands/create.ts +139 -6
  111. package/lib/sandbox/commands/rm.ts +64 -14
  112. package/lib/sandbox/commands/start.ts +4 -3
  113. package/lib/sandbox/config.ts +2 -1
  114. package/lib/sandbox/control/container-identity.ts +93 -0
  115. package/lib/sandbox/control/executor.ts +24 -12
  116. package/lib/sandbox/control/lifecycle.ts +685 -67
  117. package/lib/sandbox/control/protocol.ts +35 -6
  118. package/lib/sandbox/control/server.ts +184 -24
  119. package/lib/sandbox/control/state.ts +67 -33
  120. package/lib/sandbox/control/timing.ts +12 -0
  121. package/lib/sandbox/engine.ts +20 -9
  122. package/lib/sandbox/mounts.ts +8 -0
  123. package/lib/sandbox/recovery.ts +159 -49
  124. package/lib/sandbox/workspace-view.ts +73 -22
  125. package/lib/server/daemon.ts +1 -1
  126. package/lib/server/process-control.ts +13 -3
  127. package/lib/server/process-state.ts +129 -27
  128. package/lib/task/activity-intent.ts +4 -2
  129. package/lib/task/artifact-lifecycle.ts +73 -10
  130. package/lib/task/artifact-receipts.ts +161 -0
  131. package/lib/task/codex-orchestration.ts +91 -5
  132. package/lib/task/commands/validate.ts +1 -1
  133. package/lib/task/create.ts +11 -2
  134. package/lib/task/decision-intents.ts +4 -2
  135. package/lib/task/delegation-receipts.ts +205 -25
  136. package/lib/task/events.ts +132 -6
  137. package/lib/task/guard-override.ts +50 -0
  138. package/lib/task/human-override.ts +1503 -0
  139. package/lib/task/ledger-intents.ts +6 -3
  140. package/lib/task/ledger.ts +16 -1
  141. package/lib/task/lifecycle.ts +71 -14
  142. package/lib/task/orchestration.ts +443 -22
  143. package/lib/task/review-finalization.ts +6 -2
  144. package/lib/task/sections.ts +6 -2
  145. package/lib/task/task-execution-lock.ts +11 -9
  146. package/lib/task/verification-engine.ts +93 -32
  147. package/lib/task/verification.ts +15 -1
  148. package/lib/task/workflow-warning-intents.ts +4 -2
  149. package/lib/task/write.ts +4 -1
  150. package/package.json +1 -1
  151. package/templates/.agents/README.en.md +7 -0
  152. package/templates/.agents/README.zh-CN.md +5 -0
  153. package/templates/.agents/hooks/lifecycle-delegation.js +33 -4
  154. package/templates/.agents/rules/lifecycle-orchestration.en.md +10 -3
  155. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +10 -3
  156. package/templates/.agents/rules/pr-checks-commands.github.en.md +1 -1
  157. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +1 -1
  158. package/templates/.agents/rules/review-handshake.en.md +3 -1
  159. package/templates/.agents/rules/review-handshake.zh-CN.md +3 -1
  160. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +3 -1
  161. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +3 -1
  162. package/templates/.agents/skills/complete-task/SKILL.en.md +4 -0
  163. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +4 -0
  164. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +6 -6
  165. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +6 -6
  166. package/templates/.agents/skills/run-manual-validation/config/verify.en.json +14 -3
  167. package/templates/.agents/skills/run-manual-validation/config/verify.zh-CN.json +14 -3
  168. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +67 -0
  169. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +67 -0
  170. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +25 -0
  171. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +25 -0
  172. package/templates/.agents/skills/run-task/SKILL.en.md +9 -7
  173. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +9 -7
  174. package/templates/.agents/skills/run-task/reference/host-validation.en.md +5 -1
  175. package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +5 -1
  176. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +75 -3
  177. package/templates/.agents/workspace/README.en.md +0 -26
  178. package/templates/.agents/workspace/README.zh-CN.md +0 -26
@@ -1,3 +1,5 @@
1
+ import fs from 'node:fs';
2
+
1
3
  import {
2
4
  preflightCodexLifecycleEvidence,
3
5
  resolveCodexSpawnedChild,
@@ -5,9 +7,16 @@ import {
5
7
  resolveCodexThread
6
8
  } from '../agent-clients/adapters/codex-lifecycle/app-server.ts';
7
9
  import { createCodexLifecycleStore } from '../agent-clients/adapters/codex-lifecycle/store.ts';
10
+ import { createCodexCapabilityStore } from '../agent-clients/adapters/codex-lifecycle/capability-store.ts';
11
+ import { computeLifecycleBuildIdentity } from '../agent-clients/adapters/codex-lifecycle/build-identity.ts';
12
+ import type { LifecycleBuildIdentity } from '../agent-clients/adapters/codex-lifecycle/build-identity.ts';
13
+ import { verifyCodexSandboxControllerContext } from '../agent-clients/adapters/codex-lifecycle/sandbox-controller.ts';
8
14
  import type { AgentClientId } from '../agent-clients/types.ts';
15
+ import { resolveTaskRef } from './resolve-ref.ts';
9
16
  import {
10
17
  activateMatchingOrchestrationDelegation,
18
+ hasActivatableOrchestrationDelegation,
19
+ hasSealableOrchestrationDelegation,
11
20
  pauseMatchingOrchestrationDelegation,
12
21
  prepareOrchestrationDelegation,
13
22
  reconcileMatchingOrchestrationDelegation,
@@ -16,12 +25,15 @@ import {
16
25
  import type { OrchestrationOptions, OrchestrationResult } from './orchestration.ts';
17
26
 
18
27
  type LifecycleStore = ReturnType<typeof createCodexLifecycleStore>;
28
+ type CapabilityStore = ReturnType<typeof createCodexCapabilityStore>;
19
29
  type CodexBridgeOptions = Readonly<{
20
30
  repoRoot?: string;
21
31
  store?: LifecycleStore;
22
32
  preflight?: typeof preflightCodexLifecycleEvidence;
23
33
  resolveThread?: typeof resolveCodexThread;
24
34
  resolveTerminal?: typeof resolveCodexTerminal;
35
+ capabilityStore?: CapabilityStore;
36
+ buildIdentity?: LifecycleBuildIdentity;
25
37
  orchestrationOptions?: OrchestrationOptions;
26
38
  }>;
27
39
 
@@ -59,25 +71,68 @@ function requiredStore(options: CodexBridgeOptions): LifecycleStore {
59
71
  return options.store;
60
72
  }
61
73
 
74
+ function controllerContext(taskId: string, repoRoot: string) {
75
+ const contextPath = process.env.AGENT_INFRA_CODEX_CONTROLLER_CONTEXT;
76
+ return contextPath
77
+ ? verifyCodexSandboxControllerContext(contextPath, taskId, { repoRoot })
78
+ : null;
79
+ }
80
+
62
81
  async function prepareCodexOrchestrationDelegation(
63
82
  taskRef: string,
64
83
  input: Readonly<{
65
84
  client: AgentClientId;
66
85
  requestedModel?: string;
67
86
  requestedReasoningEffort?: string;
87
+ capabilityToken?: string;
68
88
  }>,
69
89
  options: CodexBridgeOptions = {}
70
90
  ): Promise<OrchestrationResult> {
71
91
  if (input.client !== 'codex') return prepareOrchestrationDelegation(taskRef, input, coreOptions(options));
72
92
  try {
73
- await (options.preflight ?? preflightCodexLifecycleEvidence)(options.repoRoot ?? process.cwd());
93
+ const repoRoot = options.repoRoot ?? process.cwd();
94
+ const resolved = resolveTaskRef(taskRef, { repoRoot });
95
+ if (!resolved.ok) return bridgeFailure(resolved.code, resolved.message);
96
+ const preflight = await (options.preflight ?? preflightCodexLifecycleEvidence)(repoRoot);
97
+ if (!input.capabilityToken) {
98
+ return bridgeFailure(
99
+ 'ORCHESTRATION_CODEX_CAPABILITY_REQUIRED',
100
+ 'Codex prepare requires a current-session capability token'
101
+ );
102
+ }
103
+ const buildIdentity = options.buildIdentity ?? computeLifecycleBuildIdentity(repoRoot);
104
+ const controller = controllerContext(resolved.taskId, repoRoot);
105
+ const capabilityStore = options.capabilityStore ?? createCodexCapabilityStore();
106
+ const consumed = capabilityStore.consume(input.capabilityToken, {
107
+ taskId: resolved.taskId,
108
+ hookDefinitionHash: preflight.hookDefinitionHash,
109
+ buildIdentity,
110
+ ...(controller ? { controller: {
111
+ instanceDigest: controller.controllerInstanceDigest,
112
+ controlGeneration: controller.controlGeneration
113
+ } } : {})
114
+ });
115
+ return prepareOrchestrationDelegation(taskRef, {
116
+ ...input,
117
+ lifecycleProvenance: {
118
+ ...consumed.buildIdentity,
119
+ hookDefinitionHash: preflight.hookDefinitionHash,
120
+ ...preflight.hookProvenance,
121
+ capabilitySessionId: consumed.sessionId!,
122
+ capabilityTurnId: consumed.turnId!,
123
+ capabilityToolUseId: consumed.toolUseId!,
124
+ controllerInstanceDigest: controller?.controllerInstanceDigest ?? null,
125
+ controlGeneration: controller?.controlGeneration ?? null
126
+ }
127
+ }, coreOptions(options));
74
128
  } catch (error) {
75
129
  return bridgeFailure(
76
- 'ORCHESTRATION_CLIENT_PREFLIGHT_FAILED',
130
+ error instanceof Error && error.name.startsWith('CODEX_CAPABILITY_')
131
+ ? error.name
132
+ : 'ORCHESTRATION_CLIENT_PREFLIGHT_FAILED',
77
133
  error instanceof Error ? error.message : String(error)
78
134
  );
79
135
  }
80
- return prepareOrchestrationDelegation(taskRef, input, coreOptions(options));
81
136
  }
82
137
 
83
138
  async function activateCodexOrchestrationDelegation(
@@ -85,6 +140,9 @@ async function activateCodexOrchestrationDelegation(
85
140
  options: CodexBridgeOptions = {}
86
141
  ): Promise<OrchestrationResult> {
87
142
  try {
143
+ if (!hasActivatableOrchestrationDelegation('codex', childThreadId, coreOptions(options))) {
144
+ return bridgeFailure('ORCHESTRATION_DELEGATION_MISSING', 'No matching Codex delegation is active');
145
+ }
88
146
  const store = requiredStore(options);
89
147
  const resolved = await (options.resolveThread ?? resolveCodexThread)(childThreadId);
90
148
  store.apply(resolved.resolution.thread);
@@ -95,6 +153,23 @@ async function activateCodexOrchestrationDelegation(
95
153
  if (record.state.status !== 'start-ready' || !evidence) {
96
154
  return pauseBridge('ORCHESTRATION_CODEX_START_EVIDENCE_INVALID', 'Codex lifecycle start evidence is not ready', options);
97
155
  }
156
+ const repoRoot = options.repoRoot ?? process.cwd();
157
+ const preflight = await (options.preflight ?? preflightCodexLifecycleEvidence)(repoRoot, {
158
+ sessionId: evidence.parentThreadId,
159
+ turnId: evidence.parentTurnId,
160
+ toolUseId: evidence.spawnToolUseId
161
+ });
162
+ const buildIdentity = options.buildIdentity ?? computeLifecycleBuildIdentity(repoRoot);
163
+ const contextPath = process.env.AGENT_INFRA_CODEX_CONTROLLER_CONTEXT;
164
+ const contextTaskId = contextPath
165
+ ? (JSON.parse(fs.readFileSync(contextPath, 'utf8')) as { taskId?: unknown }).taskId
166
+ : null;
167
+ if (contextPath && typeof contextTaskId !== 'string') {
168
+ throw new Error('CODEX_SANDBOX_CONTROLLER_CONTEXT_INVALID');
169
+ }
170
+ const controller = contextPath
171
+ ? verifyCodexSandboxControllerContext(contextPath, contextTaskId as string, { repoRoot })
172
+ : null;
98
173
  return activateMatchingOrchestrationDelegation('codex', {
99
174
  nativeAgent: evidence.nativeAgent,
100
175
  childId: evidence.childThreadId,
@@ -107,9 +182,17 @@ async function activateCodexOrchestrationDelegation(
107
182
  ? { reasoningEffortFallbackReason: evidence.reasoningEffortFallbackReason }
108
183
  : {}),
109
184
  hostEvidence: {
110
- kind: 'codex-lifecycle-v1',
185
+ kind: 'codex-lifecycle-v2',
111
186
  hookDefinitionHash: evidence.hookDefinitionHash,
112
- startRevision: record.revision
187
+ startRevision: record.revision,
188
+ ...buildIdentity,
189
+ ...preflight.hookProvenance,
190
+ capabilitySessionId: evidence.parentThreadId,
191
+ capabilityTurnId: evidence.parentTurnId,
192
+ spawnToolUseId: evidence.spawnToolUseId,
193
+ spawnObservedAt: record.spawnObservedAt ?? undefined,
194
+ controllerInstanceDigest: controller?.controllerInstanceDigest ?? null,
195
+ controlGeneration: controller?.controlGeneration ?? null
113
196
  }
114
197
  }, coreOptions(options));
115
198
  } catch (error) {
@@ -149,6 +232,9 @@ async function sealCodexOrchestrationDelegation(
149
232
  options: CodexBridgeOptions = {}
150
233
  ): Promise<OrchestrationResult> {
151
234
  try {
235
+ if (!hasSealableOrchestrationDelegation('codex', childThreadId, coreOptions(options))) {
236
+ return bridgeFailure('ORCHESTRATION_DELEGATION_MISSING', 'No matching Codex delegation is active');
237
+ }
152
238
  const store = requiredStore(options);
153
239
  const existing = store.read(childThreadId);
154
240
  if (!existing.consumer) {
@@ -169,7 +169,7 @@ function inplaceValidation(config: ReturnType<typeof loadConfig>, target: Return
169
169
  const nonce = randomUUID();
170
170
  const issuedAt = Date.now();
171
171
  const lease: SandboxControlLease = {
172
- version: 1, generation: manifest.generation, nonce,
172
+ version: 2, generation: manifest.generation, nonce,
173
173
  owner: { pid: process.pid, startTime }, issuedAt,
174
174
  expiresAt: issuedAt + Math.min(options.timeoutMs + RECOVERY_GRACE_MS, MAX_TIMEOUT_MS + RECOVERY_GRACE_MS),
175
175
  taskId: target.workspace.mode === 'task-bound' ? target.workspace.taskId : null,
@@ -231,6 +231,14 @@ function assertRealDirectory(directory: string, code: string): void {
231
231
  if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error(code);
232
232
  }
233
233
 
234
+ function ensureRealDirectory(directory: string, code: string): void {
235
+ if (fs.existsSync(directory)) {
236
+ assertRealDirectory(directory, code);
237
+ return;
238
+ }
239
+ fs.mkdirSync(directory, { mode: 0o700 });
240
+ }
241
+
234
242
  function withCreateLock<T>(repoRoot: string, workspaceRoot: string, operation: () => T): T {
235
243
  const lockRoot = path.join(workspaceRoot, '.task-create.lock');
236
244
  fs.mkdirSync(lockRoot, { recursive: true, mode: 0o700 });
@@ -289,8 +297,9 @@ function createLocalTask(value: unknown, options: LocalTaskCreateOptions): Local
289
297
  const repoRoot = fs.realpathSync.native(options.repoRoot);
290
298
  const workspaceRoot = path.join(repoRoot, '.agents', 'workspace');
291
299
  const activeRoot = path.join(workspaceRoot, 'active');
292
- assertRealDirectory(workspaceRoot, 'TASK_CREATE_WORKSPACE_INVALID');
293
- assertRealDirectory(activeRoot, 'TASK_CREATE_WORKSPACE_INVALID');
300
+ ensureRealDirectory(path.join(repoRoot, '.agents'), 'TASK_CREATE_WORKSPACE_INVALID');
301
+ ensureRealDirectory(workspaceRoot, 'TASK_CREATE_WORKSPACE_INVALID');
302
+ ensureRealDirectory(activeRoot, 'TASK_CREATE_WORKSPACE_INVALID');
294
303
  const project = readProject(repoRoot);
295
304
  const canonical = canonicalTaskCreateCandidate(candidate);
296
305
  const candidateDigest = sha256(canonical);
@@ -16,6 +16,7 @@ import { resolveTaskContext } from './resolve-ref.ts';
16
16
  import { extractSection, extractSubSection, findSectionHeading } from './sections.ts';
17
17
  import { captureTaskWriteMetadata, writeTask } from './write.ts';
18
18
  import type { TaskMutation, TaskOperationSummary, TaskWriteOptions } from './write.ts';
19
+ import { allowsManualOverride } from './guard-override.ts';
19
20
 
20
21
  type HumanDecisionRequest = {
21
22
  taskRef?: string;
@@ -85,7 +86,8 @@ function applyHumanDecision(request: HumanDecisionRequest, options: TaskWriteOpt
85
86
  if (!request.selector || !request.decision.trim()) return failed('DECISION_PAYLOAD_INVALID', 'selector and decision are required');
86
87
  const resolved = resolveTaskContext(request.taskRef, { repoRoot: options.repoRoot });
87
88
  if (!resolved.ok) return failed(resolved.code, resolved.message, resolved.taskId);
88
- if (resolved.state !== 'active') return failed('TASK_STATE_MISMATCH', `task ${resolved.taskId} is ${resolved.state}, expected active`, resolved.taskId);
89
+ const stateOverride = allowsManualOverride(options.manualOverride, 'decision-intent', 'TASK_STATE_MISMATCH');
90
+ if (resolved.state !== 'active' && !stateOverride) return failed('TASK_STATE_MISMATCH', `task ${resolved.taskId} is ${resolved.state}, expected active`, resolved.taskId);
89
91
  let content: string;
90
92
  let rows: LedgerRow[];
91
93
  try { content = fs.readFileSync(resolved.taskMdPath, 'utf8'); rows = parseLedger(content); }
@@ -170,7 +172,7 @@ function applyHumanDecision(request: HumanDecisionRequest, options: TaskWriteOpt
170
172
  kind: 'section', aliases: ACTIVITY_ALIASES, heading: activity.heading,
171
173
  body: appendActivityEntry(activity, { time: metadata.timestamp, step: 'Human Decision', agent: 'human', note: `${row.id} decided → ${recordId}` })
172
174
  });
173
- const writeResult = writeTask({ taskRef: resolved.taskId, expectedState: 'active', mutations, dryRun: request.dryRun }, {
175
+ const writeResult = writeTask({ taskRef: resolved.taskId, expectedState: stateOverride ? resolved.state : 'active', mutations, dryRun: request.dryRun }, {
174
176
  ...options,
175
177
  taskLocation: { repoRoot: resolved.repoRoot, taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, state: resolved.state },
176
178
  metadataProvider: () => metadata
@@ -7,12 +7,41 @@ type DelegationRole = 'executor' | 'reviewer';
7
7
  type DelegationStage = 'analysis' | 'review-analysis' | 'plan' | 'review-plan' | 'code' | 'review-code' | 'commit';
8
8
  type DelegationStatus = 'prepared' | 'activated' | 'stage-completed' | 'sealed' | 'consumed' | 'aborted' | 'expired';
9
9
  type DelegationHostEvidence = Readonly<{
10
- kind: 'codex-lifecycle-v1';
10
+ kind: 'codex-lifecycle-v1' | 'codex-lifecycle-v2';
11
11
  hookDefinitionHash: string;
12
12
  startRevision: number;
13
13
  stopRevision: number | null;
14
14
  consumer: string | null;
15
15
  consumedAt: string | null;
16
+ protocolVersion?: number;
17
+ packageVersion?: string;
18
+ internalExecutableBuildHash?: string;
19
+ lifecycleContractHash?: string;
20
+ hookSource?: 'project' | 'managed' | 'isolated-user';
21
+ hookSourcePathDigest?: string;
22
+ hookSourceHash?: string;
23
+ capabilitySessionId?: string;
24
+ capabilityTurnId?: string;
25
+ capabilityToolUseId?: string;
26
+ spawnToolUseId?: string;
27
+ spawnObservedAt?: string;
28
+ controllerInstanceDigest?: string | null;
29
+ controlGeneration?: string | null;
30
+ }>;
31
+ type DelegationLifecycleProvenance = Readonly<{
32
+ protocolVersion: number;
33
+ packageVersion: string;
34
+ internalExecutableBuildHash: string;
35
+ lifecycleContractHash: string;
36
+ hookDefinitionHash: string;
37
+ hookSource: 'project' | 'managed' | 'isolated-user';
38
+ hookSourcePathDigest: string;
39
+ hookSourceHash: string;
40
+ capabilitySessionId: string;
41
+ capabilityTurnId: string;
42
+ capabilityToolUseId: string;
43
+ controllerInstanceDigest: string | null;
44
+ controlGeneration: string | null;
16
45
  }>;
17
46
 
18
47
  type DelegationReceipt = Readonly<{
@@ -36,11 +65,19 @@ type DelegationReceipt = Readonly<{
36
65
  agent: string | null;
37
66
  status: DelegationStatus;
38
67
  workspaceSnapshotScope?: 'task';
68
+ lifecycleProvenance?: DelegationLifecycleProvenance | null;
39
69
  hostEvidence?: DelegationHostEvidence | null;
40
70
  beforeFingerprint: string;
41
71
  afterFingerprint: string | null;
42
72
  changedPaths: readonly string[];
43
73
  createdAt: string;
74
+ preparedMonotonicMs: number;
75
+ spawnDispatchMonotonicMs: number | null;
76
+ activationDeadlineMonotonicMs: number | null;
77
+ spawnDispatchedAt: string | null;
78
+ activationDeadlineAt: string | null;
79
+ startEvidenceMonotonicMs: number | null;
80
+ activatedMonotonicMs: number | null;
44
81
  activatedAt: string | null;
45
82
  sealedAt: string | null;
46
83
  consumedAt: string | null;
@@ -63,10 +100,16 @@ function fail(code: string, message: string): ReceiptFailure {
63
100
  return { ok: false, code, message };
64
101
  }
65
102
 
103
+ // 空白串折叠为 null,保持"缺失即 null"的单一表示(Start/Stop 两处共用,避免任一入口把 " " 当成已观察到的值入账)
104
+ function foldBlankToNull(value: string | undefined): string | null {
105
+ return value?.trim() ? value : null;
106
+ }
107
+
66
108
  function prepareDelegation(
67
- input: Omit<DelegationReceipt, 'id' | 'requestedModel' | 'requestedReasoningEffort' | 'actualModel' | 'actualReasoningEffort' | 'modelFallbackReason' | 'reasoningEffortFallbackReason' | 'parentId' | 'childId' | 'spawnMode' | 'agent' | 'status' | 'hostEvidence' | 'afterFingerprint' | 'changedPaths' | 'createdAt' | 'activatedAt' | 'sealedAt' | 'consumedAt'> & Readonly<{ requestedModel: string; requestedReasoningEffort: string }>,
68
- options: { id?: () => string; now?: () => string } = {}
109
+ input: Omit<DelegationReceipt, 'id' | 'requestedModel' | 'requestedReasoningEffort' | 'actualModel' | 'actualReasoningEffort' | 'modelFallbackReason' | 'reasoningEffortFallbackReason' | 'parentId' | 'childId' | 'spawnMode' | 'agent' | 'status' | 'hostEvidence' | 'afterFingerprint' | 'changedPaths' | 'createdAt' | 'preparedMonotonicMs' | 'spawnDispatchMonotonicMs' | 'activationDeadlineMonotonicMs' | 'spawnDispatchedAt' | 'activationDeadlineAt' | 'startEvidenceMonotonicMs' | 'activatedMonotonicMs' | 'activatedAt' | 'sealedAt' | 'consumedAt'> & Readonly<{ requestedModel: string; requestedReasoningEffort: string }>,
110
+ options: { id?: () => string; now?: () => string; monotonicNow?: () => number } = {}
69
111
  ): DelegationReceipt {
112
+ const monotonic = (options.monotonicNow ?? (() => Number(process.hrtime.bigint() / 1_000_000n)))();
70
113
  return Object.freeze({
71
114
  ...input,
72
115
  id: (options.id ?? randomUUID)(),
@@ -83,60 +126,136 @@ function prepareDelegation(
83
126
  afterFingerprint: null,
84
127
  changedPaths: Object.freeze([]),
85
128
  createdAt: (options.now ?? (() => new Date().toISOString()))(),
129
+ preparedMonotonicMs: monotonic,
130
+ spawnDispatchMonotonicMs: null,
131
+ activationDeadlineMonotonicMs: null,
132
+ spawnDispatchedAt: null,
133
+ activationDeadlineAt: null,
134
+ startEvidenceMonotonicMs: null,
135
+ activatedMonotonicMs: null,
86
136
  activatedAt: null,
87
137
  sealedAt: null,
88
138
  consumedAt: null
89
139
  });
90
140
  }
91
141
 
142
+ function dispatchDelegation(
143
+ receipt: DelegationReceipt,
144
+ options: { now?: () => string; monotonicNow?: () => number; activationWindowMs?: number } = {}
145
+ ): ReceiptResult {
146
+ if (receipt.status !== 'prepared') {
147
+ return fail('DELEGATION_STATE_INVALID', `delegation ${receipt.id} is ${receipt.status}, expected prepared`);
148
+ }
149
+ if (receipt.spawnDispatchMonotonicMs != null || receipt.spawnDispatchedAt != null) {
150
+ return fail('DELEGATION_DISPATCH_REPLAY', `delegation ${receipt.id} was already dispatched`);
151
+ }
152
+ const monotonic = (options.monotonicNow ?? (() => Number(process.hrtime.bigint() / 1_000_000n)))();
153
+ const dispatchedAt = (options.now ?? (() => new Date().toISOString()))();
154
+ const window = options.activationWindowMs ?? 15_000;
155
+ return { ok: true, receipt: Object.freeze({
156
+ ...receipt,
157
+ spawnDispatchMonotonicMs: monotonic,
158
+ activationDeadlineMonotonicMs: monotonic + window,
159
+ spawnDispatchedAt: dispatchedAt,
160
+ activationDeadlineAt: new Date(Date.parse(dispatchedAt) + window).toISOString()
161
+ }) };
162
+ }
163
+
92
164
  function activateDelegation(
93
165
  receipt: DelegationReceipt,
94
166
  event: Readonly<{
95
167
  nativeAgent: string;
96
168
  childId: string;
97
169
  parentId: string;
98
- spawnMode: string;
170
+ spawnMode?: string;
99
171
  actualModel?: string;
100
172
  actualReasoningEffort?: string;
101
173
  modelFallbackReason?: string;
102
174
  reasoningEffortFallbackReason?: string;
103
175
  hostEvidence?: Readonly<{
104
- kind: 'codex-lifecycle-v1';
176
+ kind: 'codex-lifecycle-v1' | 'codex-lifecycle-v2';
105
177
  hookDefinitionHash: string;
106
178
  startRevision: number;
179
+ protocolVersion?: number;
180
+ packageVersion?: string;
181
+ internalExecutableBuildHash?: string;
182
+ lifecycleContractHash?: string;
183
+ hookSource?: 'project' | 'managed' | 'isolated-user';
184
+ hookSourcePathDigest?: string;
185
+ hookSourceHash?: string;
186
+ capabilitySessionId?: string;
187
+ capabilityTurnId?: string;
188
+ capabilityToolUseId?: string;
189
+ spawnToolUseId?: string;
190
+ spawnObservedAt?: string;
191
+ controllerInstanceDigest?: string | null;
192
+ controlGeneration?: string | null;
107
193
  }>;
108
194
  }>,
109
- options: { now?: () => string } = {}
195
+ options: { now?: () => string; monotonicNow?: () => number } = {}
110
196
  ): ReceiptResult {
111
197
  const managedRole = managedDelegationRole(event.nativeAgent);
112
198
  if (!managedRole) return fail('DELEGATION_IGNORED', `subagent '${event.nativeAgent}' is not lifecycle-managed`);
113
199
  if (receipt.status !== 'prepared') return fail('DELEGATION_STATE_INVALID', `delegation ${receipt.id} is ${receipt.status}, expected prepared`);
200
+ if (
201
+ receipt.spawnDispatchMonotonicMs == null
202
+ || receipt.spawnDispatchedAt == null
203
+ || receipt.activationDeadlineAt == null
204
+ || receipt.activationDeadlineMonotonicMs == null
205
+ || !Number.isFinite(Date.parse(receipt.spawnDispatchedAt))
206
+ || !Number.isFinite(Date.parse(receipt.activationDeadlineAt))
207
+ ) {
208
+ return fail('DELEGATION_NOT_DISPATCHED', `delegation ${receipt.id} has not reached the native spawn dispatch boundary`);
209
+ }
210
+ const monotonic = (options.monotonicNow ?? (() => Number(process.hrtime.bigint() / 1_000_000n)))();
211
+ const wallNow = Date.parse((options.now ?? (() => new Date().toISOString()))());
212
+ if (wallNow > Date.parse(receipt.activationDeadlineAt)) {
213
+ return fail('DELEGATION_ACTIVATION_TIMEOUT', `delegation ${receipt.id} activation evidence arrived after its deadline`);
214
+ }
114
215
  if (managedRole !== receipt.role) return fail('DELEGATION_ROLE_MISMATCH', `managed role ${managedRole} does not match ${receipt.role}`);
115
216
  if (!event.parentId || (receipt.parentId !== null && event.parentId !== receipt.parentId) || !event.childId || event.childId === event.parentId) {
116
217
  return fail('DELEGATION_IDENTITY_INVALID', 'native parent/child identity does not match the prepared delegation');
117
218
  }
118
- if (event.spawnMode !== 'fresh') return fail('DELEGATION_FORK_FORBIDDEN', `spawn mode '${event.spawnMode}' is not fresh`);
119
- const actualModel = event.actualModel;
120
- if (!actualModel || actualModel.trim() !== actualModel) {
121
- return fail('DELEGATION_MODEL_IDENTITY_MISSING', 'native start event must provide a non-empty actual model identity');
219
+ // spawnMode 的必需性按 client 判断:claude-code 宿主结构上不提供该字段,跳过;其余 client 维持硬校验
220
+ if (receipt.client !== 'claude-code' && event.spawnMode !== 'fresh') {
221
+ return fail('DELEGATION_FORK_FORBIDDEN', `spawn mode '${event.spawnMode}' is not fresh`);
222
+ }
223
+ // model/effort 维度:claude-code 如实记录、不做门禁;其余 client 维持现状硬校验(HDR-2)
224
+ const actualModel = foldBlankToNull(event.actualModel);
225
+ const actualReasoningEffort = foldBlankToNull(event.actualReasoningEffort);
226
+ if (receipt.client !== 'claude-code') {
227
+ if (!actualModel || actualModel.trim() !== actualModel) {
228
+ return fail('DELEGATION_MODEL_IDENTITY_MISSING', 'native start event must provide a non-empty actual model identity');
229
+ }
122
230
  }
123
- if (actualModel !== receipt.requestedModel && (!event.modelFallbackReason || event.modelFallbackReason.trim() === '')) {
124
- return fail('DELEGATION_MODEL_FALLBACK_UNRECORDED', 'actual model differs from requested model without a fallback reason');
231
+ if (actualModel !== null && actualModel !== receipt.requestedModel) {
232
+ if (receipt.client !== 'claude-code' && (!event.modelFallbackReason || event.modelFallbackReason.trim() === '')) {
233
+ return fail('DELEGATION_MODEL_FALLBACK_UNRECORDED', 'actual model differs from requested model without a fallback reason');
234
+ }
125
235
  }
126
- const actualReasoningEffort = event.actualReasoningEffort;
127
- if (!actualReasoningEffort || actualReasoningEffort.trim() !== actualReasoningEffort) {
128
- return fail('DELEGATION_REASONING_EFFORT_MISSING', 'native start event must provide a non-empty actual reasoning effort');
236
+ if (receipt.client !== 'claude-code') {
237
+ if (!actualReasoningEffort || actualReasoningEffort.trim() !== actualReasoningEffort) {
238
+ return fail('DELEGATION_REASONING_EFFORT_MISSING', 'native start event must provide a non-empty actual reasoning effort');
239
+ }
129
240
  }
130
241
  if (
131
- actualReasoningEffort !== receipt.requestedReasoningEffort
132
- && (!event.reasoningEffortFallbackReason || event.reasoningEffortFallbackReason.trim() === '')
133
- ) {
134
- return fail('DELEGATION_REASONING_EFFORT_FALLBACK_UNRECORDED', 'actual reasoning effort differs from requested effort without a fallback reason');
242
+ receipt.client === 'codex'
243
+ && event.hostEvidence?.kind !== 'codex-lifecycle-v2'
244
+ ) return fail('DELEGATION_HOST_EVIDENCE_REQUIRED', 'Codex activation requires trusted lifecycle-v2 host evidence');
245
+ if (actualReasoningEffort !== null && actualReasoningEffort !== receipt.requestedReasoningEffort) {
246
+ if (receipt.client !== 'claude-code' && (!event.reasoningEffortFallbackReason || event.reasoningEffortFallbackReason.trim() === '')) {
247
+ return fail('DELEGATION_REASONING_EFFORT_FALLBACK_UNRECORDED', 'actual reasoning effort differs from requested effort without a fallback reason');
248
+ }
135
249
  }
136
- if (actualModel === receipt.requestedModel && event.modelFallbackReason) {
250
+ // "无关 fallback 理由"检查对所有 client 保持不变——防止编造理由的红线,不属于 HDR-2 放宽范围
251
+ // actualModel/actualReasoningEffort 为 null(未观察到)时同样没有"实际不同"这回事,理由一样是无关的
252
+ if ((actualModel === null || actualModel === receipt.requestedModel) && event.modelFallbackReason) {
137
253
  return fail('DELEGATION_MODEL_FALLBACK_INVALID', 'model fallback reason is only valid when actual model differs');
138
254
  }
139
- if (actualReasoningEffort === receipt.requestedReasoningEffort && event.reasoningEffortFallbackReason) {
255
+ if (
256
+ (actualReasoningEffort === null || actualReasoningEffort === receipt.requestedReasoningEffort)
257
+ && event.reasoningEffortFallbackReason
258
+ ) {
140
259
  return fail('DELEGATION_REASONING_EFFORT_FALLBACK_INVALID', 'reasoning-effort fallback reason is only valid when actual effort differs');
141
260
  }
142
261
  if (
@@ -148,12 +267,39 @@ function activateDelegation(
148
267
  || event.hostEvidence.startRevision < 1
149
268
  )
150
269
  ) return fail('DELEGATION_HOST_EVIDENCE_INVALID', 'Codex start evidence reference is invalid');
270
+ if (event.hostEvidence?.kind === 'codex-lifecycle-v2') {
271
+ const expected = receipt.lifecycleProvenance;
272
+ const spawnObservedAt = Date.parse(event.hostEvidence.spawnObservedAt ?? '');
273
+ const spawnDispatchedAt = Date.parse(receipt.spawnDispatchedAt);
274
+ const activationDeadlineAt = Date.parse(receipt.activationDeadlineAt);
275
+ if (
276
+ !expected
277
+ || event.hostEvidence.protocolVersion !== expected.protocolVersion
278
+ || event.hostEvidence.packageVersion !== expected.packageVersion
279
+ || event.hostEvidence.internalExecutableBuildHash !== expected.internalExecutableBuildHash
280
+ || event.hostEvidence.lifecycleContractHash !== expected.lifecycleContractHash
281
+ || event.hostEvidence.hookDefinitionHash !== expected.hookDefinitionHash
282
+ || event.hostEvidence.hookSource !== expected.hookSource
283
+ || event.hostEvidence.hookSourcePathDigest !== expected.hookSourcePathDigest
284
+ || event.hostEvidence.hookSourceHash !== expected.hookSourceHash
285
+ || event.hostEvidence.capabilitySessionId !== expected.capabilitySessionId
286
+ || event.hostEvidence.capabilityTurnId !== expected.capabilityTurnId
287
+ || !event.hostEvidence.spawnToolUseId?.trim()
288
+ || event.hostEvidence.spawnToolUseId === expected.capabilityToolUseId
289
+ || !Number.isFinite(spawnObservedAt)
290
+ || spawnObservedAt < spawnDispatchedAt
291
+ || spawnObservedAt > activationDeadlineAt
292
+ || event.parentId !== expected.capabilitySessionId
293
+ || (event.hostEvidence.controllerInstanceDigest ?? null) !== expected.controllerInstanceDigest
294
+ || (event.hostEvidence.controlGeneration ?? null) !== expected.controlGeneration
295
+ ) return fail('DELEGATION_HOST_EVIDENCE_INVALID', 'Codex lifecycle provenance does not match the prepared receipt');
296
+ }
151
297
  return { ok: true, receipt: Object.freeze({
152
298
  ...receipt,
153
299
  status: 'activated',
154
300
  parentId: event.parentId,
155
301
  childId: event.childId,
156
- spawnMode: event.spawnMode,
302
+ spawnMode: event.spawnMode ?? null,
157
303
  actualModel,
158
304
  actualReasoningEffort,
159
305
  modelFallbackReason: event.modelFallbackReason ?? null,
@@ -164,10 +310,22 @@ function activateDelegation(
164
310
  consumer: null,
165
311
  consumedAt: null
166
312
  }) : receipt.hostEvidence ?? null,
167
- activatedAt: (options.now ?? (() => new Date().toISOString()))()
313
+ startEvidenceMonotonicMs: monotonic,
314
+ activatedMonotonicMs: (options.monotonicNow ?? (() => Number(process.hrtime.bigint() / 1_000_000n)))(),
315
+ activatedAt: new Date(wallNow).toISOString()
168
316
  }) };
169
317
  }
170
318
 
319
+ function abortPreparedDelegation(receipt: DelegationReceipt): ReceiptResult {
320
+ if (receipt.status !== 'prepared') {
321
+ return fail('DELEGATION_STATE_INVALID', `delegation ${receipt.id} is ${receipt.status}, expected prepared`);
322
+ }
323
+ return {
324
+ ok: true,
325
+ receipt: Object.freeze({ ...receipt, status: 'aborted' as const })
326
+ };
327
+ }
328
+
171
329
  function completeDelegationStage(
172
330
  receipt: DelegationReceipt,
173
331
  event: Readonly<{ stage: DelegationStage; round: number; artifact: string; agent: string }>
@@ -189,11 +347,18 @@ function sealDelegation(
189
347
  exitCode: number;
190
348
  afterFingerprint: string;
191
349
  changedPaths: readonly string[];
350
+ actualModel?: string;
351
+ actualReasoningEffort?: string;
352
+ modelFallbackReason?: string;
353
+ reasoningEffortFallbackReason?: string;
192
354
  hostEvidence?: Readonly<{ stopRevision: number; consumer: string; consumedAt: string }>;
193
355
  }>,
194
- options: { now?: () => string } = {}
356
+ options: { now?: () => string; requireHostEvidence?: boolean } = {}
195
357
  ): ReceiptResult {
196
358
  if (receipt.status !== 'stage-completed') return fail('DELEGATION_STATE_INVALID', `delegation ${receipt.id} is ${receipt.status}, expected stage-completed`);
359
+ if (receipt.client === 'codex' && options.requireHostEvidence !== false && !event.hostEvidence) {
360
+ return fail('DELEGATION_HOST_EVIDENCE_REQUIRED', 'Codex sealing requires consumed lifecycle-v2 host evidence');
361
+ }
197
362
  if (event.childId !== receipt.childId || event.exitCode !== 0) return fail('DELEGATION_STOP_INVALID', 'native stop identity or exit status is invalid');
198
363
  if (receipt.role === 'reviewer') {
199
364
  const taskRoot = `.agents/workspace/active/${receipt.taskId}/`;
@@ -219,6 +384,10 @@ function sealDelegation(
219
384
  status: 'sealed',
220
385
  afterFingerprint: event.afterFingerprint,
221
386
  changedPaths: Object.freeze([...event.changedPaths]),
387
+ actualModel: receipt.actualModel ?? foldBlankToNull(event.actualModel),
388
+ actualReasoningEffort: receipt.actualReasoningEffort ?? foldBlankToNull(event.actualReasoningEffort),
389
+ modelFallbackReason: receipt.modelFallbackReason ?? event.modelFallbackReason ?? null,
390
+ reasoningEffortFallbackReason: receipt.reasoningEffortFallbackReason ?? event.reasoningEffortFallbackReason ?? null,
222
391
  hostEvidence: event.hostEvidence && receipt.hostEvidence ? Object.freeze({
223
392
  ...receipt.hostEvidence,
224
393
  ...event.hostEvidence
@@ -239,10 +408,21 @@ function consumeDelegation(receipt: DelegationReceipt, options: { now?: () => st
239
408
 
240
409
  export {
241
410
  activateDelegation,
411
+ abortPreparedDelegation,
242
412
  completeDelegationStage,
243
413
  consumeDelegation,
414
+ dispatchDelegation,
415
+ foldBlankToNull,
244
416
  managedDelegationRole,
245
417
  prepareDelegation,
246
418
  sealDelegation
247
419
  };
248
- export type { DelegationHostEvidence, DelegationReceipt, DelegationRole, DelegationStage, DelegationStatus, ReceiptResult };
420
+ export type {
421
+ DelegationHostEvidence,
422
+ DelegationLifecycleProvenance,
423
+ DelegationReceipt,
424
+ DelegationRole,
425
+ DelegationStage,
426
+ DelegationStatus,
427
+ ReceiptResult
428
+ };