intentdna 1.9.0 → 1.9.3

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 (131) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +227 -87
  4. package/dist/cli/commands/run-lifecycle.d.ts +61 -11
  5. package/dist/cli/commands/run-lifecycle.js +184 -50
  6. package/dist/cli/commands/run-observer.d.ts +15 -0
  7. package/dist/cli/commands/run-observer.js +210 -0
  8. package/dist/cli/commands/run.d.ts +16 -20
  9. package/dist/cli/commands/run.js +461 -659
  10. package/dist/cli/commands/sync.js +16 -12
  11. package/dist/cli/index.js +14 -5
  12. package/dist/compiler/compile.d.ts +1 -0
  13. package/dist/compiler/compile.js +1 -1
  14. package/dist/compiler/controller.d.ts +16 -0
  15. package/dist/compiler/controller.js +693 -0
  16. package/dist/compiler/input-resolver.d.ts +2 -0
  17. package/dist/compiler/input-resolver.js +22 -6
  18. package/dist/hooks/cli.d.ts +45 -0
  19. package/dist/hooks/cli.js +263 -31
  20. package/dist/hooks/host-event.d.ts +57 -0
  21. package/dist/hooks/host-event.js +187 -0
  22. package/dist/hooks/index.d.ts +1 -0
  23. package/dist/hooks/index.js +1 -0
  24. package/dist/hooks/protocol.d.ts +7 -0
  25. package/dist/hooks/schema.d.ts +1 -0
  26. package/dist/hooks/schema.js +89 -1
  27. package/dist/hooks/state.d.ts +23 -1
  28. package/dist/hooks/state.js +9 -0
  29. package/dist/index.d.ts +1 -0
  30. package/dist/index.js +1 -0
  31. package/dist/mcp/index.js +2 -0
  32. package/dist/mcp/tools-run.d.ts +4 -0
  33. package/dist/mcp/tools-run.js +419 -0
  34. package/dist/mcp/tools-state.d.ts +1 -1
  35. package/dist/mcp/tools-state.js +13 -241
  36. package/dist/runtime/artifact-store.d.ts +146 -0
  37. package/dist/runtime/artifact-store.js +1436 -0
  38. package/dist/runtime/canonical-attempt-outcome.d.ts +12 -0
  39. package/dist/runtime/canonical-attempt-outcome.js +195 -0
  40. package/dist/runtime/canonical-json.d.ts +10 -0
  41. package/dist/runtime/canonical-json.js +105 -0
  42. package/dist/runtime/canonical-run-application.d.ts +93 -0
  43. package/dist/runtime/canonical-run-application.js +229 -0
  44. package/dist/runtime/canonical-run-service.d.ts +454 -0
  45. package/dist/runtime/canonical-run-service.js +4760 -0
  46. package/dist/runtime/canonical-runtime-composition.d.ts +22 -0
  47. package/dist/runtime/canonical-runtime-composition.js +34 -0
  48. package/dist/runtime/canonical-runtime-projection.d.ts +3 -0
  49. package/dist/runtime/canonical-runtime-projection.js +4 -0
  50. package/dist/runtime/canonical-target-compiler.d.ts +46 -0
  51. package/dist/runtime/canonical-target-compiler.js +514 -0
  52. package/dist/runtime/claude-agent-identity.d.ts +2 -0
  53. package/dist/runtime/claude-agent-identity.js +21 -0
  54. package/dist/runtime/executable-run-plan.d.ts +328 -0
  55. package/dist/runtime/executable-run-plan.js +1485 -0
  56. package/dist/runtime/execution-authority.d.ts +83 -0
  57. package/dist/runtime/execution-authority.js +98 -0
  58. package/dist/runtime/handoff-resolver.js +4 -1
  59. package/dist/runtime/harness-pull-adapter.d.ts +146 -0
  60. package/dist/runtime/harness-pull-adapter.js +315 -0
  61. package/dist/runtime/index.d.ts +39 -14
  62. package/dist/runtime/index.js +29 -7
  63. package/dist/runtime/local-execution-authority.d.ts +194 -0
  64. package/dist/runtime/local-execution-authority.js +2897 -0
  65. package/dist/runtime/local-execution-reconciliation.d.ts +20 -0
  66. package/dist/runtime/local-execution-reconciliation.js +107 -0
  67. package/dist/runtime/local-execution-supervisor-script.d.ts +7 -0
  68. package/dist/runtime/local-execution-supervisor-script.js +793 -0
  69. package/dist/runtime/local-provider-sandbox.d.ts +42 -0
  70. package/dist/runtime/local-provider-sandbox.js +154 -0
  71. package/dist/runtime/local-verifier-execution.d.ts +24 -0
  72. package/dist/runtime/local-verifier-execution.js +290 -0
  73. package/dist/runtime/local-windows-execution-supervisor-script.d.ts +6 -0
  74. package/dist/runtime/local-windows-execution-supervisor-script.js +788 -0
  75. package/dist/runtime/plan-store.d.ts +30 -0
  76. package/dist/runtime/plan-store.js +231 -0
  77. package/dist/runtime/process-tree.d.ts +9 -0
  78. package/dist/runtime/process-tree.js +97 -24
  79. package/dist/runtime/providers/codex.js +2 -2
  80. package/dist/runtime/push-driver.d.ts +184 -0
  81. package/dist/runtime/push-driver.js +1002 -0
  82. package/dist/runtime/result-store.d.ts +34 -3
  83. package/dist/runtime/result-store.js +1073 -2
  84. package/dist/runtime/run-binding.d.ts +68 -0
  85. package/dist/runtime/run-binding.js +278 -0
  86. package/dist/runtime/run-contracts.d.ts +575 -0
  87. package/dist/runtime/run-contracts.js +58 -7
  88. package/dist/runtime/run-controller.d.ts +1 -6
  89. package/dist/runtime/run-controller.js +0 -41
  90. package/dist/runtime/run-store.d.ts +85 -7
  91. package/dist/runtime/run-store.js +2528 -186
  92. package/dist/runtime/skill-adapter.d.ts +18 -7
  93. package/dist/runtime/skill-adapter.js +100 -742
  94. package/dist/runtime/structured-output-validator.d.ts +44 -0
  95. package/dist/runtime/structured-output-validator.js +171 -0
  96. package/dist/runtime/verifier-command-binding.d.ts +22 -0
  97. package/dist/runtime/verifier-command-binding.js +162 -0
  98. package/dist/runtime/verifier.d.ts +46 -6
  99. package/dist/runtime/verifier.js +355 -53
  100. package/dist/runtime/windows-job-keeper.d.ts +47 -0
  101. package/dist/runtime/windows-job-keeper.js +231 -0
  102. package/dist/runtime/worker-executor.d.ts +17 -1
  103. package/dist/runtime/worker-executor.js +26 -5
  104. package/dist/runtime/workflow-plan-adapter.d.ts +19 -0
  105. package/dist/runtime/workflow-plan-adapter.js +502 -6
  106. package/dist/runtime/workflow-runtime-manifest.d.ts +1 -0
  107. package/dist/runtime/workflow-runtime-manifest.js +5 -0
  108. package/dist/runtime/workspace-isolation.d.ts +29 -2
  109. package/dist/runtime/workspace-isolation.js +488 -11
  110. package/dist/runtime/workspace-observation.d.ts +44 -0
  111. package/dist/runtime/workspace-observation.js +216 -0
  112. package/dist/schema/controller-registry.d.ts +0 -7
  113. package/dist/schema/controller-registry.js +0 -8
  114. package/dist/schema/types.d.ts +84 -10
  115. package/dist/schema/types.js +2 -0
  116. package/dist/schema/validate.js +151 -1
  117. package/dist/schema/validators/controllers.d.ts +1 -1
  118. package/dist/schema/validators/controllers.js +126 -41
  119. package/dist/schema/workflow-authoring-contract.js +2 -0
  120. package/dist/schema/yaml-parser.js +1 -1
  121. package/dist/templates/flutter-rewrite-new.dna.yaml +1 -0
  122. package/dist/templates/flutter-rewrite.dna.yaml +87 -60
  123. package/dist/templates/safe-refactoring.dna.yaml +1 -0
  124. package/native/windows-job-keeper/README.md +80 -0
  125. package/native/windows-job-keeper/bin/aarch64/intentdna-windows-job-keeper.exe +0 -0
  126. package/native/windows-job-keeper/bin/x86_64/intentdna-windows-job-keeper.exe +0 -0
  127. package/native/windows-job-keeper/keeper.c +979 -0
  128. package/native/windows-job-keeper/manifest.json +33 -0
  129. package/package.json +6 -2
  130. package/scripts/build-windows-job-keeper.mjs +172 -0
  131. package/scripts/verify-windows-job-keeper.mjs +184 -0
