@dsh-enhanced/assistant-actions 0.1.32 → 0.1.34

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.
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
package/lib/service.js CHANGED
@@ -6,13 +6,13 @@ import { chmodSync, closeSync, constants, fstatSync, lstatSync, mkdirSync, openS
6
6
  import { dirname, join } from 'node:path';
7
7
  import { Config, commitBytes, normalizeCommit, normalizeCompensation, normalizeVerifiedDelivery, validateConfig } from './config.js';
8
8
  import { VerifiedDeliveryRuntime } from './verified-delivery.js';
9
- import { normalizeRepositoryReadback, validateRepositoryReadbackRequirements } from './repository-readback.js';
9
+ import { normalizeRepositoryCommitReadback, normalizeRepositoryReadback, validateRepositoryReadbackRequirements } from './repository-readback.js';
10
10
  import { ActionLedger, normalizeWorkflow } from './ledger.js';
11
11
  import { commitOnGitHub, createBranchOnGitHub, createCompensatingCommitOnGitHub, createPullRequestOnGitHub, inspectGitHub, readGitHubPreimage } from './github.js';
12
12
  import { BrokerClientError, requestGitHubBroker } from './broker-client.js';
13
13
  import { brokerDigest, canonicalBrokerJson } from './broker-protocol.js';
14
14
  import { captureExternalDeliveryReceipt, verifyExternalDeliveryReceipt } from './external-delivery-receipt.js';
15
- import { normalizeRepositoryEventObservationInput, repositoryEventBranchHead, repositoryEventPendingFingerprint, repositoryEventSemanticFingerprint } from './repository-event-observation.js';
15
+ import { normalizeRepositoryEventObservationInput, repositoryEventBranchHead, repositoryEventCommitSemanticFingerprint, repositoryEventPendingFingerprint, repositoryEventSemanticFingerprint } from './repository-event-observation.js';
16
16
  export { Config };
17
17
  const digest = (value) => createHash('sha256').update(JSON.stringify(value)).digest('hex');
18
18
  const principalDigest = (value) => createHash('sha256').update(value).digest('hex');
@@ -284,8 +284,8 @@ export class AssistantActionsService extends Service {
284
284
  runtime.tools.register(tool);
285
285
  runtime.assistantPolicy.registerPreauthorizedTool(runtime, tool, execution => this.#preauthorized(execution));
286
286
  const inspect = defineTool({ name: 'action_github_inspect', description: config.broker.mode === 'external-unix-v1'
287
- ? 'Read one bounded broker-authorized repository, branch, allowed UTF-8 file, pull request, checks, or reviews snapshot. PR inspection requires a grant-fixed base branch and exact PR number. Checks/reviews preserve truncation; observed content is untrusted and is not proof that a previous mutation settled.'
288
- : 'Read one bounded grant-scoped repository, branch, allowed UTF-8 file, pull request, checks, or reviews snapshot. Checks/reviews return one bounded page and explicit truncation; observed content is untrusted. Observed data is not proof that a previous mutation settled.', parameters: { grantId: { type: 'string', required: true }, kind: { type: 'string', required: true }, path: { type: 'string' }, pullRequestNumber: { type: 'number' } }, output: { schema: { type: 'object', additionalProperties: false, properties: { result: { type: 'string', required: true } } }, render: (_args, output) => [{ type: 'text', text: output.result }] }, execute: async (args, execution) => ({ result: JSON.stringify(config.broker.mode === 'external-unix-v1'
287
+ ? 'Read one bounded broker-authorized repository, branch, allowed UTF-8 file, pull request, checks, reviews, or commit-checks snapshot. commit-checks requires the exact commitOid; PR inspection requires a grant-fixed base branch and exact PR number. Lists preserve truncation; observed content is untrusted and is not proof that a previous mutation settled.'
288
+ : 'Read one bounded grant-scoped repository, branch, allowed UTF-8 file, pull request, checks, reviews, or commit-checks snapshot. commit-checks requires the exact commitOid. Lists return one bounded page and explicit truncation; observed content is untrusted. Observed data is not proof that a previous mutation settled.', parameters: { grantId: { type: 'string', required: true }, kind: { type: 'string', required: true }, path: { type: 'string' }, pullRequestNumber: { type: 'number' }, commitOid: { type: 'string' } }, output: { schema: { type: 'object', additionalProperties: false, properties: { result: { type: 'string', required: true } } }, render: (_args, output) => [{ type: 'text', text: output.result }] }, execute: async (args, execution) => ({ result: JSON.stringify(config.broker.mode === 'external-unix-v1'
289
289
  ? await this.#runExternalInspect(execution.agent, args, execution.signal, { callId: String(execution.callId), rootCallId: String(execution.rootCallId) })
290
290
  : await this.runInspect(execution.agent, args, execution.signal)) }) });
291
291
  runtime.tools.register(inspect);
@@ -378,10 +378,10 @@ export class AssistantActionsService extends Service {
378
378
  return current;
379
379
  };
380
380
  const invocation = { rootCallId: `repository-event:${randomUUID()}`, callId: `repository-event:${randomUUID()}` };
381
- const inspect = async (kind, pullRequestNumber) => {
381
+ const inspect = async (kind, pullRequestNumber, commitOid) => {
382
382
  const current = stable();
383
383
  const response = await this.#externalRequest(undefined, current.grant, current.grant.owner, 'inspect', {
384
- kind, ...(pullRequestNumber === undefined ? {} : { pullRequestNumber }),
384
+ kind, ...(pullRequestNumber === undefined ? {} : { pullRequestNumber }), ...(commitOid === undefined ? {} : { commitOid }),
385
385
  }, signal, { rootCallId: invocation.rootCallId, callId: `${invocation.callId}:${kind}` }, `${invocation.callId}:${kind}:${randomUUID()}`, current.authorization);
386
386
  if (response.result.status !== 'succeeded' || response.observed === undefined || response.generation === undefined || response.epochs === undefined)
387
387
  throw new Error('assistant-actions: repository event inspection unavailable');
@@ -405,6 +405,16 @@ export class AssistantActionsService extends Service {
405
405
  // using the delivery-selected PR number. Caller-supplied PR numbers never
406
406
  // cross this boundary.
407
407
  this.#verifyExternalDelivery(intent, outcome);
408
+ if (input.deliveryMode === 'commit') {
409
+ const commitOid = outcome.commit.commitOid;
410
+ if (intent.request.pullRequest || !commitOid || headOid !== commitOid)
411
+ return Object.freeze({ protocol: 'assistant-actions/repository-event/v1', fingerprint: repositoryEventPendingFingerprint(input, headOid), truthy: true });
412
+ const checks = await inspect('commit-checks', undefined, commitOid);
413
+ if (checks.generation !== branch.generation || checks.epochs !== branch.epochs)
414
+ throw new Error('assistant-actions: repository event broker generation changed');
415
+ stable();
416
+ return Object.freeze({ protocol: 'assistant-actions/repository-event/v1', fingerprint: repositoryEventCommitSemanticFingerprint(input, headOid, checks.observed), truthy: true });
417
+ }
408
418
  const pullRequestNumber = outcome.pullRequest?.pullRequestNumber;
409
419
  const commitOid = outcome.commit.commitOid;
410
420
  if (!Number.isSafeInteger(pullRequestNumber) || !commitOid || headOid !== commitOid)
@@ -425,7 +435,9 @@ export class AssistantActionsService extends Service {
425
435
  const grant = this.#externalGrants.get(input.grantId);
426
436
  if (!grant || grant.revision !== input.grantRevision || grant.grantDigest !== input.grantDigest || grant.expiresAt <= Date.now()
427
437
  || grant.destination.repository !== input.repository || grant.destination.branch !== input.branch || grant.destination.baseBranch !== input.baseBranch
428
- || !grant.allowedOperations.includes('inspect') || !['branch', 'pull-request', 'checks', 'reviews'].every(kind => grant.allowedInspectKinds.includes(kind))
438
+ || !grant.allowedOperations.includes('inspect') || (input.deliveryMode === 'commit'
439
+ ? grant.allowedOperations.includes('pull-request') || !['branch', 'commit-checks'].every(kind => grant.allowedInspectKinds.includes(kind))
440
+ : !['branch', 'pull-request', 'checks', 'reviews'].every(kind => grant.allowedInspectKinds.includes(kind)))
429
441
  || grant.owner.principalDigest !== principalDigest(input.owner.principalId) || grant.owner.principalRecordId !== input.owner.principalRecordId
430
442
  || grant.owner.principalVersion !== input.owner.principalVersion || grant.owner.workspace !== input.owner.workspace || grant.owner.preset !== input.owner.preset
431
443
  || grant.expiresAt !== input.owner.expiresAt || grant.verifiedDelivery?.ownerRouteId !== input.owner.ownerRouteId)
@@ -457,7 +469,7 @@ export class AssistantActionsService extends Service {
457
469
  || grant.sessionId !== input.goal.sessionId || !this.#verified)
458
470
  throw new Error('assistant-actions: repository event goal changed');
459
471
  const latest = this.#verified.latestForGoal(input.goal, grant.id, { principalRecordId: input.owner.principalRecordId, principalVersion: input.owner.principalVersion }, { workspace: input.owner.workspace, preset: input.owner.preset });
460
- if (latest?.state === 'succeeded' && latest.outcome?.commit.status === 'succeeded' && latest.outcome.pullRequest?.status === 'succeeded')
472
+ if (latest?.state === 'succeeded' && latest.outcome?.commit.status === 'succeeded' && (input.deliveryMode === 'commit' ? !latest.intent.request.pullRequest && !latest.outcome.pullRequest : latest.outcome.pullRequest?.status === 'succeeded'))
461
473
  selected = { intent: latest.intent, outcome: latest.outcome };
462
474
  }
463
475
  const snapshot = digest({ grant: { id: grant.id, revision: grant.revision, digest: grant.grantDigest, expiresAt: grant.expiresAt, owner: grant.owner, destination: grant.destination }, route,
@@ -587,7 +599,7 @@ export class AssistantActionsService extends Service {
587
599
  const { grant, owner, identity } = this.#externalContext(agent, request.grantId);
588
600
  if (!this.#allowsExternal(grant, identity, input))
589
601
  throw new Error('assistant-actions: request not granted');
590
- const payload = { kind: request.kind, ...(request.path === undefined ? {} : { path: request.path }), ...(request.pullRequestNumber === undefined ? {} : { pullRequestNumber: request.pullRequestNumber }) };
602
+ const payload = { kind: request.kind, ...(request.path === undefined ? {} : { path: request.path }), ...(request.pullRequestNumber === undefined ? {} : { pullRequestNumber: request.pullRequestNumber }), ...(request.commitOid === undefined ? {} : { commitOid: request.commitOid }) };
591
603
  const { result, observed } = await this.#externalRequest(agent, grant, owner, 'inspect', payload, signal, invocation, request.idempotencyKey);
592
604
  return { result, ...(observed === undefined ? {} : { observed }) };
593
605
  }
@@ -702,18 +714,33 @@ export class AssistantActionsService extends Service {
702
714
  throw new Error('assistant-actions: repository readback bounds invalid');
703
715
  const observedAt = Date.now();
704
716
  const deadline = AbortSignal.any([signal, AbortSignal.timeout(initial.authority.timeoutMs)]);
717
+ if (initial.authority.kind === 'repository-commit-readback') {
718
+ // Check the receipt's immutable commit first, then fence a moving branch
719
+ // with the final remote read before issuing an affirmative outcome.
720
+ const [checks, branchSnapshot] = [
721
+ await this.#readRepositoryInspection(context, 'commit-checks', undefined, initial.commitOid, deadline),
722
+ await this.#readRepositoryInspection(context, 'branch', undefined, undefined, deadline),
723
+ ];
724
+ const final = context();
725
+ if (digest(initial) !== digest(final) || Date.now() - observedAt > final.authority.freshnessMs)
726
+ throw new Error('assistant-actions: repository readback authority changed');
727
+ return normalizeRepositoryCommitReadback({ repository: final.authority.repository, branch: final.authority.branch, commitOid: final.commitOid,
728
+ requirements: final.requirements, checks, branchSnapshot });
729
+ }
705
730
  const pullRequestNumber = initial.pullRequestNumber;
731
+ if (pullRequestNumber === undefined)
732
+ throw new Error('assistant-actions: repository delivery receipt invalid');
706
733
  const [checks, reviews, pullRequest, branchSnapshot] = [
707
- await this.#readRepositoryInspection(context, 'checks', pullRequestNumber, deadline),
708
- await this.#readRepositoryInspection(context, 'reviews', pullRequestNumber, deadline),
709
- await this.#readRepositoryInspection(context, 'pull-request', pullRequestNumber, deadline),
710
- await this.#readRepositoryInspection(context, 'branch', undefined, deadline),
734
+ await this.#readRepositoryInspection(context, 'checks', pullRequestNumber, undefined, deadline),
735
+ await this.#readRepositoryInspection(context, 'reviews', pullRequestNumber, undefined, deadline),
736
+ await this.#readRepositoryInspection(context, 'pull-request', pullRequestNumber, undefined, deadline),
737
+ await this.#readRepositoryInspection(context, 'branch', undefined, undefined, deadline),
711
738
  ];
712
739
  const final = context();
713
740
  if (digest(initial) !== digest(final) || Date.now() - observedAt > final.authority.freshnessMs)
714
741
  throw new Error('assistant-actions: repository readback authority changed');
715
742
  const normalized = normalizeRepositoryReadback({ repository: final.authority.repository, branch: final.authority.branch, baseBranch: final.authority.baseBranch,
716
- commitOid: final.commitOid, pullRequestNumber: final.pullRequestNumber, requirements: final.requirements, checks, reviews, pullRequest, branchSnapshot });
743
+ commitOid: final.commitOid, pullRequestNumber, requirements: final.requirements, checks, reviews, pullRequest, branchSnapshot });
717
744
  const headConfirmed = normalized.headOid === final.commitOid;
718
745
  const ci = !headConfirmed ? 'unknown' : normalized.ci;
719
746
  const review = !headConfirmed ? 'unknown' : normalized.review;
@@ -721,7 +748,7 @@ export class AssistantActionsService extends Service {
721
748
  ready: ci === 'passed' && review === 'approved' && (normalized.pullRequest === 'open' || normalized.pullRequest === 'merged') });
722
749
  };
723
750
  #repositoryReadbackContext(contract, authority) {
724
- if (!this.#active || !this.#verified || contract.expiresAt <= Date.now() || contract.task.kind !== 'goal-outcome' || authority.kind !== 'repository-readback')
751
+ if (!this.#active || !this.#verified || contract.expiresAt <= Date.now() || contract.task.kind !== 'goal-outcome' || !['repository-readback', 'repository-commit-readback'].includes(authority.kind))
725
752
  throw new Error('assistant-actions: repository readback binding invalid');
726
753
  const goal = contract.task.goal;
727
754
  const latest = this.#verified.latestForGoal({ id: goal.id, sessionId: goal.sessionId, nativeGoalId: goal.nativeGoalId, definitionVersion: goal.definitionVersion, definitionDigest: goal.definitionDigest }, authority.grantId, contract.owner, contract.scope);
@@ -737,6 +764,17 @@ export class AssistantActionsService extends Service {
737
764
  throw new Error('assistant-actions: repository grant changed');
738
765
  const outcome = latest.outcome;
739
766
  const commitOid = outcome.commit.commitOid, pullRequestOutcome = outcome.pullRequest, pullRequestNumber = pullRequestOutcome?.pullRequestNumber;
767
+ const direct = authority.kind === 'repository-commit-readback';
768
+ if (direct && latest.intent.request.pullRequest)
769
+ throw new Error('assistant-actions: repository direct delivery unexpectedly opened a pull request');
770
+ if (!direct && !latest.intent.request.pullRequest)
771
+ throw new Error('assistant-actions: repository pull request delivery missing');
772
+ if (direct && this.#mode === 'external-unix-v1') {
773
+ const external = this.#externalGrants.get(authority.grantId);
774
+ if (!external || external.allowedOperations.includes('pull-request') || !external.allowedOperations.includes('inspect')
775
+ || !external.allowedInspectKinds.includes('branch') || !external.allowedInspectKinds.includes('commit-checks'))
776
+ throw new Error('assistant-actions: repository direct grant changed');
777
+ }
740
778
  if (this.#mode === 'external-unix-v1')
741
779
  this.#verifyExternalDelivery(latest.intent, outcome);
742
780
  else {
@@ -744,11 +782,11 @@ export class AssistantActionsService extends Service {
744
782
  const pullRequest = pullRequestOutcome && this.#ledger.get(pullRequestOutcome.actionId);
745
783
  if (outcome.commit.status !== 'succeeded' || !commitOid || !commit || commit.kind !== 'commit' || commit.status !== 'succeeded' || digest(commit.result) !== digest(outcome.commit)
746
784
  || commit.grantId !== grant.id || commit.grantRevision !== grant.revision || commit.sessionId !== security.sessionId || digest(commit.identity) !== digest(security.identity)
747
- || !pullRequestOutcome || pullRequestOutcome.status !== 'succeeded' || !pullRequestNumber || !pullRequest || pullRequest.kind !== 'pull-request' || pullRequest.status !== 'succeeded' || digest(pullRequest.result) !== digest(pullRequestOutcome)
748
- || pullRequest.grantId !== grant.id || pullRequest.grantRevision !== grant.revision || pullRequest.sessionId !== security.sessionId || digest(pullRequest.identity) !== digest(security.identity))
785
+ || !direct && (!pullRequestOutcome || pullRequestOutcome.status !== 'succeeded' || !pullRequestNumber || !pullRequest || pullRequest.kind !== 'pull-request' || pullRequest.status !== 'succeeded' || digest(pullRequest.result) !== digest(pullRequestOutcome)
786
+ || pullRequest.grantId !== grant.id || pullRequest.grantRevision !== grant.revision || pullRequest.sessionId !== security.sessionId || digest(pullRequest.identity) !== digest(security.identity)))
749
787
  throw new Error('assistant-actions: repository delivery receipt invalid');
750
788
  }
751
- if (outcome.commit.status !== 'succeeded' || !commitOid || pullRequestOutcome?.status !== 'succeeded' || !pullRequestNumber)
789
+ if (outcome.commit.status !== 'succeeded' || !commitOid || !direct && (pullRequestOutcome?.status !== 'succeeded' || !pullRequestNumber))
752
790
  throw new Error('assistant-actions: repository delivery receipt invalid');
753
791
  this.#deliveryIdentity(security);
754
792
  const goals = this.ctx.get('assistantGoals', false);
@@ -778,10 +816,10 @@ export class AssistantActionsService extends Service {
778
816
  || digest(sourceContract.scope) !== digest(contract.scope) || sourceReceipt.objectiveStatus !== 'achieved')
779
817
  throw new Error('assistant-actions: repository source acceptance changed');
780
818
  const evidenceDigest = digest({ source, assessment, assessmentRun, acceptedSource });
781
- return Object.freeze({ authority: Object.freeze({ grantId: authority.grantId, grantRevision: authority.grantRevision, repository: authority.repository, branch: authority.branch, baseBranch: authority.baseBranch, timeoutMs: authority.timeoutMs, freshnessMs: authority.freshnessMs }),
782
- evidenceDigest, requirements: validateRepositoryReadbackRequirements({ requiredChecks: authority.requiredChecks, reviewerIds: authority.reviewerIds, minApprovals: authority.minApprovals }), security, intent: latest.intent, commitOid, pullRequestNumber });
819
+ return Object.freeze({ authority: Object.freeze({ kind: authority.kind, grantId: authority.grantId, grantRevision: authority.grantRevision, repository: authority.repository, branch: authority.branch, baseBranch: authority.baseBranch, timeoutMs: authority.timeoutMs, freshnessMs: authority.freshnessMs }),
820
+ evidenceDigest, requirements: validateRepositoryReadbackRequirements({ requiredChecks: authority.requiredChecks, reviewerIds: direct ? [] : authority.reviewerIds, minApprovals: direct ? 0 : authority.minApprovals }), security, intent: latest.intent, commitOid, ...(direct ? {} : { pullRequestNumber: pullRequestNumber }) });
783
821
  }
784
- async #readRepositoryInspection(context, kind, pullRequestNumber, signal) {
822
+ async #readRepositoryInspection(context, kind, pullRequestNumber, commitOid, signal) {
785
823
  let observed;
786
824
  const start = context();
787
825
  if (this.#mode === 'external-unix-v1') {
@@ -793,13 +831,13 @@ export class AssistantActionsService extends Service {
793
831
  authorization.current = () => { current(); if (digest(context()) !== digest(start))
794
832
  throw new Error('assistant-actions: repository readback changed'); };
795
833
  const generation = this.#externalObservedGeneration, epochs = this.#externalObservedEpochs, callId = `readback:${randomUUID()}`;
796
- const response = await this.#externalRequest(undefined, grant, grant.owner, 'inspect', { kind, ...(pullRequestNumber === undefined ? {} : { pullRequestNumber }) }, signal, { callId, rootCallId: start.intent.id }, callId, authorization);
834
+ const response = await this.#externalRequest(undefined, grant, grant.owner, 'inspect', { kind, ...(pullRequestNumber === undefined ? {} : { pullRequestNumber }), ...(commitOid === undefined ? {} : { commitOid }) }, signal, { callId, rootCallId: start.intent.id }, callId, authorization);
797
835
  if (response.result.status !== 'succeeded' || response.observed === undefined || generation !== undefined && generation !== response.generation || epochs !== undefined && epochs !== this.#externalObservedEpochs)
798
836
  throw new Error('assistant-actions: repository inspection unavailable or broker changed');
799
837
  authorization.current();
800
838
  return response.observed;
801
839
  }
802
- const request = normalizeWorkflow({ grantId: start.authority.grantId, operation: 'inspect', idempotencyKey: randomUUID(), kind, ...(pullRequestNumber === undefined ? {} : { pullRequestNumber }) });
840
+ const request = normalizeWorkflow({ grantId: start.authority.grantId, operation: 'inspect', idempotencyKey: randomUUID(), kind, ...(pullRequestNumber === undefined ? {} : { pullRequestNumber }), ...(commitOid === undefined ? {} : { commitOid }) });
803
841
  if (!('operation' in request))
804
842
  throw new Error('assistant-actions: repository inspection invalid');
805
843
  const authorization = { sessionId: start.security.sessionId,
@@ -807,7 +845,7 @@ export class AssistantActionsService extends Service {
807
845
  throw new Error('assistant-actions: repository readback changed'); return current.security.identity; },
808
846
  authorize: record => this.ctx.get('assistantPolicy')?.authorize(this.#deliveryPolicy(start.security), { idempotencyKey: `action:${record.id}` }).effect === 'allow' };
809
847
  const result = await this.#runAuthorized(authorization, request, signal, async (actionId, grant, token, combined) => {
810
- const reply = await this.workflow.inspect({ grant, kind: request.kind, ...(request.pullRequestNumber === undefined ? {} : { pullRequestNumber: request.pullRequestNumber }), token, signal: combined });
848
+ const reply = await this.workflow.inspect({ grant, kind: request.kind, ...(request.pullRequestNumber === undefined ? {} : { pullRequestNumber: request.pullRequestNumber }), ...(request.commitOid === undefined ? {} : { commitOid: request.commitOid }), token, signal: combined });
811
849
  observed = reply?.observed;
812
850
  return reply ? { actionId, status: 'succeeded' } : { actionId, status: 'failed', reason: 'github-inspect-failed' };
813
851
  });
@@ -971,16 +1009,24 @@ export class AssistantActionsService extends Service {
971
1009
  this.#deliveryIdentity(intent.security);
972
1010
  const grant = this.#externalGrants.get(intent.security.grantId), receipts = outcome.brokerReceipts;
973
1011
  const snapshot = this.#inspectDelivery(intent, true);
974
- if (!receipts?.commit || !receipts.pullRequest || !snapshot || !intent.request.pullRequest || !outcome.commit.commitOid || !outcome.pullRequest)
1012
+ if (!receipts?.commit || !snapshot || !outcome.commit.commitOid)
975
1013
  throw new Error('assistant-actions: external delivery receipt unavailable');
976
1014
  const destination = { classification: 'github-repository', repository: grant.destination.repository, branch: grant.destination.branch,
977
1015
  ...(grant.destination.baseBranch === undefined ? {} : { baseBranch: grant.destination.baseBranch }) };
978
1016
  const common = { grantId: grant.id, grantRevision: grant.revision, grantDigest: grant.grantDigest, owner: grant.owner, sessionId: intent.security.sessionId, source: grant.source, destination };
979
1017
  const commit = verifyExternalDeliveryReceipt(receipts.commit, { expectedHeadOid: intent.request.expectedHeadOid, headline: intent.request.headline,
980
1018
  files: snapshot.files.map(file => ({ path: file.path, content: file.content })) }, { ...common, operation: 'commit', actionId: this.#externalActionId(grant, intent.security.sessionId, 'commit', `${intent.id}:commit`) }, this.#external());
1019
+ if (commit.result?.operation !== 'commit' || commit.actionId !== outcome.commit.actionId || commit.result.commitOid !== outcome.commit.commitOid)
1020
+ throw new Error('assistant-actions: external delivery receipt changed');
1021
+ if (!intent.request.pullRequest) {
1022
+ if (outcome.pullRequest || receipts.pullRequest)
1023
+ throw new Error('assistant-actions: external delivery receipt changed');
1024
+ return;
1025
+ }
1026
+ if (!receipts.pullRequest || !outcome.pullRequest)
1027
+ throw new Error('assistant-actions: external delivery receipt unavailable');
981
1028
  const pr = verifyExternalDeliveryReceipt(receipts.pullRequest, { expectedHeadOid: outcome.commit.commitOid, ...intent.request.pullRequest }, { ...common, operation: 'pull-request', actionId: this.#externalActionId(grant, intent.security.sessionId, 'pull-request', `${intent.id}:pr`) }, this.#external());
982
- if (commit.result?.operation !== 'commit' || pr.result?.operation !== 'pull-request' || commit.actionId !== outcome.commit.actionId || pr.actionId !== outcome.pullRequest.actionId
983
- || commit.result.commitOid !== outcome.commit.commitOid || pr.result.pullRequestNumber !== outcome.pullRequest.pullRequestNumber)
1029
+ if (pr.result?.operation !== 'pull-request' || pr.actionId !== outcome.pullRequest.actionId || pr.result.pullRequestNumber !== outcome.pullRequest.pullRequestNumber)
984
1030
  throw new Error('assistant-actions: external delivery receipt changed');
985
1031
  }
986
1032
  async #deliverVerified(intent, snapshot, signal) {