@@ -0,0 +1,83 @@
1
+ import type { ActivationId, AttemptExecutor, AttemptId, CanonicalAttemptOutcome, CanonicalResultDigest, CanonicalWorkerStopReceipt, CanonicalWorkerStopReceiptPayload, CanonicalWorkerNonlaunchAttestation, CanonicalWorkerNonlaunchAttestationPayload, CanonicalWorkerAlreadyStoppedEvidence, CanonicalWorkerAlreadyStoppedEvidencePayload, RunId, StepId } from "./run-contracts.js";
2
+ export interface AttemptExecutionAuthorityRequest {
3
+ readonly run_id: RunId;
4
+ readonly step_id: StepId;
5
+ readonly activation_id: ActivationId;
6
+ readonly attempt_id: AttemptId;
7
+ readonly claim_epoch: number;
8
+ readonly executor: Extract<AttemptExecutor, {
9
+ kind: "worker";
10
+ }>;
11
+ readonly purpose: "finalize_result" | "reconcile_published_result";
12
+ readonly reported_execution: {
13
+ readonly started_at: string;
14
+ readonly completed_at: string;
15
+ readonly outcome: CanonicalAttemptOutcome;
16
+ };
17
+ readonly expected_receipt: CanonicalWorkerStopReceipt | null;
18
+ }
19
+ export type StopExecutionPurpose = "cancel" | "execution_deadline" | "peer_terminal";
20
+ export interface StopExecutionRequest {
21
+ readonly run_id: RunId;
22
+ readonly step_id: StepId;
23
+ readonly activation_id: ActivationId;
24
+ readonly attempt_id: AttemptId;
25
+ readonly claim_epoch: number;
26
+ readonly executor: Extract<AttemptExecutor, {
27
+ kind: "worker";
28
+ }>;
29
+ readonly purpose: StopExecutionPurpose;
30
+ readonly requested_at: string;
31
+ readonly started_at: string;
32
+ readonly requested_outcome: CanonicalAttemptOutcome;
33
+ readonly stop_idempotency_key: CanonicalResultDigest;
34
+ readonly expected_receipt: CanonicalWorkerStopReceipt | null;
35
+ }
36
+ export interface StoppedExecutionAuthority {
37
+ readonly stop_receipt: CanonicalWorkerStopReceipt;
38
+ readonly authority_instance_id: string;
39
+ readonly fencing_epoch: number;
40
+ }
41
+ export type StopExecutionResolution = {
42
+ readonly kind: "stopped_by_request";
43
+ readonly authority: StoppedExecutionAuthority;
44
+ } | {
45
+ readonly kind: "already_stopped";
46
+ readonly drain_evidence: CanonicalWorkerAlreadyStoppedEvidence;
47
+ } | {
48
+ readonly kind: "never_launched";
49
+ readonly nonlaunch_attestation: CanonicalWorkerNonlaunchAttestation;
50
+ };
51
+ export interface ExecutionRecoveryProbeRequest {
52
+ readonly run_id: RunId;
53
+ readonly step_id: StepId;
54
+ readonly activation_id: ActivationId;
55
+ readonly attempt_id: AttemptId;
56
+ readonly execution_claim_epoch: number;
57
+ readonly executor: Extract<AttemptExecutor, {
58
+ kind: "worker";
59
+ }>;
60
+ readonly started_at: string;
61
+ }
62
+ export interface ExecutionRecoveryState {
63
+ readonly raw_completion_durable: boolean;
64
+ }
65
+ export interface NeverLaunchedAttestationRequest extends ExecutionRecoveryProbeRequest {
66
+ readonly failure_idempotency_key: CanonicalResultDigest;
67
+ readonly requested_at: string;
68
+ }
69
+ export interface AttemptExecutionAuthorityPort {
70
+ withStoppedExecution<T>(request: AttemptExecutionAuthorityRequest, operation: (authority: StoppedExecutionAuthority) => Promise<T>): Promise<T>;
71
+ requestStop?(request: StopExecutionRequest): Promise<StopExecutionResolution>;
72
+ probeRecovery?(request: ExecutionRecoveryProbeRequest): Promise<ExecutionRecoveryState>;
73
+ attestNeverLaunched?(request: NeverLaunchedAttestationRequest): Promise<CanonicalWorkerNonlaunchAttestation>;
74
+ }
75
+ export declare function workerNonlaunchAttestationDigest(payload: CanonicalWorkerNonlaunchAttestationPayload): CanonicalWorkerNonlaunchAttestation["attestation_digest"];
76
+ export declare function workerNonlaunchAttestationMatches(attestation: CanonicalWorkerNonlaunchAttestation, request: NeverLaunchedAttestationRequest): boolean;
77
+ export declare function workerStopReceiptDigest(payload: CanonicalWorkerStopReceiptPayload): CanonicalWorkerStopReceipt["receipt_digest"];
78
+ export declare function workerAlreadyStoppedEvidenceDigest(payload: CanonicalWorkerAlreadyStoppedEvidencePayload): CanonicalWorkerAlreadyStoppedEvidence["evidence_digest"];
79
+ export declare function createWorkerAlreadyStoppedEvidence(payload: CanonicalWorkerAlreadyStoppedEvidencePayload): CanonicalWorkerAlreadyStoppedEvidence;
80
+ export declare function workerAlreadyStoppedEvidenceMatchesStop(evidence: CanonicalWorkerAlreadyStoppedEvidence, request: StopExecutionRequest): boolean;
81
+ export declare function createWorkerStopReceipt(payload: CanonicalWorkerStopReceiptPayload): CanonicalWorkerStopReceipt;
82
+ export declare function workerStopReceiptMatchesExecution(receipt: CanonicalWorkerStopReceipt, request: AttemptExecutionAuthorityRequest): boolean;
83
+ export declare function workerStopReceiptMatchesStop(receipt: CanonicalWorkerStopReceipt, request: StopExecutionRequest): boolean;
@@ -0,0 +1,98 @@
1
+ import { createHash } from "node:crypto";
2
+ import { canonicalizeJson } from "./canonical-json.js";
3
+ export function workerNonlaunchAttestationDigest(payload) {
4
+ return `sha256:${createHash("sha256")
5
+ .update(canonicalizeJson(payload), "utf8")
6
+ .digest("hex")}`;
7
+ }
8
+ export function workerNonlaunchAttestationMatches(attestation, request) {
9
+ const payload = attestation.payload;
10
+ return attestation.attestation_digest === workerNonlaunchAttestationDigest(payload)
11
+ && payload.run_id === request.run_id
12
+ && payload.step_id === request.step_id
13
+ && payload.activation_id === request.activation_id
14
+ && payload.attempt_id === request.attempt_id
15
+ && payload.claim_epoch === request.execution_claim_epoch
16
+ && payload.worker_session_id === request.executor.worker_session_id
17
+ && payload.started_at === request.started_at
18
+ && payload.failure_idempotency_key === request.failure_idempotency_key
19
+ && payload.launch_state === "never_launched"
20
+ && payload.fencing_epoch > 0;
21
+ }
22
+ export function workerStopReceiptDigest(payload) {
23
+ return `sha256:${createHash("sha256")
24
+ .update(canonicalizeJson(payload), "utf8")
25
+ .digest("hex")}`;
26
+ }
27
+ export function workerAlreadyStoppedEvidenceDigest(payload) {
28
+ return `sha256:${createHash("sha256")
29
+ .update(canonicalizeJson(payload), "utf8")
30
+ .digest("hex")}`;
31
+ }
32
+ export function createWorkerAlreadyStoppedEvidence(payload) {
33
+ return {
34
+ evidence_digest: workerAlreadyStoppedEvidenceDigest(payload),
35
+ payload,
36
+ };
37
+ }
38
+ export function workerAlreadyStoppedEvidenceMatchesStop(evidence, request) {
39
+ const payload = evidence.payload;
40
+ return evidence.evidence_digest === workerAlreadyStoppedEvidenceDigest(payload)
41
+ && payload.run_id === request.run_id
42
+ && payload.step_id === request.step_id
43
+ && payload.activation_id === request.activation_id
44
+ && payload.attempt_id === request.attempt_id
45
+ && payload.claim_epoch === request.claim_epoch
46
+ && payload.worker_session_id === request.executor.worker_session_id
47
+ && payload.started_at === request.started_at
48
+ && payload.completed_at >= payload.started_at
49
+ && payload.process_tree_drained === true
50
+ && payload.stop_idempotency_key === request.stop_idempotency_key
51
+ && payload.stop_requested_at === request.requested_at
52
+ && payload.stop_purpose === request.purpose
53
+ && canonicalizeJson(payload.stop_requested_outcome) === canonicalizeJson(request.requested_outcome)
54
+ && payload.execution_instance_id.length > 0
55
+ && (payload.authority_kind === "local_process" || payload.authority_kind === "host_attested")
56
+ && payload.authority_instance_id.length > 0
57
+ && Number.isSafeInteger(payload.fencing_epoch)
58
+ && payload.fencing_epoch > 0
59
+ && /^sha256:[0-9a-f]{64}$/.test(payload.source_evidence_digest);
60
+ }
61
+ export function createWorkerStopReceipt(payload) {
62
+ return {
63
+ receipt_digest: workerStopReceiptDigest(payload),
64
+ payload,
65
+ };
66
+ }
67
+ export function workerStopReceiptMatchesExecution(receipt, request) {
68
+ const payload = receipt.payload;
69
+ return receipt.receipt_digest === workerStopReceiptDigest(payload)
70
+ && payload.run_id === request.run_id
71
+ && payload.step_id === request.step_id
72
+ && payload.activation_id === request.activation_id
73
+ && payload.attempt_id === request.attempt_id
74
+ && payload.claim_epoch === request.claim_epoch
75
+ && payload.worker_session_id === request.executor.worker_session_id
76
+ && payload.started_at === request.reported_execution.started_at
77
+ && payload.stopped_at === request.reported_execution.completed_at
78
+ && canonicalizeJson(payload.terminal_outcome)
79
+ === canonicalizeJson(request.reported_execution.outcome)
80
+ && payload.process_tree_drained === true;
81
+ }
82
+ export function workerStopReceiptMatchesStop(receipt, request) {
83
+ const payload = receipt.payload;
84
+ return receipt.receipt_digest === workerStopReceiptDigest(payload)
85
+ && payload.run_id === request.run_id
86
+ && payload.step_id === request.step_id
87
+ && payload.activation_id === request.activation_id
88
+ && payload.attempt_id === request.attempt_id
89
+ && payload.claim_epoch === request.claim_epoch
90
+ && payload.worker_session_id === request.executor.worker_session_id
91
+ && payload.started_at === request.started_at
92
+ && payload.stopped_at >= request.requested_at
93
+ && canonicalizeJson(payload.terminal_outcome)
94
+ === canonicalizeJson(request.requested_outcome)
95
+ && (request.expected_receipt === null
96
+ || canonicalizeJson(receipt) === canonicalizeJson(request.expected_receipt))
97
+ && payload.process_tree_drained === true;
98
+ }
@@ -76,7 +76,10 @@ export class HandoffResolver {
76
76
  description: request.description,
77
77
  mode: "reference",
78
78
  source: request.source,
79
- reference: output.reference,
79
+ reference: {
80
+ ...output.reference,
81
+ artifact_id: null,
82
+ },
80
83
  };
81
84
  }
82
85
  if (request.mode === "quote") {
@@ -0,0 +1,146 @@
1
+ import { CanonicalRunApplication, type CompiledCanonicalTarget, type StartCanonicalTargetRequest } from "./canonical-run-application.js";
2
+ import { type AcquireAttemptResponse, type AttemptExecutionSubmission, type AttemptView, type HeartbeatRequest, type LeaseView, type RunView, type StartRunResponse, type SubmitResponse } from "./canonical-run-service.js";
3
+ import type { DriverCapabilities, ExecutableRunPlanPayload } from "./executable-run-plan.js";
4
+ import type { CompiledIRFile } from "./plugin-adapter.js";
5
+ import type { CanonicalCallerAttestationPayload, CanonicalEvidenceRef, CanonicalAttemptRecord, CanonicalResultDigest, ClaimToken, JsonValue, RunId, WorkerSessionId } from "./run-contracts.js";
6
+ export declare const HARNESS_RUN_METADATA_SCHEMA_VERSION = "intentdna.harness_run_metadata.v1";
7
+ export declare const HARNESS_CALLER_ATTESTATION_SCHEMA_VERSION: "intentdna.harness_caller_attestation.v1";
8
+ export declare const HARNESS_SUBMISSION_MODE_VALUES: readonly ["relayed_submit", "attested_independent_submit"];
9
+ export type HarnessSubmissionMode = typeof HARNESS_SUBMISSION_MODE_VALUES[number];
10
+ export type HarnessPullAdapterErrorCode = "invalid_configuration" | "invalid_request" | "invalid_service_response" | "unsupported";
11
+ export declare class HarnessPullAdapterError extends Error {
12
+ readonly code: HarnessPullAdapterErrorCode;
13
+ constructor(code: HarnessPullAdapterErrorCode, message: string, options?: ErrorOptions);
14
+ }
15
+ export interface HarnessPullCapabilities {
16
+ readonly driver: Readonly<DriverCapabilities>;
17
+ readonly submission_modes: readonly HarnessSubmissionMode[];
18
+ readonly stopped_execution_authority: boolean;
19
+ }
20
+ export interface HarnessRunMetadata {
21
+ readonly schema_version: typeof HARNESS_RUN_METADATA_SCHEMA_VERSION;
22
+ readonly transport: "harness_pull";
23
+ readonly project_directory: string;
24
+ readonly target: StartCanonicalTargetRequest["target"];
25
+ readonly compiled_ir: CompiledIRFile | null;
26
+ readonly requested_metadata: JsonValue | null;
27
+ }
28
+ export type HarnessCallerAttestationPayload = CanonicalCallerAttestationPayload;
29
+ export interface HarnessCallerAttestation {
30
+ readonly attestation_ref: string;
31
+ readonly attestation_digest: CanonicalResultDigest;
32
+ readonly payload: HarnessCallerAttestationPayload;
33
+ }
34
+ export interface HarnessCallerAttestationRequest {
35
+ readonly run: RunView;
36
+ readonly submission: {
37
+ readonly attempt: CanonicalAttemptRecord;
38
+ readonly claim_epoch: number;
39
+ readonly submission_key_digest: CanonicalResultDigest;
40
+ readonly execution_digest: CanonicalResultDigest;
41
+ };
42
+ }
43
+ /**
44
+ * This port is a composition-root trust anchor. It must derive the current
45
+ * caller from host-authenticated context. The adapter supplies only durable
46
+ * submission facts; tool arguments are never caller attestation.
47
+ */
48
+ export interface HarnessCallerAttestationAuthority {
49
+ readonly authority_id: string;
50
+ attest(request: HarnessCallerAttestationRequest): Promise<HarnessCallerAttestation>;
51
+ }
52
+ export interface HarnessAttemptProjectionContext {
53
+ readonly run: RunView;
54
+ readonly attached: AttemptView;
55
+ readonly lease_token: ClaimToken;
56
+ readonly owner_id: string;
57
+ readonly worker_session_id: WorkerSessionId;
58
+ readonly submission_mode: HarnessSubmissionMode;
59
+ readonly metadata: HarnessRunMetadata | null;
60
+ }
61
+ export interface HarnessPullService {
62
+ start(request: {
63
+ readonly plan_payload: ExecutableRunPlanPayload;
64
+ readonly run_binding: CompiledCanonicalTarget["run_binding"];
65
+ readonly metadata?: JsonValue;
66
+ readonly run_id?: RunId;
67
+ }): Promise<StartRunResponse>;
68
+ inspect(runId: RunId): Promise<RunView>;
69
+ resume(runId: RunId): Promise<RunView>;
70
+ acquireAttempt(request: {
71
+ readonly run_id: RunId;
72
+ readonly driver_id: string;
73
+ readonly recover_running?: boolean;
74
+ }): Promise<AcquireAttemptResponse>;
75
+ attachAttempt(request: {
76
+ readonly lease_token: ClaimToken;
77
+ readonly owner_id: string;
78
+ readonly worker_identity: string;
79
+ readonly capabilities: Partial<DriverCapabilities>;
80
+ }): Promise<AttemptView>;
81
+ heartbeat(request: HeartbeatRequest): Promise<LeaseView>;
82
+ submitAttempt(request: {
83
+ readonly lease_token: ClaimToken;
84
+ readonly owner_id: string;
85
+ readonly submission_key: string;
86
+ readonly execution: AttemptExecutionSubmission;
87
+ readonly evidence_refs?: readonly CanonicalEvidenceRef[];
88
+ }): Promise<SubmitResponse>;
89
+ cancel(runId: RunId, reason?: string | null): Promise<RunView>;
90
+ }
91
+ export interface HarnessAttemptAttachRequest {
92
+ readonly run_id: RunId;
93
+ readonly attempt_id: string;
94
+ readonly lease_token: ClaimToken;
95
+ readonly owner_id: string;
96
+ readonly worker_session_id: WorkerSessionId;
97
+ readonly submission_mode: HarnessSubmissionMode;
98
+ }
99
+ export interface HarnessAttemptSubmitRequest {
100
+ readonly run_id: RunId;
101
+ readonly attempt_id: string;
102
+ readonly lease_token: ClaimToken;
103
+ readonly owner_id: string;
104
+ readonly submission_key: string;
105
+ readonly submission_mode: HarnessSubmissionMode;
106
+ readonly execution: AttemptExecutionSubmission;
107
+ readonly evidence_refs?: readonly CanonicalEvidenceRef[];
108
+ }
109
+ export interface HarnessPullAdapterOptions {
110
+ readonly service: HarnessPullService;
111
+ readonly application?: CanonicalRunApplication<StartRunResponse>;
112
+ readonly capabilities: HarnessPullCapabilities;
113
+ readonly caller_attestation_authority?: HarnessCallerAttestationAuthority;
114
+ readonly attempt_projection_sink?: (context: HarnessAttemptProjectionContext) => Promise<void> | void;
115
+ readonly validate_worker_session_id?: (workerSessionId: WorkerSessionId) => void;
116
+ readonly driver_id?: string;
117
+ }
118
+ export declare function parseHarnessRunMetadata(value: JsonValue): HarnessRunMetadata | null;
119
+ export declare function harnessCallerAttestationDigest(payload: HarnessCallerAttestationPayload): CanonicalResultDigest;
120
+ export declare class HarnessPullAdapter {
121
+ readonly capabilities: HarnessPullCapabilities;
122
+ private readonly service;
123
+ private readonly application;
124
+ private readonly callerAttestationAuthority;
125
+ private readonly attemptProjectionSink;
126
+ private readonly validateWorkerSessionId;
127
+ private readonly driverId;
128
+ constructor(options: HarnessPullAdapterOptions);
129
+ start(request: StartCanonicalTargetRequest): Promise<StartRunResponse>;
130
+ startCompiled(request: {
131
+ readonly compiled: CompiledCanonicalTarget;
132
+ readonly project_directory: string;
133
+ readonly target: StartCanonicalTargetRequest["target"];
134
+ readonly metadata?: JsonValue;
135
+ readonly run_id?: RunId;
136
+ }): Promise<StartRunResponse>;
137
+ next(runId: RunId): Promise<AcquireAttemptResponse>;
138
+ attach(request: HarnessAttemptAttachRequest): Promise<AttemptView>;
139
+ heartbeat(request: HeartbeatRequest): Promise<LeaseView>;
140
+ submit(request: HarnessAttemptSubmitRequest): Promise<SubmitResponse>;
141
+ status(runId: RunId): Promise<RunView>;
142
+ cancel(runId: RunId, reason?: string | null): Promise<RunView>;
143
+ private requireAttempt;
144
+ private assertSubmissionMode;
145
+ private attestSubmission;
146
+ }
@@ -0,0 +1,315 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { CanonicalRunApplication, } from "./canonical-run-application.js";
3
+ import { canonicalizeJson } from "./canonical-json.js";
4
+ import { durableCanonicalRuntimeProjection } from "./canonical-runtime-projection.js";
5
+ import { CALLER_ATTESTATION_SCHEMA_VERSION } from "./run-contracts.js";
6
+ export const HARNESS_RUN_METADATA_SCHEMA_VERSION = "intentdna.harness_run_metadata.v1";
7
+ export const HARNESS_CALLER_ATTESTATION_SCHEMA_VERSION = CALLER_ATTESTATION_SCHEMA_VERSION;
8
+ export const HARNESS_SUBMISSION_MODE_VALUES = [
9
+ "relayed_submit",
10
+ "attested_independent_submit",
11
+ ];
12
+ export class HarnessPullAdapterError extends Error {
13
+ code;
14
+ constructor(code, message, options) {
15
+ super(message, options);
16
+ this.name = "HarnessPullAdapterError";
17
+ this.code = code;
18
+ }
19
+ }
20
+ function digest(value) {
21
+ return `sha256:${createHash("sha256")
22
+ .update(canonicalizeJson(value), "utf8")
23
+ .digest("hex")}`;
24
+ }
25
+ function requireText(value, label) {
26
+ if (!value.trim()) {
27
+ throw new HarnessPullAdapterError("invalid_request", `${label} must be non-empty`);
28
+ }
29
+ }
30
+ function canonicalMetadata(compiled, request) {
31
+ const metadata = {
32
+ schema_version: HARNESS_RUN_METADATA_SCHEMA_VERSION,
33
+ transport: "harness_pull",
34
+ project_directory: request.environment.project_root,
35
+ target: request.target,
36
+ compiled_ir: compiled.projection === null
37
+ ? null
38
+ : durableCanonicalRuntimeProjection(compiled.projection),
39
+ requested_metadata: request.metadata ?? null,
40
+ };
41
+ return JSON.parse(canonicalizeJson(metadata));
42
+ }
43
+ export function parseHarnessRunMetadata(value) {
44
+ if (value === null || typeof value !== "object" || Array.isArray(value))
45
+ return null;
46
+ const record = value;
47
+ if (record.schema_version !== HARNESS_RUN_METADATA_SCHEMA_VERSION
48
+ || record.transport !== "harness_pull"
49
+ || typeof record.project_directory !== "string"
50
+ || record.target === null
51
+ || typeof record.target !== "object") {
52
+ return null;
53
+ }
54
+ return value;
55
+ }
56
+ export function harnessCallerAttestationDigest(payload) {
57
+ return digest(payload);
58
+ }
59
+ function validateCapabilities(capabilities, authority, projectionSink) {
60
+ const modes = new Set(capabilities.submission_modes);
61
+ if (capabilities.submission_modes.length !== modes.size
62
+ || capabilities.submission_modes.some((mode) => !HARNESS_SUBMISSION_MODE_VALUES.includes(mode))) {
63
+ throw new HarnessPullAdapterError("invalid_configuration", "harness submission modes are invalid");
64
+ }
65
+ if (modes.has("relayed_submit")
66
+ && capabilities.driver.direct_structured_submission !== true) {
67
+ throw new HarnessPullAdapterError("invalid_configuration", "relayed_submit requires direct_structured_submission");
68
+ }
69
+ if (modes.has("attested_independent_submit")
70
+ !== (capabilities.driver.caller_attestation === true)
71
+ || capabilities.driver.caller_attestation === true && authority === undefined) {
72
+ throw new HarnessPullAdapterError("invalid_configuration", "attested_independent_submit requires a trusted caller attestation authority");
73
+ }
74
+ if (capabilities.driver.hook_identity === true && projectionSink === undefined) {
75
+ throw new HarnessPullAdapterError("invalid_configuration", "hook_identity requires an attempt projection sink");
76
+ }
77
+ if (capabilities.driver.cancellation === true
78
+ && capabilities.stopped_execution_authority !== true) {
79
+ throw new HarnessPullAdapterError("invalid_configuration", "cancellation requires stopped-execution authority");
80
+ }
81
+ }
82
+ function assertRequiredCapabilities(plan, capabilities) {
83
+ for (const [name, required] of Object.entries(plan.required_capabilities)) {
84
+ if (required && capabilities[name] !== true) {
85
+ throw new HarnessPullAdapterError("unsupported", `harness capability ${name} is required`);
86
+ }
87
+ }
88
+ }
89
+ function sameJson(left, right) {
90
+ try {
91
+ return canonicalizeJson(left) === canonicalizeJson(right);
92
+ }
93
+ catch {
94
+ return false;
95
+ }
96
+ }
97
+ export class HarnessPullAdapter {
98
+ capabilities;
99
+ service;
100
+ application;
101
+ callerAttestationAuthority;
102
+ attemptProjectionSink;
103
+ validateWorkerSessionId;
104
+ driverId;
105
+ constructor(options) {
106
+ validateCapabilities(options.capabilities, options.caller_attestation_authority, options.attempt_projection_sink);
107
+ this.service = options.service;
108
+ this.application = options.application
109
+ ?? new CanonicalRunApplication({ starter: options.service });
110
+ this.capabilities = Object.freeze({
111
+ driver: Object.freeze({ ...options.capabilities.driver }),
112
+ submission_modes: Object.freeze([...options.capabilities.submission_modes]),
113
+ stopped_execution_authority: options.capabilities.stopped_execution_authority,
114
+ });
115
+ this.callerAttestationAuthority = options.caller_attestation_authority;
116
+ this.attemptProjectionSink = options.attempt_projection_sink;
117
+ this.validateWorkerSessionId = options.validate_worker_session_id;
118
+ this.driverId = options.driver_id ?? `harness-pull:${process.pid}:${randomUUID()}`;
119
+ requireText(this.driverId, "driver_id");
120
+ }
121
+ async start(request) {
122
+ const compiled = await this.application.compileTarget(request);
123
+ assertRequiredCapabilities(compiled.plan_payload, this.capabilities.driver);
124
+ return this.application.startCompiledTarget({
125
+ compiled,
126
+ metadata: canonicalMetadata(compiled, request),
127
+ ...(request.run_id === undefined ? {} : { run_id: request.run_id }),
128
+ });
129
+ }
130
+ async startCompiled(request) {
131
+ assertRequiredCapabilities(request.compiled.plan_payload, this.capabilities.driver);
132
+ const metadata = {
133
+ schema_version: HARNESS_RUN_METADATA_SCHEMA_VERSION,
134
+ transport: "harness_pull",
135
+ project_directory: request.project_directory,
136
+ target: request.target,
137
+ compiled_ir: request.compiled.projection === null
138
+ ? null
139
+ : durableCanonicalRuntimeProjection(request.compiled.projection),
140
+ requested_metadata: request.metadata ?? null,
141
+ };
142
+ return this.application.startCompiledTarget({
143
+ compiled: request.compiled,
144
+ metadata: JSON.parse(canonicalizeJson(metadata)),
145
+ ...(request.run_id === undefined ? {} : { run_id: request.run_id }),
146
+ });
147
+ }
148
+ async next(runId) {
149
+ requireText(runId, "run_id");
150
+ const resumed = await this.service.resume(runId);
151
+ assertRequiredCapabilities(resumed.plan.plan, this.capabilities.driver);
152
+ return this.service.acquireAttempt({
153
+ run_id: runId,
154
+ driver_id: this.driverId,
155
+ recover_running: false,
156
+ });
157
+ }
158
+ async attach(request) {
159
+ const run = await this.requireAttempt(request.run_id, request.attempt_id);
160
+ this.assertSubmissionMode(run, request.submission_mode);
161
+ try {
162
+ this.validateWorkerSessionId?.(request.worker_session_id);
163
+ }
164
+ catch (error) {
165
+ throw new HarnessPullAdapterError("invalid_request", "worker_session_id is invalid for this harness host", { cause: error });
166
+ }
167
+ const attached = await this.service.attachAttempt({
168
+ lease_token: request.lease_token,
169
+ owner_id: request.owner_id,
170
+ worker_identity: request.worker_session_id,
171
+ capabilities: this.capabilities.driver,
172
+ });
173
+ if (attached.lease.run_id !== request.run_id
174
+ || attached.lease.attempt_id !== request.attempt_id
175
+ || attached.attempt.executor?.kind !== "worker"
176
+ || attached.attempt.executor.worker_session_id !== request.worker_session_id) {
177
+ throw new HarnessPullAdapterError("invalid_service_response", "attached attempt identity does not match the requested harness lease");
178
+ }
179
+ if (this.capabilities.driver.hook_identity === true) {
180
+ const current = await this.service.inspect(request.run_id);
181
+ await this.attemptProjectionSink?.({
182
+ run: current,
183
+ attached,
184
+ lease_token: request.lease_token,
185
+ owner_id: request.owner_id,
186
+ worker_session_id: request.worker_session_id,
187
+ submission_mode: request.submission_mode,
188
+ metadata: parseHarnessRunMetadata(current.run.metadata),
189
+ });
190
+ }
191
+ return attached;
192
+ }
193
+ async heartbeat(request) {
194
+ return this.service.heartbeat(request);
195
+ }
196
+ async submit(request) {
197
+ const run = await this.requireAttempt(request.run_id, request.attempt_id);
198
+ this.assertSubmissionMode(run, request.submission_mode);
199
+ if (request.evidence_refs?.some((evidence) => evidence.kind === "caller_attestation")) {
200
+ throw new HarnessPullAdapterError("invalid_request", "caller attestation cannot be supplied through harness tool arguments");
201
+ }
202
+ const attempt = run.attempts.find((candidate) => candidate.attempt_id === request.attempt_id);
203
+ if (attempt.executor?.kind !== "worker"
204
+ || request.execution.executor.kind !== "worker"
205
+ || !sameJson(attempt.executor, request.execution.executor)) {
206
+ throw new HarnessPullAdapterError("invalid_request", "submission executor does not match the attached worker attempt");
207
+ }
208
+ const evidence = [...(request.evidence_refs ?? [])];
209
+ if (request.submission_mode === "attested_independent_submit") {
210
+ evidence.push(await this.attestSubmission(run, request));
211
+ }
212
+ return this.service.submitAttempt({
213
+ lease_token: request.lease_token,
214
+ owner_id: request.owner_id,
215
+ submission_key: request.submission_key,
216
+ execution: request.execution,
217
+ evidence_refs: evidence,
218
+ });
219
+ }
220
+ async status(runId) {
221
+ requireText(runId, "run_id");
222
+ return this.service.inspect(runId);
223
+ }
224
+ async cancel(runId, reason) {
225
+ requireText(runId, "run_id");
226
+ if (this.capabilities.driver.cancellation !== true) {
227
+ throw new HarnessPullAdapterError("unsupported", "harness cancellation requires trusted stopped-execution authority");
228
+ }
229
+ return this.service.cancel(runId, reason);
230
+ }
231
+ async requireAttempt(runId, attemptId) {
232
+ requireText(runId, "run_id");
233
+ requireText(attemptId, "attempt_id");
234
+ const run = await this.service.inspect(runId);
235
+ assertRequiredCapabilities(run.plan.plan, this.capabilities.driver);
236
+ if (!run.attempts.some((attempt) => attempt.attempt_id === attemptId)) {
237
+ throw new HarnessPullAdapterError("invalid_request", `attempt ${attemptId} does not belong to run ${runId}`);
238
+ }
239
+ return run;
240
+ }
241
+ assertSubmissionMode(run, mode) {
242
+ if (!this.capabilities.submission_modes.includes(mode)) {
243
+ throw new HarnessPullAdapterError("unsupported", `harness submission mode ${mode} is unavailable`);
244
+ }
245
+ if (run.plan.plan.required_capabilities.caller_attestation
246
+ && mode !== "attested_independent_submit") {
247
+ throw new HarnessPullAdapterError("unsupported", "this run requires attested_independent_submit");
248
+ }
249
+ }
250
+ async attestSubmission(run, request) {
251
+ const authority = this.callerAttestationAuthority;
252
+ if (authority === undefined) {
253
+ throw new HarnessPullAdapterError("unsupported", "trusted caller attestation is unavailable");
254
+ }
255
+ const attempt = run.attempts.find((candidate) => candidate.attempt_id === request.attempt_id);
256
+ const claim = [...run.claims]
257
+ .reverse()
258
+ .find((candidate) => candidate.attempt_id === request.attempt_id);
259
+ if (!claim || claim.owner_id !== request.owner_id) {
260
+ throw new HarnessPullAdapterError("invalid_request", "submission owner does not match the durable attempt claim");
261
+ }
262
+ if (request.execution.executor.kind !== "worker") {
263
+ throw new HarnessPullAdapterError("unsupported", "independent submission currently supports worker attempts only");
264
+ }
265
+ if (attempt.executor?.kind !== "worker"
266
+ || attempt.executor.worker_session_id !== request.execution.executor.worker_session_id) {
267
+ throw new HarnessPullAdapterError("invalid_request", "submission executor does not match the attached worker attempt");
268
+ }
269
+ const expected = {
270
+ run_id: request.run_id,
271
+ step_id: attempt.step_id,
272
+ activation_id: attempt.activation_id,
273
+ attempt_id: request.attempt_id,
274
+ claim_epoch: claim.claim_epoch,
275
+ worker_session_id: attempt.executor.worker_session_id,
276
+ submission_key_digest: digest({ submission_key: request.submission_key }),
277
+ execution_digest: digest(request.execution),
278
+ };
279
+ const attestation = await authority.attest({
280
+ run,
281
+ submission: {
282
+ attempt,
283
+ claim_epoch: claim.claim_epoch,
284
+ submission_key_digest: expected.submission_key_digest,
285
+ execution_digest: expected.execution_digest,
286
+ },
287
+ });
288
+ const payload = attestation.payload;
289
+ if (authority.authority_id.length === 0
290
+ || payload.schema_version !== HARNESS_CALLER_ATTESTATION_SCHEMA_VERSION
291
+ || payload.authority_id !== authority.authority_id
292
+ || !payload.agent_id
293
+ || !payload.session_id
294
+ || !sameJson({
295
+ run_id: payload.run_id,
296
+ step_id: payload.step_id,
297
+ activation_id: payload.activation_id,
298
+ attempt_id: payload.attempt_id,
299
+ claim_epoch: payload.claim_epoch,
300
+ worker_session_id: payload.worker_session_id,
301
+ submission_key_digest: payload.submission_key_digest,
302
+ execution_digest: payload.execution_digest,
303
+ }, expected)
304
+ || !attestation.attestation_ref
305
+ || attestation.attestation_digest !== harnessCallerAttestationDigest(payload)) {
306
+ throw new HarnessPullAdapterError("invalid_request", "caller attestation does not match the durable attempt submission");
307
+ }
308
+ return {
309
+ kind: "caller_attestation",
310
+ attestation_ref: attestation.attestation_ref,
311
+ attestation_digest: attestation.attestation_digest,
312
+ payload,
313
+ };
314
+ }
315
+ }