bazilion 0.17.0 → 0.18.0

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 (104) hide show
  1. package/dist/cli.js +336 -67
  2. package/dist/cli.js.map +1 -1
  3. package/dist/daemon.js +1770 -151
  4. package/dist/daemon.js.map +1 -1
  5. package/dist/migrations/0001_init.sql +107 -0
  6. package/dist/web/client/assets/{ChatPane-BI3QVX2A.js → ChatPane-CAYS_fIQ.js} +1 -1
  7. package/dist/web/client/assets/ConfirmDialog-BzIiABOP.js +1 -0
  8. package/dist/web/client/assets/{FieldRow-swJ5qn2h.js → FieldRow-W_54rw5c.js} +1 -1
  9. package/dist/web/client/assets/{ProductionTeamPolicyEditor-LGw1UuF-.js → ProductionTeamPolicyEditor-DNXVX8Lz.js} +2 -2
  10. package/dist/web/client/assets/{ProfileCommunicationEditor-raoau_YB.js → ProfileCommunicationEditor-DN0fOzqn.js} +1 -1
  11. package/dist/web/client/assets/{ResultSourceConversation-BEwkhFog.js → ResultSourceConversation-DoU4tOWc.js} +1 -1
  12. package/dist/web/client/assets/TeamTabs-BmTZRI4T.js +1 -0
  13. package/dist/web/client/assets/{TemplatesTabs-BX5hhEJ7.js → TemplatesTabs-Bs_OXKwx.js} +1 -1
  14. package/dist/web/client/assets/{UnsavedChangesGuard-CVJtmR1D.js → UnsavedChangesGuard-CPRtFReU.js} +1 -1
  15. package/dist/web/client/assets/{_id-DmEVZIlx.js → _id-CxAB4TDr.js} +1 -1
  16. package/dist/web/client/assets/{_id-DHqq2W34.js → _id-DL4tJFQB.js} +1 -1
  17. package/dist/web/client/assets/{_id-BQPOE3gj.js → _id-DR9eFC17.js} +1 -1
  18. package/dist/web/client/assets/{_id-BkYrUP0R.js → _id-Dbmei5tg.js} +1 -1
  19. package/dist/web/client/assets/{_id-CriixlZD.js → _id-ybF-pqmr.js} +1 -1
  20. package/dist/web/client/assets/{activity-Bzr8R18n.js → activity-oUyy77jD.js} +1 -1
  21. package/dist/web/client/assets/{agents-13oafeOA.js → agents-D_TrEqAg.js} +1 -1
  22. package/dist/web/client/assets/{agents-DF4NALmJ.js → agents-DkjJp7JP.js} +1 -1
  23. package/dist/web/client/assets/{approvals-DsG0Ijls.js → approvals-DhOerWdt.js} +1 -1
  24. package/dist/web/client/assets/{attention-DG7K25mz.js → attention-DGwiF-Jy.js} +1 -1
  25. package/dist/web/client/assets/chevron-right-DSa4xPTs.js +1 -0
  26. package/dist/web/client/assets/{config-DAaDbFhS.js → config-BJ2ZzHPR.js} +1 -1
  27. package/dist/web/client/assets/{inbox-C9e7QjsX.js → inbox-BUElnGep.js} +1 -1
  28. package/dist/web/client/assets/{index-Dsstm2hf.js → index-Bi-HxcPG.js} +2 -2
  29. package/dist/web/client/assets/{learning-23arTd21.js → learning-BiTHNwB3.js} +1 -1
  30. package/dist/web/client/assets/login-BmcZvAH2.js +1 -0
  31. package/dist/web/client/assets/{mcp-Cdx9qAl8.js → mcp-Cwk9V82W.js} +1 -1
  32. package/dist/web/client/assets/{members-fotOz4rR.js → members-CHDNabFh.js} +1 -1
  33. package/dist/web/client/assets/{memory-C7UznVot.js → memory-Cx_Fpd4e.js} +1 -1
  34. package/dist/web/client/assets/{policy-CactLW1X.js → policy-C0nMdwcG.js} +1 -1
  35. package/dist/web/client/assets/{results-DqEuYnQH.js → results-Bz3jASs-.js} +1 -1
  36. package/dist/web/client/assets/{review-CnBSYclb.js → review-AK9WGmpv.js} +1 -1
  37. package/dist/web/client/assets/routes-DsMY_6oy.js +1 -0
  38. package/dist/web/client/assets/{services-xEANwZAu.js → services-DItA6fJ7.js} +1 -1
  39. package/dist/web/client/assets/{skills-CamV6wYM.js → skills-DbNV2vgL.js} +1 -1
  40. package/dist/web/client/assets/{teams-B12dMSjW.js → teams-D83scDxw.js} +1 -1
  41. package/dist/web/client/assets/{teams-CbH43zSG.js → teams-DAny1ypN.js} +1 -1
  42. package/dist/web/client/assets/{telegram-muIql4u-.js → telegram-BOmf9vUh.js} +1 -1
  43. package/dist/web/client/assets/{tokens-DGFmApdF.js → tokens-DBGH6Bw5.js} +1 -1
  44. package/dist/web/client/assets/{triggers-D8n3sCBW.js → triggers-D1_pseI3.js} +1 -1
  45. package/dist/web/client/assets/verifications-CBTo-FyV.js +2 -0
  46. package/dist/web/client/assets/{welcome-CMHWRZhs.js → welcome-DAfPOm15.js} +1 -1
  47. package/dist/web/client/assets/{x-BGCHwZOH.js → x-CWY-gUaM.js} +1 -1
  48. package/dist/web/server/assets/{TeamTabs-DQXh-3ij.js → TeamTabs-Dg4v6x0-.js} +4 -0
  49. package/dist/web/server/assets/{_id-DDyA9CGX.js → _id--onriuvj.js} +1 -1
  50. package/dist/web/server/assets/{_id-XkxlX036.js → _id--zoh1vv7.js} +1 -1
  51. package/dist/web/server/assets/{_id-Dw3gKOGv.js → _id-6p-mDmI8.js} +1 -1
  52. package/dist/web/server/assets/{_id-CPfILjMa.js → _id-DptBl3X8.js} +1 -1
  53. package/dist/web/server/assets/{_id-DtJn-yzu.js → _id-EAjRXNbD.js} +2 -2
  54. package/dist/web/server/assets/{_id-DSPFJMzf.js → _id-dUnXL-My2.js} +1 -1
  55. package/dist/web/server/assets/{_tanstack-start-manifest_v-vOXRfKJD.js → _tanstack-start-manifest_v-B3M-dfRO.js} +90 -79
  56. package/dist/web/server/assets/{activity-pYQPT3QT.js → activity-C5jpoEQI.js} +1 -1
  57. package/dist/web/server/assets/{activity-BX1jZBPQ.js → activity-Cu7zKPGD.js} +1 -1
  58. package/dist/web/server/assets/{activity-bozPMU2v.js → activity-Dn50vkQP.js} +2 -2
  59. package/dist/web/server/assets/{agents-BKBfW700.js → agents-RE6aYOb-.js} +1 -1
  60. package/dist/web/server/assets/{agents-CVCfxnE2.js → agents-nAOx_H7s.js} +1 -1
  61. package/dist/web/server/assets/{approvals-C3ya6B6U.js → approvals-DhHxIDrL.js} +1 -1
  62. package/dist/web/server/assets/{attention-l28hGCHS.js → attention-CBWzWRni.js} +1 -1
  63. package/dist/web/server/assets/{auth-AvDFNeOv.js → auth-tB3i6cFd.js} +1 -1
  64. package/dist/web/server/assets/{config-BWKn4XII.js → config-D1k_tTAw.js} +1 -1
  65. package/dist/web/server/assets/{daemon-client-Cgx-YW4l.js → daemon-client-C7qjQ2iO.js} +15 -0
  66. package/dist/web/server/assets/{git-review-f_uta4Mx.js → git-review-Bf5ABFJg.js} +1 -1
  67. package/dist/web/server/assets/{inbox-BBZiOOQs.js → inbox-Dw4pTevh.js} +1 -1
  68. package/dist/web/server/assets/{learning-CheVay1i.js → learning-CF8ZzFVD.js} +1 -1
  69. package/dist/web/server/assets/{mcp-DCBDmNtQ.js → mcp-D5dmBT82.js} +1 -1
  70. package/dist/web/server/assets/{members-C5FQruRZ.js → members-Bd0OtiTr.js} +1 -1
  71. package/dist/web/server/assets/{members-C2He8mrU.js → members-CvwEN9pm.js} +1 -1
  72. package/dist/web/server/assets/{members-C_2xB9pr.js → members-xSXoYUOd.js} +2 -2
  73. package/dist/web/server/assets/{memory-rmiFNj7T.js → memory-CcPK7um7.js} +1 -1
  74. package/dist/web/server/assets/{memory-BTcmf0sD.js → memory-UP6AsRkO.js} +2 -2
  75. package/dist/web/server/assets/{memory-4tI-UbOf.js → memory-lo2vHRNw.js} +1 -1
  76. package/dist/web/server/assets/{policy-C3D2Q1EA.js → policy-B62WXIFo.js} +1 -1
  77. package/dist/web/server/assets/{policy-BGILKGHz.js → policy-Bze9Krhg.js} +2 -2
  78. package/dist/web/server/assets/{policy-DS7LGe--.js → policy-Dh6wd2wN.js} +1 -1
  79. package/dist/web/server/assets/{results-_6K_zXQS.js → results-BFqs2iOu.js} +1 -1
  80. package/dist/web/server/assets/{results-C6H42tjq.js → results-BWnu3gXP.js} +1 -1
  81. package/dist/web/server/assets/{results-Cgx7SrFt.js → results-CzZk50Fu.js} +2 -2
  82. package/dist/web/server/assets/{review-DHhiL-JQ.js → review-DUe3vHPU.js} +2 -2
  83. package/dist/web/server/assets/{review-DSTMCwP4.js → review-c_-cFi7H.js} +1 -1
  84. package/dist/web/server/assets/{router-ElARvZzI.js → router-Deq94UJQ.js} +33 -26
  85. package/dist/web/server/assets/{routes-BgMvLvS-.js → routes-CVKkvFVv.js} +1 -1
  86. package/dist/web/server/assets/{services-yHZroxsi.js → services-CEr61xb5.js} +1 -1
  87. package/dist/web/server/assets/{skills--bIKID1Q.js → skills-BImC3LTO.js} +1 -1
  88. package/dist/web/server/assets/{teams-BbRfuVXY.js → teams-8zEIo08E.js} +1 -1
  89. package/dist/web/server/assets/{teams--a956vWL.js → teams-D-yaAWLV.js} +1 -1
  90. package/dist/web/server/assets/{telegram-4kMxRtVZ.js → telegram-CGl_LFtJ.js} +1 -1
  91. package/dist/web/server/assets/{tokens-BYwTN9JZ.js → tokens-cB-uf7qm.js} +1 -1
  92. package/dist/web/server/assets/{triggers-BM6mzLuH.js → triggers-CtSj79L0.js} +1 -1
  93. package/dist/web/server/assets/verification-B5QjcpIo.js +97 -0
  94. package/dist/web/server/assets/verifications-BfQsfwSE.js +268 -0
  95. package/dist/web/server/assets/verifications-CUq_6ZqL.js +26 -0
  96. package/dist/web/server/server.js +51 -35
  97. package/dist/worker.js +178 -4
  98. package/dist/worker.js.map +1 -1
  99. package/package.json +3 -3
  100. package/dist/web/client/assets/ConfirmDialog-Qam6Ut08.js +0 -1
  101. package/dist/web/client/assets/TeamTabs-BDdTLGIf.js +0 -1
  102. package/dist/web/client/assets/chevron-right-DFqFHtLy.js +0 -1
  103. package/dist/web/client/assets/login-BIXnBsuj.js +0 -1
  104. package/dist/web/client/assets/routes-COxMuwVz.js +0 -1
package/dist/daemon.js CHANGED
@@ -21833,6 +21833,7 @@ __export(communicationApprovals_exports, {
21833
21833
  get: () => get9,
21834
21834
  getByAttempt: () => getByAttempt,
21835
21835
  grantSchedulerTrigger: () => grantSchedulerTrigger,
21836
+ grantVerificationRequest: () => grantVerificationRequest,
21836
21837
  list: () => list6,
21837
21838
  request: () => request
21838
21839
  });
@@ -22093,6 +22094,29 @@ function claimDelivery(db, id, actor, revalidate, now = Date.now()) {
22093
22094
  return outcome.detail;
22094
22095
  }
22095
22096
  function grantSchedulerTrigger(db, id, actor, revalidate, validateDelivery, now = Date.now()) {
22097
+ return grantDurableApproval(
22098
+ db,
22099
+ id,
22100
+ actor,
22101
+ { operation: "scheduler_trigger", payloadKind: "scheduler_trigger" },
22102
+ revalidate,
22103
+ validateDelivery,
22104
+ now
22105
+ );
22106
+ }
22107
+ function grantVerificationRequest(db, id, actor, revalidate, validateDelivery, onGranted, now = Date.now()) {
22108
+ return grantDurableApproval(
22109
+ db,
22110
+ id,
22111
+ actor,
22112
+ { operation: "request_verification", payloadKind: "verification_request" },
22113
+ revalidate,
22114
+ validateDelivery,
22115
+ now,
22116
+ onGranted
22117
+ );
22118
+ }
22119
+ function grantDurableApproval(db, id, actor, expected, revalidate, validateDelivery, now, onGranted) {
22096
22120
  expirePending(db, now);
22097
22121
  return db.raw.transaction(() => {
22098
22122
  const current = raw(db, id);
@@ -22100,8 +22124,10 @@ function grantSchedulerTrigger(db, id, actor, revalidate, validateDelivery, now
22100
22124
  const detail3 = detailFromRow(db, current);
22101
22125
  if (detail3.status !== "pending")
22102
22126
  throw new Error(`approval_state_conflict: current ${detail3.status}`);
22103
- if (detail3.operation !== "scheduler_trigger" || detail3.payloadKind !== "scheduler_trigger") {
22104
- throw new Error("approval_payload_conflict: not a scheduler trigger approval");
22127
+ if (detail3.operation !== expected.operation || detail3.payloadKind !== expected.payloadKind) {
22128
+ throw new Error(
22129
+ `approval_payload_conflict: not a ${expected.operation}/${expected.payloadKind} approval`
22130
+ );
22105
22131
  }
22106
22132
  const authorization = revalidate(detail3);
22107
22133
  const refsMatch = JSON.stringify(authorization.policyRefs) === JSON.stringify(detail3.policyRefs) && JSON.stringify(authorization.requiredEdgeIds) === JSON.stringify(detail3.requiredEdgeIds);
@@ -22154,6 +22180,7 @@ function grantSchedulerTrigger(db, id, actor, revalidate, validateDelivery, now
22154
22180
  [now, actor, now, id]
22155
22181
  ).changes;
22156
22182
  if (changed !== 1) throw new Error("approval_state_conflict: concurrent approval");
22183
+ onGranted?.(detail3);
22157
22184
  appendEvent(db, id, "approved", actor, null, now);
22158
22185
  appendEvent(db, id, "delivery_started", actor, null, now);
22159
22186
  appendEvent(db, id, "delivered", actor, null, now);
@@ -25957,6 +25984,356 @@ function approvalReference(db, agentId, id) {
25957
25984
  return { agentId, itemId: id, inputDigest: row.input_digest };
25958
25985
  }
25959
25986
 
25987
+ // ../daemon/src/core/repos/verification-requests.ts
25988
+ import { randomUUID as randomUUID21 } from "crypto";
25989
+ var VERIFICATION_REQUEST_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
25990
+ var VERIFICATION_MAX_CHECKS = 8;
25991
+ var VERIFICATION_LIMITS = {
25992
+ command: 2e3,
25993
+ cwd: 1e3,
25994
+ purpose: 500,
25995
+ summary: 2e3,
25996
+ error: 2e3,
25997
+ minTimeoutMs: 1e3,
25998
+ maxTimeoutMs: 3e5
25999
+ };
26000
+ var VERIFICATION_TERMINAL_REQUEST_STATES = [
26001
+ "completed",
26002
+ "failed",
26003
+ "cancelled",
26004
+ "uncertain"
26005
+ ];
26006
+ var REQUEST_COLUMNS = "id, team_id, requester_kind, requester_agent_id, recipient_agent_id, message_id, source_session_id, snapshot_id, snapshot_complete, head, base_oid, environment_json, summary, state, created_at, expires_at";
26007
+ var CHECK_COLUMNS = "request_id, ordinal, command, cwd, purpose, timeout_ms";
26008
+ var OUTCOME_COLUMNS = "attempt_id, ordinal, state, command_id, exit_code, started_at, finished_at";
26009
+ var ATTEMPT_COLUMNS = "id, request_id, attempt_number, supersedes_attempt_id, state, lease_owner, lease_expires_at, started_at, finished_at, error, created_at";
26010
+ function toRequest(row) {
26011
+ return {
26012
+ id: row.id,
26013
+ teamId: row.team_id,
26014
+ requesterKind: row.requester_kind === "agent" ? "agent" : "operator",
26015
+ requesterAgentId: row.requester_agent_id,
26016
+ recipientAgentId: row.recipient_agent_id,
26017
+ messageId: row.message_id,
26018
+ sourceSessionId: row.source_session_id,
26019
+ snapshotId: row.snapshot_id,
26020
+ snapshotComplete: row.snapshot_complete === 1,
26021
+ head: row.head,
26022
+ baseOid: row.base_oid,
26023
+ environment: JSON.parse(row.environment_json),
26024
+ summary: row.summary,
26025
+ state: row.state,
26026
+ createdAt: row.created_at,
26027
+ expiresAt: row.expires_at
26028
+ };
26029
+ }
26030
+ function toCheck(row) {
26031
+ return {
26032
+ requestId: row.request_id,
26033
+ ordinal: row.ordinal,
26034
+ command: row.command,
26035
+ cwd: row.cwd,
26036
+ purpose: row.purpose,
26037
+ timeoutMs: row.timeout_ms
26038
+ };
26039
+ }
26040
+ function toOutcome(row) {
26041
+ return {
26042
+ attemptId: row.attempt_id,
26043
+ ordinal: row.ordinal,
26044
+ state: row.state,
26045
+ commandId: row.command_id,
26046
+ exitCode: row.exit_code,
26047
+ startedAt: row.started_at,
26048
+ finishedAt: row.finished_at
26049
+ };
26050
+ }
26051
+ function toAttempt(row) {
26052
+ return {
26053
+ id: row.id,
26054
+ requestId: row.request_id,
26055
+ attemptNumber: row.attempt_number,
26056
+ supersedesAttemptId: row.supersedes_attempt_id,
26057
+ state: row.state,
26058
+ leaseOwner: row.lease_owner,
26059
+ leaseExpiresAt: row.lease_expires_at,
26060
+ startedAt: row.started_at,
26061
+ finishedAt: row.finished_at,
26062
+ error: row.error,
26063
+ createdAt: row.created_at
26064
+ };
26065
+ }
26066
+ var VerificationRequestError = class extends Error {
26067
+ status = 400;
26068
+ };
26069
+ function createVerificationRequest(db, input) {
26070
+ const now = input.now ?? Date.now();
26071
+ const id = input.id ?? randomUUID21();
26072
+ if (input.checks.length < 1)
26073
+ throw new VerificationRequestError("a request needs at least one check");
26074
+ if (input.checks.length > VERIFICATION_MAX_CHECKS) {
26075
+ throw new VerificationRequestError(
26076
+ `a request captures at most ${VERIFICATION_MAX_CHECKS} checks`
26077
+ );
26078
+ }
26079
+ for (const check of input.checks) validateCheck(check);
26080
+ validateEnvironment(input.environment);
26081
+ if (input.summary != null) {
26082
+ if (!input.summary.trim()) throw new VerificationRequestError("a summary must not be empty");
26083
+ assertLength(input.summary, VERIFICATION_LIMITS.summary, "summary");
26084
+ }
26085
+ if (!input.snapshotId)
26086
+ throw new VerificationRequestError("a request requires a captured snapshot");
26087
+ if (!input.baseOid) throw new VerificationRequestError("a request requires a captured base");
26088
+ if (input.requesterKind === "agent") {
26089
+ if (!input.requesterAgentId)
26090
+ throw new VerificationRequestError("an Agent request names its requester");
26091
+ if (input.requesterAgentId === input.recipientAgentId) {
26092
+ throw new VerificationRequestError("a specialist cannot verify its own request");
26093
+ }
26094
+ } else if (input.requesterAgentId) {
26095
+ throw new VerificationRequestError("an operator request has no requester Agent");
26096
+ }
26097
+ return inTx(db, () => {
26098
+ db.raw.run(
26099
+ `INSERT INTO verification_requests (${REQUEST_COLUMNS})
26100
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending', ?, ?)`,
26101
+ [
26102
+ id,
26103
+ input.teamId,
26104
+ input.requesterKind,
26105
+ input.requesterAgentId,
26106
+ input.recipientAgentId,
26107
+ input.messageId ?? null,
26108
+ input.sourceSessionId ?? null,
26109
+ input.snapshotId,
26110
+ input.snapshotComplete ? 1 : 0,
26111
+ input.head,
26112
+ input.baseOid,
26113
+ JSON.stringify(input.environment),
26114
+ input.summary ?? null,
26115
+ now,
26116
+ now + VERIFICATION_REQUEST_TTL_MS
26117
+ ]
26118
+ );
26119
+ input.checks.forEach((check, ordinal) => {
26120
+ db.raw.run(
26121
+ `INSERT INTO verification_checks (request_id, ordinal, command, cwd, purpose, timeout_ms)
26122
+ VALUES (?, ?, ?, ?, ?, ?)`,
26123
+ [id, ordinal, check.command, check.cwd, check.purpose, check.timeoutMs]
26124
+ );
26125
+ });
26126
+ const request2 = getVerificationRequest(db, input.teamId, id, now);
26127
+ if (!request2) throw new VerificationRequestError("request was not stored");
26128
+ return request2;
26129
+ });
26130
+ }
26131
+ function getVerificationRequest(db, teamId, id, now = Date.now()) {
26132
+ const row = db.raw.query(
26133
+ `SELECT ${REQUEST_COLUMNS} FROM verification_requests
26134
+ WHERE team_id = ? AND id = ? AND expires_at > ?`
26135
+ ).get(teamId, id, now);
26136
+ return row ? toRequest(row) : null;
26137
+ }
26138
+ function getVerificationRequestById(db, id, now = Date.now()) {
26139
+ const row = db.raw.query(
26140
+ `SELECT ${REQUEST_COLUMNS} FROM verification_requests WHERE id = ? AND expires_at > ?`
26141
+ ).get(id, now);
26142
+ return row ? toRequest(row) : null;
26143
+ }
26144
+ function listVerificationRequests(db, teamId, limit = 50, now = Date.now()) {
26145
+ return db.raw.query(
26146
+ `SELECT ${REQUEST_COLUMNS} FROM verification_requests
26147
+ WHERE team_id = ? AND expires_at > ?
26148
+ ORDER BY created_at DESC, id LIMIT ?`
26149
+ ).all(teamId, now, limit).map(toRequest);
26150
+ }
26151
+ function listVerificationChecks(db, requestId2) {
26152
+ return db.raw.query(
26153
+ `SELECT ${CHECK_COLUMNS} FROM verification_checks WHERE request_id = ? ORDER BY ordinal`
26154
+ ).all(requestId2).map(toCheck);
26155
+ }
26156
+ function listVerificationCheckOutcomes(db, attemptId) {
26157
+ return db.raw.query(
26158
+ `SELECT ${OUTCOME_COLUMNS} FROM verification_check_outcomes WHERE attempt_id = ?
26159
+ ORDER BY ordinal`
26160
+ ).all(attemptId).map(toOutcome);
26161
+ }
26162
+ function listVerificationAttempts(db, requestId2) {
26163
+ return db.raw.query(
26164
+ `SELECT ${ATTEMPT_COLUMNS} FROM verification_attempts WHERE request_id = ?
26165
+ ORDER BY attempt_number`
26166
+ ).all(requestId2).map(toAttempt);
26167
+ }
26168
+ function claimVerificationAttempt(db, input) {
26169
+ const now = input.now ?? Date.now();
26170
+ if (!input.leaseOwner) throw new VerificationRequestError("a claim requires an owner");
26171
+ if (input.leaseMs <= 0) throw new VerificationRequestError("a claim requires a positive lease");
26172
+ return inTx(db, () => {
26173
+ const row = db.raw.query(
26174
+ `SELECT ${REQUEST_COLUMNS} FROM verification_requests WHERE id = ? AND expires_at > ?`
26175
+ ).get(input.requestId, now);
26176
+ if (!row) return null;
26177
+ const request2 = toRequest(row);
26178
+ const terminal = VERIFICATION_TERMINAL_REQUEST_STATES.includes(request2.state);
26179
+ if (!terminal && request2.state !== "pending") return null;
26180
+ if (terminal && !input.rerun) return null;
26181
+ const open = db.raw.query(
26182
+ "SELECT id FROM verification_attempts WHERE request_id = ? AND finished_at IS NULL"
26183
+ ).get(input.requestId);
26184
+ if (open) return null;
26185
+ const previous = db.raw.query(
26186
+ `SELECT id, attempt_number FROM verification_attempts WHERE request_id = ?
26187
+ ORDER BY attempt_number DESC LIMIT 1`
26188
+ ).get(input.requestId);
26189
+ const attemptId = randomUUID21();
26190
+ db.raw.run(
26191
+ `INSERT INTO verification_attempts
26192
+ (id, request_id, attempt_number, supersedes_attempt_id, state, lease_owner,
26193
+ lease_expires_at, created_at)
26194
+ VALUES (?, ?, ?, ?, 'claimed', ?, ?, ?)`,
26195
+ [
26196
+ attemptId,
26197
+ input.requestId,
26198
+ (previous?.attempt_number ?? 0) + 1,
26199
+ previous?.id ?? null,
26200
+ input.leaseOwner,
26201
+ now + input.leaseMs,
26202
+ now
26203
+ ]
26204
+ );
26205
+ db.raw.run(
26206
+ `INSERT INTO verification_check_outcomes (attempt_id, ordinal, state)
26207
+ SELECT ?, ordinal, 'not_executed' FROM verification_checks WHERE request_id = ?`,
26208
+ [attemptId, input.requestId]
26209
+ );
26210
+ setRequestState(db, input.requestId, "running");
26211
+ const attempt = db.raw.query(
26212
+ `SELECT ${ATTEMPT_COLUMNS} FROM verification_attempts WHERE id = ?`
26213
+ ).get(attemptId);
26214
+ if (!attempt) throw new VerificationRequestError("attempt was not stored");
26215
+ return { attempt: toAttempt(attempt), state: "running" };
26216
+ });
26217
+ }
26218
+ function finishVerificationAttempt(db, input) {
26219
+ const now = input.now ?? Date.now();
26220
+ if (input.error != null) assertLength(input.error, VERIFICATION_LIMITS.error, "error");
26221
+ return inTx(db, () => {
26222
+ const row = db.raw.query(
26223
+ `SELECT ${ATTEMPT_COLUMNS} FROM verification_attempts WHERE id = ? AND lease_owner = ?`
26224
+ ).get(input.attemptId, input.leaseOwner);
26225
+ if (!row) return false;
26226
+ const attempt = toAttempt(row);
26227
+ if (attempt.finishedAt !== null) return false;
26228
+ db.raw.run(
26229
+ `UPDATE verification_attempts
26230
+ SET state = ?, finished_at = ?, lease_owner = NULL, lease_expires_at = NULL, error = ?
26231
+ WHERE id = ?`,
26232
+ [input.state, now, input.error ?? null, input.attemptId]
26233
+ );
26234
+ setRequestState(db, attempt.requestId, input.state === "uncertain" ? "uncertain" : input.state);
26235
+ return true;
26236
+ });
26237
+ }
26238
+ function setRequestState(db, requestId2, state3) {
26239
+ db.raw.run("UPDATE verification_requests SET state = ? WHERE id = ?", [state3, requestId2]);
26240
+ }
26241
+ function recordVerificationCheckOutcome(db, input) {
26242
+ if (input.state === "not_executed") {
26243
+ throw new VerificationRequestError("a settled outcome cannot return to not_executed");
26244
+ }
26245
+ const executed = ["succeeded", "failed", "timed_out", "cancelled"].includes(input.state);
26246
+ if (executed && !input.commandId) {
26247
+ throw new VerificationRequestError(`${input.state} requires the receipt that produced it`);
26248
+ }
26249
+ if (!executed && input.commandId) {
26250
+ throw new VerificationRequestError(`${input.state} cannot claim a command receipt`);
26251
+ }
26252
+ if (input.exitCode != null && input.state !== "succeeded" && input.state !== "failed") {
26253
+ throw new VerificationRequestError("only an executed check records an exit code");
26254
+ }
26255
+ const attempt = db.raw.query(
26256
+ "SELECT request_id FROM verification_attempts WHERE id = ?"
26257
+ ).get(input.attemptId);
26258
+ if (!attempt) return false;
26259
+ const result = db.raw.run(
26260
+ `UPDATE verification_check_outcomes
26261
+ SET state = ?, command_id = ?, exit_code = ?, started_at = ?, finished_at = ?
26262
+ WHERE attempt_id = ? AND ordinal = ? AND state = 'not_executed'
26263
+ AND EXISTS (SELECT 1 FROM verification_checks
26264
+ WHERE request_id = ? AND ordinal = ?)`,
26265
+ [
26266
+ input.state,
26267
+ input.commandId ?? null,
26268
+ input.exitCode ?? null,
26269
+ input.startedAt ?? null,
26270
+ input.finishedAt ?? Date.now(),
26271
+ input.attemptId,
26272
+ input.ordinal,
26273
+ attempt.request_id,
26274
+ input.ordinal
26275
+ ]
26276
+ );
26277
+ return Number(result.changes) === 1;
26278
+ }
26279
+ function recoverInterruptedVerificationAttempts(db, daemonIdentity, now = Date.now()) {
26280
+ return inTx(db, () => {
26281
+ const rows = db.raw.query(
26282
+ `SELECT id, request_id, lease_owner FROM verification_attempts WHERE finished_at IS NULL`
26283
+ ).all();
26284
+ const recovered = [];
26285
+ for (const row of rows) {
26286
+ if (row.lease_owner === daemonIdentity) continue;
26287
+ db.raw.run(
26288
+ `UPDATE verification_attempts
26289
+ SET state = 'uncertain', finished_at = ?, lease_owner = NULL, lease_expires_at = NULL,
26290
+ error = 'execution was interrupted before it reported an outcome'
26291
+ WHERE id = ?`,
26292
+ [now, row.id]
26293
+ );
26294
+ db.raw.run(
26295
+ `UPDATE verification_check_outcomes SET state = 'unknown', finished_at = ?
26296
+ WHERE attempt_id = ? AND state = 'not_executed'`,
26297
+ [now, row.id]
26298
+ );
26299
+ setRequestState(db, row.request_id, "uncertain");
26300
+ recovered.push(row.request_id);
26301
+ }
26302
+ return recovered;
26303
+ });
26304
+ }
26305
+ function pruneVerificationRequests(db, now = Date.now()) {
26306
+ const result = db.raw.run("DELETE FROM verification_requests WHERE expires_at <= ?", [now]);
26307
+ return Number(result.changes);
26308
+ }
26309
+ function validateCheck(check) {
26310
+ if (!check.command.trim()) throw new VerificationRequestError("a check requires a command");
26311
+ assertLength(check.command, VERIFICATION_LIMITS.command, "command");
26312
+ if (check.cwd.length > VERIFICATION_LIMITS.cwd) {
26313
+ throw new VerificationRequestError("cwd is outside its bounded contract");
26314
+ }
26315
+ if (!check.purpose.trim()) throw new VerificationRequestError("a check requires a purpose");
26316
+ assertLength(check.purpose, VERIFICATION_LIMITS.purpose, "purpose");
26317
+ if (!Number.isInteger(check.timeoutMs) || check.timeoutMs < VERIFICATION_LIMITS.minTimeoutMs || check.timeoutMs > VERIFICATION_LIMITS.maxTimeoutMs) {
26318
+ throw new VerificationRequestError("timeout is outside its bounded contract");
26319
+ }
26320
+ }
26321
+ function validateEnvironment(environment) {
26322
+ if (!environment.image)
26323
+ throw new VerificationRequestError("the admitted environment has no image");
26324
+ if (environment.sandbox !== "off" && environment.sandbox !== "docker") {
26325
+ throw new VerificationRequestError("the admitted environment has an unknown shell backend");
26326
+ }
26327
+ if (environment.env && Object.keys(environment.env).length > 32) {
26328
+ throw new VerificationRequestError("the admitted environment carries too many variables");
26329
+ }
26330
+ }
26331
+ function assertLength(value, limit, field) {
26332
+ if (Buffer.byteLength(value) > limit) {
26333
+ throw new VerificationRequestError(`${field} is outside its bounded contract`);
26334
+ }
26335
+ }
26336
+
25960
26337
  // ../daemon/src/lib/agent-cancel.ts
25961
26338
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("bazilion.agent-cancel.registry");
25962
26339
  var AgentTurnActiveError = class extends Error {
@@ -26054,14 +26431,14 @@ function reconcilePrivateResults(db, options = {}) {
26054
26431
  }
26055
26432
 
26056
26433
  // ../daemon/src/lib/coding-environment/lifecycle.ts
26057
- import { randomUUID as randomUUID24 } from "crypto";
26434
+ import { randomUUID as randomUUID25 } from "crypto";
26058
26435
 
26059
26436
  // ../daemon/src/lib/coding-environment/resources.ts
26060
- import { randomUUID as randomUUID22 } from "crypto";
26437
+ import { randomUUID as randomUUID23 } from "crypto";
26061
26438
 
26062
26439
  // ../daemon/src/runtime/shell/docker.ts
26063
26440
  import { spawn } from "child_process";
26064
- import { randomUUID as randomUUID21 } from "crypto";
26441
+ import { randomUUID as randomUUID22 } from "crypto";
26065
26442
  import { closeSync as closeSync2, constants as constants2, mkdtempSync as mkdtempSync2, openSync as openSync2, rmSync as rmSync9, writeFileSync as writeFileSync6 } from "fs";
26066
26443
  import { access, lstat, realpath, stat } from "fs/promises";
26067
26444
  import { tmpdir as tmpdir2 } from "os";
@@ -26551,7 +26928,7 @@ function createPreparedDockerBashOperations(runtime, lifecycle) {
26551
26928
  }
26552
26929
  await assertDockerExecutableIdentity(runtime.dockerPath, runtime.executableIdentity);
26553
26930
  if (signal?.aborted) throw new Error("aborted");
26554
- const containerName = lifecycle?.name("bash") ?? `bazilion-bash-${process.pid}-${randomUUID21().replaceAll("-", "")}`;
26931
+ const containerName = lifecycle?.name("bash") ?? `bazilion-bash-${process.pid}-${randomUUID22().replaceAll("-", "")}`;
26555
26932
  const spec = buildDockerRunSpec({
26556
26933
  image: runtime.image,
26557
26934
  resolvedImage: runtime.imageId,
@@ -26600,7 +26977,7 @@ async function preflightProtectedDockerEngine(input) {
26600
26977
  }
26601
26978
  async function proveProtectedContainerCreation(engine, workspace, readOnlyMounts, lifecycle, signal) {
26602
26979
  if (signal?.aborted) throw new Error("aborted");
26603
- const containerName = lifecycle?.name("preflight") ?? `bazilion-preflight-${process.pid}-${randomUUID21().replaceAll("-", "")}`;
26980
+ const containerName = lifecycle?.name("preflight") ?? `bazilion-preflight-${process.pid}-${randomUUID22().replaceAll("-", "")}`;
26604
26981
  const dockerClientEnv = { DOCKER_HOST: engine.endpoint };
26605
26982
  const spec = buildDockerRunSpec({
26606
26983
  image: engine.image,
@@ -26932,7 +27309,7 @@ function createDockerBashOperations(options) {
26932
27309
  const dockerClientEnv = await resolveLocalDockerClientEnv(dockerPath, hostEnv);
26933
27310
  const resolvedImage = await inspectSandboxImage(dockerPath, image, dockerClientEnv);
26934
27311
  if (signal?.aborted) throw new Error("aborted");
26935
- const containerName = options.lifecycle?.name("bash") ?? `bazilion-bash-${process.pid}-${randomUUID21().replaceAll("-", "")}`;
27312
+ const containerName = options.lifecycle?.name("bash") ?? `bazilion-bash-${process.pid}-${randomUUID22().replaceAll("-", "")}`;
26936
27313
  const spec = buildDockerRunSpec({
26937
27314
  image,
26938
27315
  env,
@@ -27588,7 +27965,7 @@ var WorkspaceResources = class {
27588
27965
  }
27589
27966
  register(lease, resource) {
27590
27967
  return inTx(this.db, () => {
27591
- const id = randomUUID22();
27968
+ const id = randomUUID23();
27592
27969
  lease.attach({ id, kind: resource.kind });
27593
27970
  this.db.raw.run(
27594
27971
  "INSERT INTO workspace_resources (id, writer_id, kind, identity_json) VALUES (?, ?, ?, ?)",
@@ -27626,7 +28003,7 @@ var WorkspaceResources = class {
27626
28003
  };
27627
28004
 
27628
28005
  // ../daemon/src/lib/coding-environment/workspace.ts
27629
- import { randomUUID as randomUUID23 } from "crypto";
28006
+ import { randomUUID as randomUUID24 } from "crypto";
27630
28007
  import { realpathSync as realpathSync3 } from "fs";
27631
28008
  import { isAbsolute as isAbsolute3, relative as relative2 } from "path";
27632
28009
  var WorkspaceBusyError = class extends Error {
@@ -27670,7 +28047,7 @@ var WorkspaceCoordinator = class {
27670
28047
  this.db = db;
27671
28048
  }
27672
28049
  db;
27673
- identity = randomUUID23();
28050
+ identity = randomUUID24();
27674
28051
  leases = /* @__PURE__ */ new Set();
27675
28052
  issued = /* @__PURE__ */ new WeakSet();
27676
28053
  claim(teamId, registeredRoot, kind) {
@@ -27684,7 +28061,7 @@ var WorkspaceCoordinator = class {
27684
28061
  const recovery = row.daemon_identity !== this.identity || row.state === "recovery";
27685
28062
  if (recovery || exclusive || row.exclusive === 1) throw new WorkspaceBusyError(recovery);
27686
28063
  }
27687
- const id = randomUUID23();
28064
+ const id = randomUUID24();
27688
28065
  this.db.raw.run(
27689
28066
  `INSERT INTO workspace_writers
27690
28067
  (id, team_id, root_path, root_identity, daemon_identity, kind, exclusive, state, created_at)
@@ -27803,7 +28180,7 @@ var WorkspaceLifecycle = class {
27803
28180
  const prefix = `bazilion-${lease.writer.id}-`;
27804
28181
  const records2 = /* @__PURE__ */ new Map();
27805
28182
  return {
27806
- name: (kind) => `${prefix}${kind}-${randomUUID24()}`,
28183
+ name: (kind) => `${prefix}${kind}-${randomUUID25()}`,
27807
28184
  beforeCreate: async (identity2) => {
27808
28185
  if (!identity2.containerName.startsWith(prefix) || !/^bazilion-[a-z0-9-]{1,160}$/.test(identity2.containerName) || records2.has(identity2.containerName))
27809
28186
  throw new Error("Invalid turn container identity");
@@ -27838,7 +28215,7 @@ var WorkspaceLifecycle = class {
27838
28215
  };
27839
28216
 
27840
28217
  // ../daemon/src/lib/conversation-target.ts
27841
- import { randomUUID as randomUUID26 } from "crypto";
28218
+ import { randomUUID as randomUUID27 } from "crypto";
27842
28219
 
27843
28220
  // ../daemon/src/core/repos/conversations.ts
27844
28221
  var columns = "id, agent_id AS agentId, title, title_revision AS titleRevision, created_at AS createdAt, updated_at AS updatedAt";
@@ -27960,7 +28337,7 @@ function rename(db, agentId, id, value, expectedRevision) {
27960
28337
  }
27961
28338
 
27962
28339
  // ../daemon/src/lib/conversation-file.ts
27963
- import { randomUUID as randomUUID25 } from "crypto";
28340
+ import { randomUUID as randomUUID26 } from "crypto";
27964
28341
  import {
27965
28342
  closeSync as closeSync4,
27966
28343
  constants as constants4,
@@ -28025,7 +28402,7 @@ function createConversationFile(paths, agentId, conversationId, cwd) {
28025
28402
  if (realpathSync5(directory) !== directory) throw new Error("Conversation escaped its Agent");
28026
28403
  const filename2 = `${conversationId}.jsonl`;
28027
28404
  const destination = join16(directory, filename2);
28028
- const staging = join16(directory, `.conversation-${randomUUID25()}.tmp`);
28405
+ const staging = join16(directory, `.conversation-${randomUUID26()}.tmp`);
28029
28406
  const header = SessionManager.inMemory(cwd, { id: conversationId }).getHeader();
28030
28407
  const fd = openSync4(staging, constants4.O_WRONLY | constants4.O_CREAT | constants4.O_EXCL, 384);
28031
28408
  try {
@@ -28063,7 +28440,7 @@ function resolveConversationTarget(db, paths, agentId, pinnedId) {
28063
28440
  db,
28064
28441
  agentId,
28065
28442
  {
28066
- requestId: randomUUID26(),
28443
+ requestId: randomUUID27(),
28067
28444
  expectedSelection: { conversationId: null, revision: 0 }
28068
28445
  },
28069
28446
  (newId) => createConversationFile(paths, agentId, newId, agent.team.path)
@@ -28130,7 +28507,7 @@ async function runAgentLifecycleMutation(agentId, mutation) {
28130
28507
  }
28131
28508
 
28132
28509
  // ../daemon/src/lib/agent-loop-guard.ts
28133
- import { randomUUID as randomUUID27 } from "crypto";
28510
+ import { randomUUID as randomUUID28 } from "crypto";
28134
28511
  var DEFAULT_MAX_HOPS = 8;
28135
28512
  function toEvent(row) {
28136
28513
  return {
@@ -28182,8 +28559,8 @@ function enforceMessageCausality(db, input) {
28182
28559
  const target = agents_exports.get(db, input.to);
28183
28560
  if (!source || !target) return null;
28184
28561
  const event2 = {
28185
- id: randomUUID27(),
28186
- causalChainId: input.causality.causalChainId ?? input.causality.parentMessageId ?? randomUUID27(),
28562
+ id: randomUUID28(),
28563
+ causalChainId: input.causality.causalChainId ?? input.causality.parentMessageId ?? randomUUID28(),
28187
28564
  parentMessageId: input.causality.parentMessageId,
28188
28565
  fromAgentId: input.from,
28189
28566
  toAgentId: input.to,
@@ -29610,8 +29987,8 @@ function assertRepositoryContext(value, teamId) {
29610
29987
  ]) && string(candidate.source) && digest3(candidate.sha256) && string(candidate.location) && string(candidate.cwd) && string(candidate.command) && ["script", "excerpt"].includes(String(candidate.kind)) && [null, "npm", "pnpm", "yarn"].includes(candidate.packageManager)
29611
29988
  ) || !["available", "unavailable", "not_repository"].includes(String(git.state)) || ![null, "branch", "detached", "unborn"].includes(git.headState) || ![git.root, git.branch, git.head].every((value2) => value2 === null || string(value2)) || ![git.staged, git.unstaged, git.untracked, git.conflicted].every(count2) || !list15(git.issues, 128, issue))
29612
29989
  throw new Error("Invalid repository context report");
29613
- const report = value;
29614
- if (report.instructions.files.reduce((bytes, file) => bytes + Buffer.byteLength(file.content), 0) > 128 * 1024 || report.instructions.state === "complete" && (report.rootIdentity === null || report.instructions.issues.length > 0))
29990
+ const report2 = value;
29991
+ if (report2.instructions.files.reduce((bytes, file) => bytes + Buffer.byteLength(file.content), 0) > 128 * 1024 || report2.instructions.state === "complete" && (report2.rootIdentity === null || report2.instructions.issues.length > 0))
29615
29992
  throw new Error("Invalid repository instruction completeness");
29616
29993
  }
29617
29994
 
@@ -31192,6 +31569,16 @@ var PROTECTED_REQUIRED_KEYS = new Set(
31192
31569
  (key3) => key3 !== "images" && key3 !== "questionEnabled" && key3 !== "containerNamespace"
31193
31570
  )
31194
31571
  );
31572
+ var VERIFICATION_KEYS = /* @__PURE__ */ new Set([
31573
+ "kind",
31574
+ "agentId",
31575
+ "message",
31576
+ "turnId",
31577
+ "runtime",
31578
+ "verification",
31579
+ "apiKeyRefreshEnabled",
31580
+ "scratch"
31581
+ ]);
31195
31582
  var REVIEW_KEYS = /* @__PURE__ */ new Set([
31196
31583
  "kind",
31197
31584
  "agentId",
@@ -31326,6 +31713,27 @@ function parseWorkerInput(value) {
31326
31713
  assertMinimalWorkerScratch(input.scratch);
31327
31714
  return value;
31328
31715
  }
31716
+ if (kind === "specialist_verification") {
31717
+ assertExactKeys(input, VERIFICATION_KEYS, "verification worker input", VERIFICATION_KEYS);
31718
+ requireString(input.agentId, "agentId");
31719
+ requireString(input.message, "message");
31720
+ requireString(input.turnId, "turnId");
31721
+ assertProtectedProviderRuntime(input.runtime);
31722
+ if (input.apiKeyRefreshEnabled !== true) {
31723
+ throw new Error("worker: verification input requires bound API key refresh");
31724
+ }
31725
+ assertMinimalWorkerScratch(input.scratch);
31726
+ const verification = objectRecord(input.verification, "verification metadata");
31727
+ assertExactKeys(
31728
+ verification,
31729
+ /* @__PURE__ */ new Set(["requestId", "attemptId"]),
31730
+ "verification metadata",
31731
+ /* @__PURE__ */ new Set(["requestId", "attemptId"])
31732
+ );
31733
+ requireString(verification.requestId, "requestId");
31734
+ requireString(verification.attemptId, "attemptId");
31735
+ return value;
31736
+ }
31329
31737
  if (kind === "restricted_review") {
31330
31738
  assertExactKeys(input, REVIEW_KEYS, "restricted review worker input", REVIEW_KEYS);
31331
31739
  requireString(input.agentId, "agentId");
@@ -33766,6 +34174,9 @@ async function spawnReviewWorker(spec, opts) {
33766
34174
  }
33767
34175
  throw new Error("review worker exited without a result");
33768
34176
  }
34177
+ function spawnVerificationWorker(spec, opts) {
34178
+ return spawnWorker(spec, opts);
34179
+ }
33769
34180
  function spawnWorkerTurn(spec, opts) {
33770
34181
  return spawnWorker(spec, opts);
33771
34182
  }
@@ -33813,7 +34224,7 @@ async function* spawnWorker(spec, opts) {
33813
34224
  }
33814
34225
  const accessTokens = spec.kind === "configured_operator_http" ? spec.apiKey ? [spec.apiKey] : [] : protectedRuntimeSecrets(spec.runtime);
33815
34226
  const stderrRedactor = accessTokens.length > 0 ? new ExactValueStreamRedactor(accessTokens) : void 0;
33816
- const resourceLifecycle = spec.kind === "restricted_review" ? void 0 : opts.resourceLifecycle;
34227
+ const resourceLifecycle = isRestrictedWorkerKind(spec) ? void 0 : opts.resourceLifecycle;
33817
34228
  let resourceCleanup;
33818
34229
  const cleanupResources = () => resourceCleanup ??= resourceLifecycle?.afterExit(child.exitCode !== null && child.signalCode === null).catch(() => false) ?? Promise.resolve(true);
33819
34230
  let child;
@@ -33989,9 +34400,12 @@ async function* spawnWorker(spec, opts) {
33989
34400
  throw new Error("Worker cleanup could not be confirmed; workspace recovery required");
33990
34401
  }
33991
34402
  }
34403
+ function isRestrictedWorkerKind(spec) {
34404
+ return spec.kind === "restricted_review" || spec.kind === "specialist_verification";
34405
+ }
33992
34406
  function assertSpawnCombination(spec, opts) {
33993
34407
  const record3 = opts;
33994
- if (spec.kind !== "restricted_review" && (Boolean(spec.questionEnabled) !== Boolean(record3.questionHost) || record3.questionHost && !hostHasMethods(record3.questionHost, ["ask", "close", "subscribe", "consumed"])))
34408
+ if (!isRestrictedWorkerKind(spec) && (Boolean(spec.questionEnabled) !== Boolean(record3.questionHost) || record3.questionHost && !hostHasMethods(record3.questionHost, ["ask", "close", "subscribe", "consumed"])))
33995
34409
  throw new Error("Question capability requires its bound host");
33996
34410
  if (spec.kind === "configured_operator_http") {
33997
34411
  if (!("env" in record3) || !record3.env || typeof record3.env !== "object") {
@@ -34025,9 +34439,20 @@ function assertSpawnCombination(spec, opts) {
34025
34439
  "userMdHost",
34026
34440
  "bashApprovalHost",
34027
34441
  "browserHost",
34028
- "mcpHost"
34442
+ "mcpHost",
34443
+ "codingHost",
34444
+ "containerHost",
34445
+ "repositoryContextHost",
34446
+ "resultHost",
34447
+ "resourceLifecycle"
34029
34448
  ]) {
34030
- if (forbidden in record3) throw new Error(`restricted review rejects ${forbidden}`);
34449
+ if (forbidden in record3) throw new Error(`${spec.kind} rejects ${forbidden}`);
34450
+ }
34451
+ const wantsCapability = spec.kind === "specialist_verification";
34452
+ if (wantsCapability !== "verificationHost" in record3) {
34453
+ throw new Error(
34454
+ wantsCapability ? "verification turn requires its bound capability host" : `${spec.kind} rejects verificationHost`
34455
+ );
34031
34456
  }
34032
34457
  }
34033
34458
  }
@@ -34054,16 +34479,20 @@ function spawnHosts(spec, opts, signal, onBashApproval, onQuestion, onApiKeyRefr
34054
34479
  );
34055
34480
  if (signal.aborted) questionHost.close();
34056
34481
  }
34482
+ const restricted = isRestrictedWorkerKind(spec);
34057
34483
  return {
34058
- questionHost,
34059
- containerHost: spec.kind === "restricted_review" ? void 0 : opts.containerHost,
34060
- codingHost: spec.kind === "restricted_review" ? void 0 : opts.codingHost,
34061
- repositoryContextHost: spec.kind === "restricted_review" ? void 0 : opts.repositoryContextHost,
34062
- resultHost: spec.kind === "restricted_review" ? void 0 : opts.resultHost,
34063
- messagingHost: configuredOpts?.messagingHost ?? protectedOpts?.messagingHost,
34064
- userMdHost: configuredOpts?.userMdHost ?? protectedOpts?.userMdHost,
34065
- browserHost: configuredOpts?.browserHost,
34066
- mcpHost: configuredOpts?.mcpHost,
34484
+ questionHost: restricted ? void 0 : questionHost,
34485
+ containerHost: restricted ? void 0 : opts.containerHost,
34486
+ codingHost: restricted ? void 0 : opts.codingHost,
34487
+ repositoryContextHost: restricted ? void 0 : opts.repositoryContextHost,
34488
+ resultHost: restricted ? void 0 : opts.resultHost,
34489
+ // A verification turn reads its request and runs captured checks; it does not message peers,
34490
+ // edit USER.md, drive a browser or call MCP. Cleared here rather than trusting the caller.
34491
+ messagingHost: restricted ? void 0 : configuredOpts?.messagingHost ?? protectedOpts?.messagingHost,
34492
+ userMdHost: restricted ? void 0 : configuredOpts?.userMdHost ?? protectedOpts?.userMdHost,
34493
+ browserHost: restricted ? void 0 : configuredOpts?.browserHost,
34494
+ mcpHost: restricted ? void 0 : configuredOpts?.mcpHost,
34495
+ verificationHost: spec.kind === "specialist_verification" ? opts.verificationHost : void 0,
34067
34496
  bashApprovalHost: configuredOpts?.bashApprovalHost ?? protectedOpts?.bashApprovalHost,
34068
34497
  apiKeyRefreshHost: opts.apiKeyRefreshHost,
34069
34498
  apiKeyRefreshContext: {
@@ -34216,6 +34645,19 @@ async function dispatch(req, hosts) {
34216
34645
  req.args.args
34217
34646
  );
34218
34647
  break;
34648
+ case "verificationRead":
34649
+ result = await require2(hosts.verificationHost, "verification", req.method).read(
34650
+ req.args.requestId,
34651
+ req.args.attemptId
34652
+ );
34653
+ break;
34654
+ case "verificationRun":
34655
+ result = await require2(hosts.verificationHost, "verification", req.method).run(
34656
+ req.args.requestId,
34657
+ req.args.attemptId,
34658
+ req.args.ordinal
34659
+ );
34660
+ break;
34219
34661
  case "refreshApiKey":
34220
34662
  result = await refreshApiKeyForTurn(
34221
34663
  req.args,
@@ -35058,7 +35500,7 @@ function createBrowserHost(config2) {
35058
35500
  }
35059
35501
 
35060
35502
  // ../daemon/src/lib/coding-environment/agent-host.ts
35061
- import { createHash as createHash10, randomUUID as randomUUID30 } from "crypto";
35503
+ import { createHash as createHash10, randomUUID as randomUUID31 } from "crypto";
35062
35504
 
35063
35505
  // ../daemon/src/core/repos/coding-command-logs.ts
35064
35506
  var CODING_LOG_BYTES = 2 * 1024 * 1024;
@@ -35278,7 +35720,7 @@ function pruneCodingCommandLogs(db, now = Date.now(), budgetBytes = CODING_LOG_H
35278
35720
  }
35279
35721
 
35280
35722
  // ../daemon/src/lib/communication.ts
35281
- import { randomUUID as randomUUID29 } from "crypto";
35723
+ import { randomUUID as randomUUID30 } from "crypto";
35282
35724
 
35283
35725
  // ../daemon/src/lib/question-approval.ts
35284
35726
  function questionApprovalReference(snapshot, kind) {
@@ -35373,7 +35815,7 @@ function questionVisible(db, item) {
35373
35815
  }
35374
35816
 
35375
35817
  // ../daemon/src/core/repos/results.ts
35376
- import { createHash as createHash9, randomUUID as randomUUID28 } from "crypto";
35818
+ import { createHash as createHash9, randomUUID as randomUUID29 } from "crypto";
35377
35819
  var MAX_RESULT_BYTES = 25 * 1024 * 1024;
35378
35820
  var MAX_RETAINED_RESULT_BYTES = 1024 * 1024 * 1024;
35379
35821
  var columns2 = `id, team_id AS teamId, agent_id AS agentId, session_id AS sessionId,
@@ -35420,7 +35862,7 @@ function publish(db, input) {
35420
35862
  "Result storage is full (1 GiB). Delete saved results before delivering more files."
35421
35863
  );
35422
35864
  }
35423
- const id = randomUUID28();
35865
+ const id = randomUUID29();
35424
35866
  db.raw.run(
35425
35867
  `INSERT INTO agent_results
35426
35868
  (id, team_id, agent_id, session_id, tool_call_id, name, mime_type, byte_length, sha256, created_at, bytes)
@@ -35649,6 +36091,39 @@ function authorizeAgentEgress(db, agentId, attempt) {
35649
36091
  "agent_to_user"
35650
36092
  );
35651
36093
  }
36094
+ function authorizeOperatorVerification(db, input) {
36095
+ const agent = agents_exports.get(db, input.agentId);
36096
+ return authorizeBoundary(
36097
+ db,
36098
+ {
36099
+ source: { kind: "user", teamId: agent?.teamId ?? "__missing__" },
36100
+ target: { kind: "agent", id: input.agentId },
36101
+ origin: "verification_request",
36102
+ attemptKind: "verification_request",
36103
+ attemptId: input.requestId,
36104
+ approvalPayloadKind: "verification_request",
36105
+ approvalPayload: { requestId: input.requestId },
36106
+ requester: "user"
36107
+ },
36108
+ "request_verification"
36109
+ );
36110
+ }
36111
+ function authorizeVerificationRequest(db, input) {
36112
+ return authorizeBoundary(
36113
+ db,
36114
+ {
36115
+ source: { kind: "agent", id: input.from },
36116
+ target: { kind: "agent", id: input.to },
36117
+ origin: "verification_request",
36118
+ attemptKind: "verification_request",
36119
+ attemptId: input.requestId,
36120
+ approvalPayloadKind: "verification_request",
36121
+ approvalPayload: { requestId: input.requestId },
36122
+ requester: input.from
36123
+ },
36124
+ "request_verification"
36125
+ );
36126
+ }
35652
36127
  function authorizeHttpChatFrame(db, agentId, requestAttemptId, frameIndex, frame) {
35653
36128
  if (frame.kind === "event" && frame.event.type === "agent_question") {
35654
36129
  const current = get18(db, agentId, frame.event.question.id);
@@ -35687,7 +36162,7 @@ function isUserFacingFrame(frame) {
35687
36162
  }
35688
36163
  function sendAgentMessage(db, input) {
35689
36164
  const attemptKind = input.attemptKind ?? "agent_tool";
35690
- const attemptId = input.attemptId ?? randomUUID29();
36165
+ const attemptId = input.attemptId ?? randomUUID30();
35691
36166
  const outcome = db.raw.transaction(
35692
36167
  () => {
35693
36168
  const causality = resolveMessageCausality(db, input);
@@ -36555,11 +37030,11 @@ async function readChangePatch(captured, base, change, patchBytes = REVIEW_LIMIT
36555
37030
  omitted: null
36556
37031
  };
36557
37032
  }
36558
- async function attachPatches(captured, report, limits = REVIEW_LIMITS, onlyPath) {
37033
+ async function attachPatches(captured, report2, limits = REVIEW_LIMITS, onlyPath) {
36559
37034
  let total = 0;
36560
37035
  let tooLarge = 0;
36561
37036
  const changes = [];
36562
- for (const change of report.changes) {
37037
+ for (const change of report2.changes) {
36563
37038
  if (onlyPath !== void 0 && change.path !== onlyPath) {
36564
37039
  changes.push(change);
36565
37040
  continue;
@@ -36572,7 +37047,7 @@ async function attachPatches(captured, report, limits = REVIEW_LIMITS, onlyPath)
36572
37047
  changes.push({ ...change, contentOmitted: "total_limit" });
36573
37048
  continue;
36574
37049
  }
36575
- const read = await readChangePatch(captured, report.base, change, limits.patchBytes);
37050
+ const read = await readChangePatch(captured, report2.base, change, limits.patchBytes);
36576
37051
  const bytes = read.patch ? Buffer.byteLength(read.patch) : 0;
36577
37052
  if (bytes > limits.fileBytes && !read.truncated) {
36578
37053
  tooLarge++;
@@ -36587,7 +37062,7 @@ async function attachPatches(captured, report, limits = REVIEW_LIMITS, onlyPath)
36587
37062
  contentOmitted: read.omitted
36588
37063
  });
36589
37064
  }
36590
- return { ...report, changes, withheld: { ...report.withheld, tooLarge } };
37065
+ return { ...report2, changes, withheld: { ...report2.withheld, tooLarge } };
36591
37066
  }
36592
37067
  async function readDiff(captured, base, args) {
36593
37068
  return captured.runGit(["diff", base.resolvedOid, ...args]);
@@ -37103,13 +37578,13 @@ var emptyGit = () => ({
37103
37578
  issues: []
37104
37579
  });
37105
37580
  async function inspectGit(ancestry) {
37106
- const report = emptyGit();
37581
+ const report2 = emptyGit();
37107
37582
  let capture2 = null;
37108
37583
  try {
37109
37584
  const root = findRepositoryRoot(ancestry);
37110
- if (!root) return report;
37111
- report.root = root.label;
37112
- report.state = "unavailable";
37585
+ if (!root) return report2;
37586
+ report2.root = root.label;
37587
+ report2.state = "unavailable";
37113
37588
  capture2 = await captureRepositoryGit(root);
37114
37589
  const output = await capture2.runGit([
37115
37590
  "status",
@@ -37125,32 +37600,32 @@ async function inspectGit(ancestry) {
37125
37600
  const line = records2[i] ?? "";
37126
37601
  if (line.startsWith("# branch.oid ")) {
37127
37602
  const oid = line.slice(13);
37128
- report.head = /^[0-9a-f]{40,64}$/.test(oid) ? oid : null;
37603
+ report2.head = /^[0-9a-f]{40,64}$/.test(oid) ? oid : null;
37129
37604
  } else if (line.startsWith("# branch.head ")) {
37130
37605
  const branch = line.slice(14);
37131
37606
  if (branch.length > 4096) throw new ContextReadError("git_output_limit");
37132
- report.branch = branch === "(detached)" ? null : branch;
37133
- } else if (line.startsWith("? ")) report.untracked++;
37134
- else if (line.startsWith("u ")) report.conflicted++;
37607
+ report2.branch = branch === "(detached)" ? null : branch;
37608
+ } else if (line.startsWith("? ")) report2.untracked++;
37609
+ else if (line.startsWith("u ")) report2.conflicted++;
37135
37610
  else if (line.startsWith("1 ") || line.startsWith("2 ")) {
37136
- if (line[2] !== ".") report.staged++;
37137
- if (line[3] !== ".") report.unstaged++;
37611
+ if (line[2] !== ".") report2.staged++;
37612
+ if (line[3] !== ".") report2.unstaged++;
37138
37613
  if (line.startsWith("2 ")) i++;
37139
37614
  }
37140
37615
  }
37141
- report.headState = report.head ? report.branch ? "branch" : "detached" : "unborn";
37142
- report.state = "available";
37616
+ report2.headState = report2.head ? report2.branch ? "branch" : "detached" : "unborn";
37617
+ report2.state = "available";
37143
37618
  } catch (error2) {
37144
- report.state = "unavailable";
37619
+ report2.state = "unavailable";
37145
37620
  const code = error2 instanceof ContextReadError ? error2.code : error2.code === "ENOENT" ? "git_missing" : error2.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER" ? "git_output_limit" : error2.killed || error2.code === "ETIMEDOUT" ? "git_timeout" : "git_inspection_failed";
37146
- report.issues.push({
37621
+ report2.issues.push({
37147
37622
  code,
37148
37623
  message: `Git inspection is unavailable (${code.replaceAll("_", " ")}); repository instructions are evaluated separately.`
37149
37624
  });
37150
37625
  } finally {
37151
37626
  capture2?.cleanup();
37152
37627
  }
37153
- return report;
37628
+ return report2;
37154
37629
  }
37155
37630
 
37156
37631
  // ../daemon/src/lib/repository-context/index.ts
@@ -37176,7 +37651,7 @@ function issue2(error2, path) {
37176
37651
  };
37177
37652
  }
37178
37653
  async function resolveRepositoryContext(input) {
37179
- const report = {
37654
+ const report2 = {
37180
37655
  version: 1,
37181
37656
  teamId: input.teamId,
37182
37657
  rootIdentity: null,
@@ -37190,9 +37665,9 @@ async function resolveRepositoryContext(input) {
37190
37665
  let root;
37191
37666
  try {
37192
37667
  root = new ContextDirectory(input.root);
37193
- report.rootIdentity = root.identity;
37668
+ report2.rootIdentity = root.identity;
37194
37669
  const parts = relativeParts(input.target ?? ".");
37195
- report.target = parts.join("/") || ".";
37670
+ report2.target = parts.join("/") || ".";
37196
37671
  if (input.expectedRootIdentity && root.identity !== input.expectedRootIdentity)
37197
37672
  throw new ContextReadError("root_changed");
37198
37673
  const ancestry = [root];
@@ -37220,17 +37695,17 @@ async function resolveRepositoryContext(input) {
37220
37695
  instructionBytes += bytes.length;
37221
37696
  if (instructionBytes > CONTEXT_LIMITS.instructionTotal)
37222
37697
  throw new ContextReadError("instruction_total_limit");
37223
- report.instructions.files.push({
37698
+ report2.instructions.files.push({
37224
37699
  path,
37225
37700
  scope: directory.label,
37226
- precedence: report.instructions.files.length,
37701
+ precedence: report2.instructions.files.length,
37227
37702
  content: decode3(bytes),
37228
37703
  sha256: hash3(bytes)
37229
37704
  });
37230
37705
  }
37231
37706
  } catch (error2) {
37232
- report.instructions.state = "incomplete";
37233
- report.instructions.issues.push(issue2(error2, path));
37707
+ report2.instructions.state = "incomplete";
37708
+ report2.instructions.issues.push(issue2(error2, path));
37234
37709
  }
37235
37710
  const memory = input.memoryPath ?? "memory";
37236
37711
  if (directory.label === memory || directory.label.startsWith(`${memory}/`) || directory.label.split("/").some((part) => discoveryExcluded.has(part)))
@@ -37247,14 +37722,14 @@ async function resolveRepositoryContext(input) {
37247
37722
  if (sourceBytes > CONTEXT_LIMITS.sourceTotal)
37248
37723
  throw new ContextReadError("source_total_limit");
37249
37724
  const sha256 = hash3(bytes);
37250
- report.commands.sources.push({ path: path2, sha256 });
37725
+ report2.commands.sources.push({ path: path2, sha256 });
37251
37726
  const content = decode3(bytes);
37252
37727
  const add2 = (candidate) => {
37253
- if (report.commands.candidates.length >= CONTEXT_LIMITS.candidates)
37728
+ if (report2.commands.candidates.length >= CONTEXT_LIMITS.candidates)
37254
37729
  throw new ContextReadError("candidate_limit");
37255
37730
  if (candidate.command.length > 4096 || candidate.location.length > 4096)
37256
37731
  throw new ContextReadError("command_limit");
37257
- report.commands.candidates.push({
37732
+ report2.commands.candidates.push({
37258
37733
  ...candidate,
37259
37734
  source: path2,
37260
37735
  sha256,
@@ -37301,50 +37776,50 @@ async function resolveRepositoryContext(input) {
37301
37776
  }
37302
37777
  }
37303
37778
  } catch (error2) {
37304
- report.commands.state = "incomplete";
37305
- report.commands.issues.push(issue2(error2, path2));
37779
+ report2.commands.state = "incomplete";
37780
+ report2.commands.issues.push(issue2(error2, path2));
37306
37781
  }
37307
37782
  }
37308
37783
  }
37309
- report.git = await inspectGit(ancestry);
37784
+ report2.git = await inspectGit(ancestry);
37310
37785
  root.validate(true, /* @__PURE__ */ new Set(["AGENTS.md"]));
37311
37786
  try {
37312
37787
  root.validate(true, new Set(sourceNames));
37313
37788
  } catch (error2) {
37314
- report.commands = { state: "incomplete", sources: [], candidates: [], issues: [issue2(error2)] };
37789
+ report2.commands = { state: "incomplete", sources: [], candidates: [], issues: [issue2(error2)] };
37315
37790
  }
37316
37791
  } catch (error2) {
37317
- report.instructions.state = "incomplete";
37318
- report.instructions.files = [];
37319
- report.instructions.issues.push(issue2(error2));
37320
- report.commands.state = "incomplete";
37321
- report.commands.sources = [];
37322
- report.commands.candidates = [];
37323
- report.commands.issues.push(issue2(error2));
37324
- report.git = { ...emptyGit(), state: "unavailable", issues: [issue2(error2)] };
37792
+ report2.instructions.state = "incomplete";
37793
+ report2.instructions.files = [];
37794
+ report2.instructions.issues.push(issue2(error2));
37795
+ report2.commands.state = "incomplete";
37796
+ report2.commands.sources = [];
37797
+ report2.commands.candidates = [];
37798
+ report2.commands.issues.push(issue2(error2));
37799
+ report2.git = { ...emptyGit(), state: "unavailable", issues: [issue2(error2)] };
37325
37800
  } finally {
37326
37801
  root?.close();
37327
37802
  }
37328
- if (Buffer.byteLength(JSON.stringify(report)) > CONTEXT_LIMITS.report - 128) {
37329
- report.instructions = {
37803
+ if (Buffer.byteLength(JSON.stringify(report2)) > CONTEXT_LIMITS.report - 128) {
37804
+ report2.instructions = {
37330
37805
  state: "incomplete",
37331
37806
  files: [],
37332
37807
  issues: [issue2(new ContextReadError("report_limit"))]
37333
37808
  };
37334
- report.commands = {
37809
+ report2.commands = {
37335
37810
  state: "incomplete",
37336
37811
  sources: [],
37337
37812
  candidates: [],
37338
37813
  issues: [issue2(new ContextReadError("report_limit"))]
37339
37814
  };
37340
37815
  }
37341
- report.fingerprint = hash3(JSON.stringify({ ...report, capturedAt: 0, fingerprint: "" }));
37342
- return report;
37816
+ report2.fingerprint = hash3(JSON.stringify({ ...report2, capturedAt: 0, fingerprint: "" }));
37817
+ return report2;
37343
37818
  }
37344
- function requireCompleteRepositoryContext(report) {
37345
- if (report.instructions.state !== "complete") {
37819
+ function requireCompleteRepositoryContext(report2) {
37820
+ if (report2.instructions.state !== "complete") {
37346
37821
  throw new Error(
37347
- `Repository instructions incomplete (${report.instructions.issues.map((i) => i.code).join(", ")}). Inspect Team repository context before coding.`
37822
+ `Repository instructions incomplete (${report2.instructions.issues.map((i) => i.code).join(", ")}). Inspect Team repository context before coding.`
37348
37823
  );
37349
37824
  }
37350
37825
  }
@@ -37371,14 +37846,14 @@ function createCodingHost(input) {
37371
37846
  input.assertActive();
37372
37847
  codingRelativePath(target);
37373
37848
  resolveCodingDirectory(input.root, target);
37374
- const report = await input.context(target);
37375
- requireCompleteRepositoryContext(report);
37849
+ const report2 = await input.context(target);
37850
+ requireCompleteRepositoryContext(report2);
37376
37851
  let fingerprint2 = null;
37377
37852
  const dir = new ContextDirectory(input.root);
37378
37853
  try {
37379
37854
  const sources2 = [
37380
- report.instructions.files.map((file) => [file.path, file.sha256]),
37381
- report.commands.sources,
37855
+ report2.instructions.files.map((file) => [file.path, file.sha256]),
37856
+ report2.commands.sources,
37382
37857
  input.values
37383
37858
  ];
37384
37859
  let current = dir;
@@ -37406,7 +37881,7 @@ function createCodingHost(input) {
37406
37881
  posture: input.posture,
37407
37882
  imageId: input.imageId,
37408
37883
  cwd: target,
37409
- rootIdentity: report.rootIdentity ?? "unavailable",
37884
+ rootIdentity: report2.rootIdentity ?? "unavailable",
37410
37885
  inputFingerprint: fingerprint2,
37411
37886
  capturedAt: Date.now(),
37412
37887
  restrictions: input.posture === "host" ? [
@@ -37463,7 +37938,7 @@ function createCodingHost(input) {
37463
37938
  try {
37464
37939
  const environment = await snapshot(command.cwd);
37465
37940
  const receipt = {
37466
- id: randomUUID30(),
37941
+ id: randomUUID31(),
37467
37942
  agentId: input.agentId,
37468
37943
  teamId: input.teamId,
37469
37944
  turnId: input.turnId,
@@ -37798,7 +38273,7 @@ function createDbMessagingHost(db, opts = {}) {
37798
38273
  }
37799
38274
 
37800
38275
  // ../daemon/src/lib/question-service.ts
37801
- import { randomUUID as randomUUID32 } from "crypto";
38276
+ import { randomUUID as randomUUID33 } from "crypto";
37802
38277
 
37803
38278
  // ../daemon/src/lib/question-consumption.ts
37804
38279
  import { isDeepStrictEqual } from "util";
@@ -38326,7 +38801,7 @@ function parseTelegramQuestionReply(db, authToken, update3) {
38326
38801
  }
38327
38802
 
38328
38803
  // ../daemon/src/lib/attachments.ts
38329
- import { randomUUID as randomUUID31 } from "crypto";
38804
+ import { randomUUID as randomUUID32 } from "crypto";
38330
38805
  import { closeSync as closeSync9, constants as constants10, fstatSync as fstatSync7, openSync as openSync9, writeFileSync as writeFileSync13 } from "fs";
38331
38806
  import { join as join26, posix } from "path";
38332
38807
  var MAX_FILE_BYTES = 25 * 1024 * 1024;
@@ -38353,7 +38828,7 @@ function saveInputFiles(agentDir, files, options = {}) {
38353
38828
  lines.push(`[attachment "${label}" skipped: too large (${fmtBytes(buf.byteLength)} > 25 MB)]`);
38354
38829
  continue;
38355
38830
  }
38356
- const filename2 = `${randomUUID31().slice(0, 8)}-${safeName(label)}`;
38831
+ const filename2 = `${randomUUID32().slice(0, 8)}-${safeName(label)}`;
38357
38832
  const path = join26(dir, filename2);
38358
38833
  let fd;
38359
38834
  try {
@@ -38685,9 +39160,11 @@ function deepFreezePreparedProtectedExecution(value, seen = /* @__PURE__ */ new
38685
39160
  // ../daemon/src/lib/turn-invocation.ts
38686
39161
  var trustedTurnBrand = /* @__PURE__ */ Symbol("bazilion.trusted-turn-invocation");
38687
39162
  var trustedReviewBrand = /* @__PURE__ */ Symbol("bazilion.trusted-review-invocation");
39163
+ var trustedVerificationBrand = /* @__PURE__ */ Symbol("bazilion.trusted-verification-invocation");
38688
39164
  var preclaimedTurnBrand = /* @__PURE__ */ Symbol("bazilion.preclaimed-turn");
38689
39165
  var trustedTurns = /* @__PURE__ */ new WeakSet();
38690
39166
  var trustedReviews = /* @__PURE__ */ new WeakSet();
39167
+ var trustedVerifications = /* @__PURE__ */ new WeakSet();
38691
39168
  var trustedClaims = /* @__PURE__ */ new WeakSet();
38692
39169
  var consumedClaims = /* @__PURE__ */ new WeakSet();
38693
39170
  function createPreclaimedTurn(input) {
@@ -38722,6 +39199,32 @@ function createTrustedReviewInvocation(value) {
38722
39199
  trustedReviews.add(candidate);
38723
39200
  return Object.freeze(candidate);
38724
39201
  }
39202
+ function createTrustedVerificationInvocation(value) {
39203
+ validateVerificationInvocation(value);
39204
+ const candidate = {
39205
+ ...value,
39206
+ authorization: Object.freeze({ ...value.authorization })
39207
+ };
39208
+ validateVerificationInvocation(candidate);
39209
+ Object.defineProperty(candidate, trustedVerificationBrand, { value: true });
39210
+ trustedVerifications.add(candidate);
39211
+ return Object.freeze(candidate);
39212
+ }
39213
+ function assertTrustedVerificationInvocation(value) {
39214
+ if (!isRecord2(value) || !trustedVerifications.has(value)) throw invalidInvocation();
39215
+ validateVerificationInvocation(value);
39216
+ }
39217
+ function validateVerificationInvocation(value) {
39218
+ if (!isRecord2(value)) throw invalidInvocation();
39219
+ assertExactKeys2(value, ["kind", "authorization", "bashApprovalMode"]);
39220
+ if (value.kind !== "restricted_verification" || value.bashApprovalMode !== "auto_deny" || !isRecord2(value.authorization)) {
39221
+ throw invalidInvocation();
39222
+ }
39223
+ assertExactKeys2(value.authorization, ["kind", "requestId", "attemptId"]);
39224
+ if (value.authorization.kind !== "request" || !isNonEmptyString2(value.authorization.requestId) || !isNonEmptyString2(value.authorization.attemptId)) {
39225
+ throw invalidInvocation();
39226
+ }
39227
+ }
38725
39228
  function executionSurfaceForInvocation(invocation) {
38726
39229
  return invocation.kind === "operator_http" && !process.env.BAZILION_PUBLIC_ORIGIN ? "configured_operator_http" : "protected";
38727
39230
  }
@@ -39170,7 +39673,7 @@ var QuestionService = class {
39170
39673
  turn.conversation.id
39171
39674
  ).length;
39172
39675
  this.#attached.add(turn);
39173
- const turnId = randomUUID32();
39676
+ const turnId = randomUUID33();
39174
39677
  const listeners = /* @__PURE__ */ new Set();
39175
39678
  if (onQuestion) listeners.add(onQuestion);
39176
39679
  this.#turns.set(turnId, {
@@ -41445,7 +41948,7 @@ async function* runAgentTurn(turn) {
41445
41948
  throw new Error("Repository context unavailable for this turn");
41446
41949
  contextBusy = true;
41447
41950
  try {
41448
- const report = await resolveRepositoryContext({
41951
+ const report2 = await resolveRepositoryContext({
41449
41952
  teamId: agent.team.id,
41450
41953
  root: agent.team.path,
41451
41954
  target,
@@ -41454,7 +41957,7 @@ async function* runAgentTurn(turn) {
41454
41957
  turn.controller.signal.throwIfAborted();
41455
41958
  if (!ownsActiveAgent(agent.agent.id, turn.controller))
41456
41959
  throw new Error("Repository context turn ended");
41457
- return report;
41960
+ return report2;
41458
41961
  } finally {
41459
41962
  contextBusy = false;
41460
41963
  }
@@ -42003,46 +42506,809 @@ async function dispatchClaimableReviews(now = Date.now()) {
42003
42506
  );
42004
42507
  }
42005
42508
 
42006
- // ../daemon/src/lib/scheduler.ts
42007
- var SCHEDULER_KEY = /* @__PURE__ */ Symbol.for("bazilion.scheduler");
42008
- var TICK_MS = Number(process.env.BAZILION_SCHEDULER_TICK_MS ?? 5e3);
42009
- function state2() {
42010
- const g2 = globalThis;
42011
- let s = g2[SCHEDULER_KEY];
42012
- if (!s) {
42013
- s = { timer: null, firing: /* @__PURE__ */ new Set(), cronCache: /* @__PURE__ */ new Map(), stopped: false };
42014
- g2[SCHEDULER_KEY] = s;
42015
- }
42016
- return s;
42017
- }
42018
- function floorToMinute(ms) {
42019
- return Math.floor(ms / 6e4) * 6e4;
42020
- }
42021
- function isDue(t, now, cronCache) {
42022
- if (!t.enabled) return false;
42023
- if (t.kind === "interval") {
42024
- const every = (t.intervalSec ?? 0) * 1e3;
42025
- if (every <= 0) return false;
42026
- const baseline = t.lastFiredAt ?? t.createdAt;
42027
- return now - baseline >= every;
42028
- }
42029
- if (t.kind === "cron") {
42030
- if (!t.cronExpr) return false;
42031
- let parsed = cronCache.get(t.cronExpr);
42032
- if (!parsed) {
42033
- try {
42034
- parsed = parseCron(t.cronExpr);
42035
- } catch {
42036
- return false;
42037
- }
42038
- cronCache.set(t.cronExpr, parsed);
42509
+ // ../daemon/src/lib/verification/admission.ts
42510
+ import { randomUUID as randomUUID34 } from "crypto";
42511
+ var VERIFICATION_LEASE_MS = 10 * 60 * 1e3;
42512
+ var VERIFICATION_DISPATCH_OWNER = randomUUID34();
42513
+ async function admitVerificationRequest(db, paths, requestId2, now = Date.now()) {
42514
+ const request2 = getVerificationRequestById(db, requestId2, now);
42515
+ if (!request2) return { kind: "deferred", requestId: requestId2, reason: "unknown_or_expired" };
42516
+ const blockedReason = async () => {
42517
+ const team = safeTeam(db, paths, request2.teamId);
42518
+ if (!team) return blocker("unsupported", "the request no longer names a known Team");
42519
+ const recipient = get(db, request2.recipientAgentId);
42520
+ if (!recipient || recipient.status === "archived") {
42521
+ return blocker("recipient_unavailable", "the selected specialist is missing or archived");
42522
+ }
42523
+ if (recipient.teamId !== team.id) {
42524
+ return blocker("recipient_not_same_team", "the selected specialist left this Team");
42525
+ }
42526
+ if (!getSourceSnapshot(db, team.id, request2.snapshotId, now)) {
42527
+ return blocker(
42528
+ "snapshot_evidence_gone",
42529
+ "the captured change is no longer inside its retention window"
42530
+ );
42039
42531
  }
42040
- const nowFloor = floorToMinute(now);
42041
- if (t.lastFiredAt && floorToMinute(t.lastFiredAt) === nowFloor) return false;
42042
- return matchesCron(parsed, new Date(nowFloor));
42532
+ return null;
42533
+ };
42534
+ const refusal = await blockedReason();
42535
+ if (refusal) {
42536
+ setRequestState(db, requestId2, "blocked");
42537
+ return { kind: "blocked", requestId: requestId2, blocker: refusal };
42538
+ }
42539
+ const decision = teamPolicyEnforcementEnabled() ? authorizeCommunication(db, authorizationFor(request2, requestId2)) : { decision: "allow" };
42540
+ if (decision.decision === "deny") {
42541
+ setRequestState(db, requestId2, "blocked");
42542
+ return {
42543
+ kind: "blocked",
42544
+ requestId: requestId2,
42545
+ blocker: blocker("policy_denied", "the current Team policy no longer permits this request")
42546
+ };
42043
42547
  }
42044
- return false;
42045
- }
42548
+ if (decision.decision === "approval_required") {
42549
+ try {
42550
+ if (request2.requesterKind === "agent" && request2.requesterAgentId) {
42551
+ authorizeVerificationRequest(db, {
42552
+ from: request2.requesterAgentId,
42553
+ to: request2.recipientAgentId,
42554
+ requestId: requestId2
42555
+ });
42556
+ } else {
42557
+ authorizeOperatorVerification(db, {
42558
+ agentId: request2.recipientAgentId,
42559
+ requestId: requestId2
42560
+ });
42561
+ }
42562
+ setRequestState(db, requestId2, "blocked");
42563
+ return {
42564
+ kind: "blocked",
42565
+ requestId: requestId2,
42566
+ blocker: blocker("approval_required", "the request was not captured for approval")
42567
+ };
42568
+ } catch {
42569
+ setRequestState(db, requestId2, "awaiting_approval");
42570
+ return { kind: "held", requestId: requestId2 };
42571
+ }
42572
+ }
42573
+ let workspace;
42574
+ try {
42575
+ const team = requireTeam(db, paths, request2.teamId);
42576
+ workspace = await workspaceLifecycle(db).claim(team.id, team.path, "agent");
42577
+ } catch (error2) {
42578
+ if (error2 instanceof WorkspaceBusyError) {
42579
+ return { kind: "deferred", requestId: requestId2, reason: "workspace_busy" };
42580
+ }
42581
+ throw error2;
42582
+ }
42583
+ const claim5 = claimVerificationAttempt(db, {
42584
+ requestId: requestId2,
42585
+ leaseOwner: VERIFICATION_DISPATCH_OWNER,
42586
+ leaseMs: VERIFICATION_LEASE_MS,
42587
+ now
42588
+ });
42589
+ if (!claim5) {
42590
+ await workspaceLifecycle(db).release(workspace);
42591
+ return { kind: "deferred", requestId: requestId2, reason: "already_owned" };
42592
+ }
42593
+ const applicability = await readSnapshotApplicability(
42594
+ db,
42595
+ paths,
42596
+ request2.teamId,
42597
+ request2.snapshotId
42598
+ );
42599
+ if (applicability.comparison !== "identical") {
42600
+ await workspaceLifecycle(db).release(workspace);
42601
+ const reason = applicability.comparison === "changed" ? "source_changed" : "source_unverifiable";
42602
+ const detail3 = applicability.comparison === "changed" ? "the workspace changed after the capture, so a fresh capture is required" : "the workspace could not be shown to match the captured change";
42603
+ settleUnstarted(db, claim5, detail3);
42604
+ setRequestState(db, requestId2, "blocked");
42605
+ return { kind: "blocked", requestId: requestId2, blocker: blocker(reason, detail3) };
42606
+ }
42607
+ return { kind: "admitted", requestId: requestId2, claim: claim5, workspace };
42608
+ }
42609
+ function authorizationFor(request2, requestId2) {
42610
+ const attempt = {
42611
+ origin: "verification_request",
42612
+ attemptKind: "verification_request",
42613
+ attemptId: requestId2
42614
+ };
42615
+ return request2.requesterKind === "agent" && request2.requesterAgentId ? {
42616
+ source: { kind: "agent", id: request2.requesterAgentId },
42617
+ target: { kind: "agent", id: request2.recipientAgentId },
42618
+ ...attempt
42619
+ } : {
42620
+ source: { kind: "user", teamId: request2.teamId },
42621
+ target: { kind: "agent", id: request2.recipientAgentId },
42622
+ ...attempt
42623
+ };
42624
+ }
42625
+ function settleUnstarted(db, claim5, error2) {
42626
+ db.raw.run(
42627
+ `UPDATE verification_attempts
42628
+ SET state = 'failed', finished_at = ?, lease_owner = NULL, lease_expires_at = NULL, error = ?
42629
+ WHERE id = ? AND lease_owner IS NOT NULL AND finished_at IS NULL`,
42630
+ [Date.now(), error2, claim5.attempt.id]
42631
+ );
42632
+ db.raw.run(
42633
+ `UPDATE verification_check_outcomes SET state = 'blocked', finished_at = ?
42634
+ WHERE attempt_id = ? AND state = 'not_executed'`,
42635
+ [Date.now(), claim5.attempt.id]
42636
+ );
42637
+ }
42638
+ function blocker(reason, detail3) {
42639
+ return { reason, detail: detail3 };
42640
+ }
42641
+ function safeTeam(db, paths, teamId) {
42642
+ try {
42643
+ return requireTeam(db, paths, teamId);
42644
+ } catch {
42645
+ return null;
42646
+ }
42647
+ }
42648
+
42649
+ // ../daemon/src/lib/verification/executor.ts
42650
+ import { randomUUID as randomUUID35 } from "crypto";
42651
+ import { createLocalBashOperations as createLocalBashOperations3 } from "@earendil-works/pi-coding-agent";
42652
+ function createProtectedCheckExecutor(input) {
42653
+ const env = input.env ?? process.env;
42654
+ return {
42655
+ async run({ command, cwd, timeoutMs }) {
42656
+ const config2 = resolveShellSecurityConfig(env);
42657
+ const wantsContainer = input.request.environment.sandbox === "docker";
42658
+ const isContainer = config2.sandboxMode === "docker";
42659
+ if (wantsContainer !== isContainer) {
42660
+ return blocked(
42661
+ "environment_unavailable",
42662
+ wantsContainer ? "this request was captured against a container, but shell isolation is not active" : "this request was captured for host execution, but shell isolation is active"
42663
+ );
42664
+ }
42665
+ if (config2.approvalMode === "dangerous" && classifyBashCommand(command).length > 0) {
42666
+ return blocked(
42667
+ "approval_required",
42668
+ "this check needs a command approval that an unattended verification turn cannot obtain"
42669
+ );
42670
+ }
42671
+ const relative8 = codingRelativePath(cwd || ".");
42672
+ const { path: absoluteCwd } = resolveCodingDirectory(input.teamPath, relative8);
42673
+ const secrets = input.secrets();
42674
+ if (secrets.some((secret) => secret && command.includes(secret))) {
42675
+ return blocked("unsupported", "the captured command contains protected credential material");
42676
+ }
42677
+ const commandId = randomUUID35();
42678
+ const startedAt = Date.now();
42679
+ const receipt = {
42680
+ id: commandId,
42681
+ agentId: input.request.recipientAgentId,
42682
+ teamId: input.request.teamId,
42683
+ turnId: input.attemptId,
42684
+ toolCallId: `verification:${input.attemptId}:${randomUUID35()}`,
42685
+ input: {
42686
+ command,
42687
+ cwd: relative8,
42688
+ purpose: "verification",
42689
+ timeoutSeconds: Math.max(1, Math.round(timeoutMs / 1e3))
42690
+ },
42691
+ environment: {
42692
+ posture: "protected",
42693
+ imageId: isContainer ? input.request.environment.image : null,
42694
+ cwd: relative8,
42695
+ rootIdentity: workspaceIdentity(input.teamPath).rootIdentity,
42696
+ // No repository-context fingerprint is computed for a verification check, so it is absent
42697
+ // rather than invented. Unknown applicability is reported as unknown.
42698
+ inputFingerprint: null,
42699
+ capturedAt: startedAt,
42700
+ // Declared output paths name where a check is expected to write; they do not confine it in
42701
+ // host mode, and the receipt must not imply otherwise. Any write still makes the tree differ
42702
+ // from the captured snapshot, which is reported as `changed` rather than as a pass.
42703
+ restrictions: [
42704
+ ...isContainer ? ["network_disabled", "read_only_memory"] : [],
42705
+ "declared_output_paths_are_advisory"
42706
+ ]
42707
+ },
42708
+ startedAt,
42709
+ finishedAt: null,
42710
+ state: "running",
42711
+ exitCode: null,
42712
+ diagnostic: "",
42713
+ truncated: false,
42714
+ reason: null,
42715
+ sourceBefore: {
42716
+ id: input.request.snapshotId,
42717
+ complete: input.request.snapshotComplete,
42718
+ capturedAt: input.request.createdAt
42719
+ },
42720
+ sourceAfter: null
42721
+ };
42722
+ saveCodingCommand(input.db, receipt);
42723
+ let observed = "";
42724
+ let observedBytes = 0;
42725
+ let truncatedStream = false;
42726
+ const operations = buildOperations(input, env, config2.envAllowlist);
42727
+ const hostEnv = {
42728
+ ...buildScrubbedShellEnv(env, config2.envAllowlist),
42729
+ ...input.request.environment.env ?? {}
42730
+ };
42731
+ let exitCode = null;
42732
+ let failure;
42733
+ try {
42734
+ const result = await operations.exec(command, absoluteCwd, {
42735
+ signal: input.signal,
42736
+ timeout: timeoutMs,
42737
+ // Host mode runs with the scrubbed environment above; container mode supplies its own.
42738
+ ...isContainer ? {} : { env: hostEnv },
42739
+ onData: (chunk) => {
42740
+ if (observedBytes >= CODING_OUTPUT_BYTES * 4) return;
42741
+ const text3 = chunk.toString("utf8");
42742
+ observed += text3;
42743
+ observedBytes += Buffer.byteLength(text3);
42744
+ }
42745
+ });
42746
+ exitCode = result.exitCode;
42747
+ if (observedBytes > CODING_OUTPUT_BYTES) truncatedStream = true;
42748
+ } catch (error2) {
42749
+ failure = error2;
42750
+ }
42751
+ const finishedAt = Date.now();
42752
+ const redaction = redactJsonValue(observed, secrets);
42753
+ const redacted = redaction !== observed;
42754
+ const tail = diagnosticTail(redaction, CODING_OUTPUT_BYTES);
42755
+ const state3 = resolveState(exitCode, failure, input.signal);
42756
+ receipt.finishedAt = finishedAt;
42757
+ receipt.state = state3;
42758
+ receipt.exitCode = state3 === "succeeded" || state3 === "failed" ? exitCode : null;
42759
+ receipt.diagnostic = tail.text;
42760
+ receipt.truncated = truncatedStream || tail.truncated;
42761
+ receipt.reason = state3 === "blocked" ? "check could not start" : state3 === "timed_out" ? "check exceeded its captured timeout" : state3 === "cancelled" ? "check was cancelled with its turn" : null;
42762
+ saveCodingCommand(input.db, receipt);
42763
+ saveCodingCommandLog(input.db, {
42764
+ commandId,
42765
+ teamId: input.request.teamId,
42766
+ agentId: input.request.recipientAgentId,
42767
+ turnId: input.attemptId,
42768
+ toolCallId: receipt.toolCallId,
42769
+ diagnostic: redaction,
42770
+ observedBytes,
42771
+ redacted,
42772
+ truncated: receipt.truncated
42773
+ });
42774
+ if (state3 === "blocked") {
42775
+ return blocked(
42776
+ "unsupported",
42777
+ failure instanceof Error ? failure.message : "the captured check could not start"
42778
+ );
42779
+ }
42780
+ return {
42781
+ commandId,
42782
+ state: state3,
42783
+ exitCode: state3 === "succeeded" || state3 === "failed" ? exitCode : null,
42784
+ output: tail.text,
42785
+ truncated: receipt.truncated
42786
+ };
42787
+ }
42788
+ };
42789
+ }
42790
+ function buildOperations(input, env, envAllowlist) {
42791
+ if (input.request.environment.sandbox !== "docker") return createLocalBashOperations3();
42792
+ return createDockerBashOperations({
42793
+ image: input.request.environment.image,
42794
+ env: buildSandboxContainerEnv(env, envAllowlist)
42795
+ });
42796
+ }
42797
+ function resolveState(exitCode, failure, signal) {
42798
+ if (signal?.aborted) return "cancelled";
42799
+ if (failure) return "blocked";
42800
+ if (exitCode === null) return "timed_out";
42801
+ return exitCode === 0 ? "succeeded" : "failed";
42802
+ }
42803
+ function blocked(reason, detail3) {
42804
+ return {
42805
+ commandId: null,
42806
+ state: "blocked",
42807
+ exitCode: null,
42808
+ output: detail3,
42809
+ truncated: false,
42810
+ blocker: { reason, detail: detail3 }
42811
+ };
42812
+ }
42813
+
42814
+ // ../daemon/src/lib/verification/preparation.ts
42815
+ async function prepareVerificationTurn(input) {
42816
+ const { db, paths, authToken } = getCtx();
42817
+ const resolved = resolveAgent(db, paths, input.request.recipientAgentId);
42818
+ if (resolved.agent.id !== input.request.recipientAgentId) {
42819
+ throw new Error("verification request does not match the resolved specialist");
42820
+ }
42821
+ const invocation = createTrustedVerificationInvocation({
42822
+ kind: "restricted_verification",
42823
+ authorization: {
42824
+ kind: "request",
42825
+ requestId: input.request.id,
42826
+ attemptId: input.attemptId
42827
+ },
42828
+ bashApprovalMode: "auto_deny"
42829
+ });
42830
+ assertTrustedVerificationInvocation(invocation);
42831
+ const provider = await resolveProtectedProviderRuntime(
42832
+ db,
42833
+ authToken,
42834
+ resolved,
42835
+ resolved.agent.reasoningLevel
42836
+ );
42837
+ return {
42838
+ invocation,
42839
+ spec: {
42840
+ kind: "specialist_verification",
42841
+ agentId: input.request.recipientAgentId,
42842
+ message: verificationPrompt(input.request),
42843
+ turnId: input.attemptId,
42844
+ runtime: provider.runtime,
42845
+ verification: { requestId: input.request.id, attemptId: input.attemptId }
42846
+ },
42847
+ refreshApiKey: provider.refreshApiKey
42848
+ };
42849
+ }
42850
+ function verificationPrompt(request2) {
42851
+ return `Verify the captured change for verification request ${request2.id}.
42852
+
42853
+ Call verification_request to read the captured change, its environment and the checks your requester selected. Then run each declared check with verification_check, using its ordinal. Each check runs once; report failures as failures and blockers as blockers.`;
42854
+ }
42855
+ function bindVerificationCapability(host2, identity2) {
42856
+ const assertBound = (requestId2, attemptId) => {
42857
+ if (requestId2 !== identity2.requestId || attemptId !== identity2.attemptId) {
42858
+ throw new Error("verification capability is bound to a different request attempt");
42859
+ }
42860
+ };
42861
+ return {
42862
+ read: async (requestId2, attemptId) => {
42863
+ assertBound(requestId2, attemptId);
42864
+ return host2.read();
42865
+ },
42866
+ run: async (requestId2, attemptId, ordinal) => {
42867
+ assertBound(requestId2, attemptId);
42868
+ return host2.invoke(ordinal);
42869
+ }
42870
+ };
42871
+ }
42872
+ function executePreparedVerification(prepared, opts) {
42873
+ assertTrustedVerificationInvocation(prepared.invocation);
42874
+ return spawnVerificationWorker(prepared.spec, {
42875
+ signal: opts.signal,
42876
+ apiKeyRefreshHost: { refresh: prepared.refreshApiKey },
42877
+ verificationHost: opts.verificationHost,
42878
+ ...opts.workerEntryPath ? { workerEntryPath: opts.workerEntryPath } : {}
42879
+ });
42880
+ }
42881
+
42882
+ // ../daemon/src/lib/verification/result.ts
42883
+ var MAX_RESULT_CHARACTERS = 4e3;
42884
+ function deliverVerificationResult(input) {
42885
+ const { request: request2 } = input;
42886
+ if (request2.requesterKind !== "agent" || !request2.requesterAgentId) return false;
42887
+ const payload = renderResult(input);
42888
+ try {
42889
+ sendAgentMessage(input.db, {
42890
+ from: request2.recipientAgentId,
42891
+ to: request2.requesterAgentId,
42892
+ payload,
42893
+ origin: "verification_result",
42894
+ attemptKind: "verification_result",
42895
+ // Per attempt, not per request: a rerun's result is its own delivery, and reusing the request id
42896
+ // would collide with the first attempt's approval identity if the edge requires approval.
42897
+ attemptId: `${request2.id}:${input.attempt.id}`
42898
+ });
42899
+ return true;
42900
+ } catch (error2) {
42901
+ console.warn(
42902
+ JSON.stringify({
42903
+ event: "verification_result_not_delivered",
42904
+ requestId: request2.id,
42905
+ errorName: error2 instanceof Error ? error2.name : "unknown"
42906
+ })
42907
+ );
42908
+ return false;
42909
+ }
42910
+ }
42911
+ function renderResult(input) {
42912
+ const { request: request2, attempt } = input;
42913
+ const checks = listVerificationChecks(input.db, request2.id);
42914
+ const outcomes = new Map(
42915
+ listVerificationCheckOutcomes(input.db, attempt.id).map((outcome) => [
42916
+ outcome.ordinal,
42917
+ outcome
42918
+ ])
42919
+ );
42920
+ const lines = [
42921
+ `Verification ${request2.id}: ${input.outcome}.`,
42922
+ `Change: snapshot ${request2.snapshotId} (base ${request2.baseOid.slice(0, 12)}${request2.snapshotComplete ? "" : ", INCOMPLETE COVERAGE"}).`,
42923
+ `Environment: image ${request2.environment.image}, shell ${request2.environment.sandbox}.`,
42924
+ input.applicability === null ? "Applicability: not checked." : `Applicability: ${input.applicability === "identical" ? "unchanged since capture" : input.applicability}.`,
42925
+ "",
42926
+ "Checks:"
42927
+ ];
42928
+ for (const check of checks) {
42929
+ const outcome = outcomes.get(check.ordinal);
42930
+ const state3 = outcome?.state ?? "not_executed";
42931
+ const exit = outcome?.exitCode === null || outcome?.exitCode === void 0 ? "" : ` exit ${outcome.exitCode}`;
42932
+ const receipt = outcome?.commandId ? ` coding-receipt:${outcome.commandId}` : outcome && ["succeeded", "failed", "timed_out", "cancelled"].includes(outcome.state) ? " (receipt no longer available)" : "";
42933
+ lines.push(` [${check.ordinal}] ${state3}${exit} \u2014 ${check.command}${receipt}`);
42934
+ }
42935
+ if (attempt.error) lines.push("", `Limitation: ${attempt.error}`);
42936
+ lines.push(
42937
+ "",
42938
+ "Facts above are executor-owned. A non-zero exit is a result about the commands that ran, never",
42939
+ "proof about later code, and this is not an approval to publish, merge or deploy."
42940
+ );
42941
+ const payload = lines.join("\n");
42942
+ return payload.length > MAX_RESULT_CHARACTERS ? `${payload.slice(0, MAX_RESULT_CHARACTERS)}
42943
+ [result truncated]` : payload;
42944
+ }
42945
+
42946
+ // ../daemon/src/runtime/tools/verification.ts
42947
+ var VerificationCapabilityError = class extends Error {
42948
+ constructor(message) {
42949
+ super(message);
42950
+ this.name = "VerificationCapabilityError";
42951
+ }
42952
+ };
42953
+
42954
+ // ../daemon/src/lib/verification/runner.ts
42955
+ function createVerificationHost(input) {
42956
+ const { db, request: request2, attemptId, executor } = input;
42957
+ return {
42958
+ async read() {
42959
+ const declared = listVerificationChecks(db, request2.id);
42960
+ const outcomes = new Map(
42961
+ listVerificationCheckOutcomes(db, attemptId).map((outcome) => [outcome.ordinal, outcome])
42962
+ );
42963
+ const checks = declared.map((check) => {
42964
+ const outcome = outcomes.get(check.ordinal);
42965
+ return {
42966
+ ordinal: check.ordinal,
42967
+ command: check.command,
42968
+ cwd: check.cwd,
42969
+ purpose: check.purpose,
42970
+ timeoutMs: check.timeoutMs,
42971
+ state: outcome?.state ?? "not_executed",
42972
+ commandId: outcome?.commandId ?? null,
42973
+ exitCode: outcome?.exitCode ?? null
42974
+ };
42975
+ });
42976
+ return {
42977
+ requestId: request2.id,
42978
+ summary: request2.summary,
42979
+ snapshot: {
42980
+ id: request2.snapshotId,
42981
+ complete: request2.snapshotComplete,
42982
+ head: request2.head,
42983
+ baseOid: request2.baseOid
42984
+ },
42985
+ environment: {
42986
+ image: request2.environment.image,
42987
+ sandbox: request2.environment.sandbox,
42988
+ ...request2.environment.cwd ? { cwd: request2.environment.cwd } : {}
42989
+ },
42990
+ writablePaths: request2.environment.writablePaths ?? [],
42991
+ checks,
42992
+ applicability: input.applicability
42993
+ };
42994
+ },
42995
+ async invoke(ordinal) {
42996
+ const declared = listVerificationChecks(db, request2.id).find(
42997
+ (check) => check.ordinal === ordinal
42998
+ );
42999
+ if (!declared) {
43000
+ throw new VerificationCapabilityError(`check ${ordinal} was not captured with this request`);
43001
+ }
43002
+ const settled = listVerificationCheckOutcomes(db, attemptId).find(
43003
+ (outcome) => outcome.ordinal === ordinal
43004
+ );
43005
+ if (settled && settled.state !== "not_executed") {
43006
+ throw new VerificationCapabilityError(
43007
+ `check ${ordinal} already reported '${settled.state}' and cannot be run again`
43008
+ );
43009
+ }
43010
+ const startedAt = Date.now();
43011
+ let result;
43012
+ try {
43013
+ result = await executor.run({
43014
+ command: declared.command,
43015
+ cwd: declared.cwd,
43016
+ timeoutMs: declared.timeoutMs,
43017
+ purpose: "verification",
43018
+ writablePaths: request2.environment.writablePaths ?? []
43019
+ });
43020
+ } catch (error2) {
43021
+ throw error2 instanceof Error ? error2 : new Error("verification check failed to start");
43022
+ }
43023
+ const state3 = normalizeState(result.state);
43024
+ if (state3 !== "blocked" && !result.commandId) {
43025
+ throw new VerificationCapabilityError(
43026
+ `a ${state3} check must report the receipt that produced it`
43027
+ );
43028
+ }
43029
+ const recorded = recordVerificationCheckOutcome(db, {
43030
+ attemptId,
43031
+ ordinal,
43032
+ state: state3,
43033
+ commandId: state3 === "blocked" ? null : result.commandId,
43034
+ exitCode: state3 === "succeeded" || state3 === "failed" ? result.exitCode : null,
43035
+ startedAt,
43036
+ finishedAt: Date.now()
43037
+ });
43038
+ if (!recorded) {
43039
+ throw new VerificationCapabilityError(`check ${ordinal} was already settled`);
43040
+ }
43041
+ return {
43042
+ ordinal,
43043
+ state: state3,
43044
+ commandId: state3 === "blocked" ? null : result.commandId,
43045
+ exitCode: state3 === "succeeded" || state3 === "failed" ? result.exitCode : null,
43046
+ output: result.output,
43047
+ truncated: result.truncated
43048
+ };
43049
+ }
43050
+ };
43051
+ }
43052
+ function normalizeState(state3) {
43053
+ return state3;
43054
+ }
43055
+ function settleVerificationAttempt(db, input) {
43056
+ const now = input.now ?? Date.now();
43057
+ const owned = db.raw.query(
43058
+ `SELECT id FROM verification_attempts
43059
+ WHERE id = ? AND lease_owner = ? AND finished_at IS NULL`
43060
+ ).get(input.attemptId, input.leaseOwner);
43061
+ if (!owned) return "uncertain";
43062
+ const declared = listVerificationChecks(db, input.requestId);
43063
+ const outcomes = new Map(
43064
+ listVerificationCheckOutcomes(db, input.attemptId).map((outcome) => [outcome.ordinal, outcome])
43065
+ );
43066
+ for (const check of declared) {
43067
+ const outcome = outcomes.get(check.ordinal);
43068
+ if (!outcome || outcome.state === "not_executed") {
43069
+ db.raw.run(
43070
+ `UPDATE verification_check_outcomes SET state = 'skipped', finished_at = ?
43071
+ WHERE attempt_id = ? AND ordinal = ? AND state = 'not_executed'`,
43072
+ [now, input.attemptId, check.ordinal]
43073
+ );
43074
+ }
43075
+ }
43076
+ const settled = listVerificationCheckOutcomes(db, input.attemptId);
43077
+ const executed = settled.filter(
43078
+ (outcome) => ["succeeded", "failed"].includes(outcome.state)
43079
+ ).length;
43080
+ const state3 = executed > 0 ? "completed" : "failed";
43081
+ const error2 = state3 === "failed" ? "no captured check executed" : null;
43082
+ const finished = finishVerificationAttempt(db, {
43083
+ attemptId: input.attemptId,
43084
+ leaseOwner: input.leaseOwner,
43085
+ state: state3,
43086
+ error: error2,
43087
+ now
43088
+ });
43089
+ if (!finished) {
43090
+ return "uncertain";
43091
+ }
43092
+ setRequestState(db, input.requestId, state3);
43093
+ return state3;
43094
+ }
43095
+ function abandonVerificationAttempt(db, input) {
43096
+ const now = input.now ?? Date.now();
43097
+ const finished = finishVerificationAttempt(db, {
43098
+ attemptId: input.attemptId,
43099
+ leaseOwner: input.leaseOwner,
43100
+ state: input.state,
43101
+ error: input.error,
43102
+ now
43103
+ });
43104
+ if (!finished) return false;
43105
+ db.raw.run(
43106
+ `UPDATE verification_check_outcomes
43107
+ SET state = 'unknown', finished_at = ?
43108
+ WHERE attempt_id = ? AND state = 'not_executed'`,
43109
+ [now, input.attemptId]
43110
+ );
43111
+ setRequestState(db, input.requestId, input.state);
43112
+ return true;
43113
+ }
43114
+
43115
+ // ../daemon/src/lib/verification/dispatch.ts
43116
+ var DISPATCH_REGISTRY_KEY = /* @__PURE__ */ Symbol.for("bazilion.verification.dispatch");
43117
+ function dispatchRegistry() {
43118
+ const host2 = globalThis;
43119
+ host2[DISPATCH_REGISTRY_KEY] ??= { controllers: /* @__PURE__ */ new Map() };
43120
+ return host2[DISPATCH_REGISTRY_KEY];
43121
+ }
43122
+ function cancelVerificationDispatch(requestId2) {
43123
+ const controller = dispatchRegistry().controllers.get(requestId2);
43124
+ if (!controller) return false;
43125
+ controller.abort();
43126
+ return true;
43127
+ }
43128
+ async function dispatchVerificationRequest(requestId2, opts = {}) {
43129
+ const { db, paths } = getCtx();
43130
+ const request2 = getVerificationRequestById(db, requestId2);
43131
+ if (!request2) return "not_dispatchable";
43132
+ if (isActiveAgent(request2.recipientAgentId)) return "agent_busy";
43133
+ const releaseLease = await acquireAgentLifecycleLease(request2.recipientAgentId);
43134
+ const controller = new AbortController();
43135
+ let registered = false;
43136
+ try {
43137
+ if (isActiveAgent(request2.recipientAgentId)) return "agent_busy";
43138
+ registerAgent(request2.recipientAgentId, controller);
43139
+ registered = true;
43140
+ } finally {
43141
+ releaseLease();
43142
+ }
43143
+ if (opts.signal) opts.signal.addEventListener("abort", () => controller.abort(), { once: true });
43144
+ dispatchRegistry().controllers.set(requestId2, controller);
43145
+ let admission;
43146
+ try {
43147
+ admission = await admitVerificationRequest(db, paths, requestId2);
43148
+ if (admission.kind !== "admitted") return "not_dispatchable";
43149
+ const admitted = admission;
43150
+ const live2 = getVerificationRequest(db, request2.teamId, requestId2);
43151
+ if (!live2) {
43152
+ await workspaceLifecycle(db).release(admitted.workspace);
43153
+ settleVerificationAttempt(db, {
43154
+ attemptId: admitted.claim.attempt.id,
43155
+ requestId: requestId2,
43156
+ leaseOwner: VERIFICATION_DISPATCH_OWNER
43157
+ });
43158
+ return "settled";
43159
+ }
43160
+ const prepared = await prepareVerificationTurn({
43161
+ request: live2,
43162
+ attemptId: admitted.claim.attempt.id
43163
+ });
43164
+ const capability = bindVerificationCapability(
43165
+ createVerificationHost({
43166
+ db,
43167
+ request: live2,
43168
+ attemptId: admitted.claim.attempt.id,
43169
+ applicability: "identical",
43170
+ executor: createProtectedCheckExecutor({
43171
+ db,
43172
+ paths,
43173
+ request: live2,
43174
+ attemptId: admitted.claim.attempt.id,
43175
+ teamPath: paths.teamDir(live2.teamId),
43176
+ secrets: () => currentSecrets(),
43177
+ signal: controller.signal
43178
+ })
43179
+ }),
43180
+ { requestId: requestId2, attemptId: admitted.claim.attempt.id }
43181
+ );
43182
+ let failure = null;
43183
+ for await (const frame of executePreparedVerification(prepared, {
43184
+ verificationHost: capability,
43185
+ signal: controller.signal,
43186
+ ...opts.workerEntryPath ? { workerEntryPath: opts.workerEntryPath } : {}
43187
+ })) {
43188
+ if (frame.kind === "fatal") failure ??= frame.error;
43189
+ else if (frame.kind === "event" && frame.event.type === "error") failure ??= frame.event.error;
43190
+ }
43191
+ if (controller.signal.aborted) {
43192
+ const abandoned = abandonVerificationAttempt(db, {
43193
+ attemptId: admitted.claim.attempt.id,
43194
+ requestId: requestId2,
43195
+ leaseOwner: VERIFICATION_DISPATCH_OWNER,
43196
+ state: "cancelled",
43197
+ error: "verification was cancelled before it reported"
43198
+ });
43199
+ if (abandoned) await handBackResult(db, paths, requestId2, "cancelled");
43200
+ return "settled";
43201
+ }
43202
+ if (failure) {
43203
+ const abandoned = abandonVerificationAttempt(db, {
43204
+ attemptId: admitted.claim.attempt.id,
43205
+ requestId: requestId2,
43206
+ leaseOwner: VERIFICATION_DISPATCH_OWNER,
43207
+ state: "failed",
43208
+ error: failure
43209
+ });
43210
+ if (abandoned) await handBackResult(db, paths, requestId2, "failed");
43211
+ return "settled";
43212
+ }
43213
+ const settled = settleVerificationAttempt(db, {
43214
+ attemptId: admitted.claim.attempt.id,
43215
+ requestId: requestId2,
43216
+ leaseOwner: VERIFICATION_DISPATCH_OWNER
43217
+ });
43218
+ if (settled !== "uncertain") await handBackResult(db, paths, requestId2, settled);
43219
+ return "dispatched";
43220
+ } catch (error2) {
43221
+ if (admission?.kind === "admitted") {
43222
+ abandonVerificationAttempt(db, {
43223
+ attemptId: admission.claim.attempt.id,
43224
+ requestId: requestId2,
43225
+ leaseOwner: VERIFICATION_DISPATCH_OWNER,
43226
+ state: controller.signal.aborted ? "cancelled" : "failed",
43227
+ error: protectedFailureMessage(error2, "Verification")
43228
+ });
43229
+ }
43230
+ return "settled";
43231
+ } finally {
43232
+ if (admission?.kind === "admitted") await workspaceLifecycle(db).release(admission.workspace);
43233
+ dispatchRegistry().controllers.delete(requestId2);
43234
+ if (registered) unregisterAgent(request2.recipientAgentId);
43235
+ }
43236
+ }
43237
+ async function handBackResult(db, paths, requestId2, outcome) {
43238
+ const request2 = getVerificationRequestById(db, requestId2);
43239
+ if (!request2) return;
43240
+ const attempt = listVerificationAttempts(db, requestId2).at(-1);
43241
+ if (!attempt) return;
43242
+ let applicability = null;
43243
+ try {
43244
+ const comparison = await readSnapshotApplicability(
43245
+ db,
43246
+ paths,
43247
+ request2.teamId,
43248
+ request2.snapshotId
43249
+ );
43250
+ applicability = comparison.comparison;
43251
+ } catch {
43252
+ applicability = null;
43253
+ }
43254
+ deliverVerificationResult({ db, paths, request: request2, attempt, outcome, applicability });
43255
+ }
43256
+ async function dispatchPendingVerifications(now = Date.now()) {
43257
+ const { db, paths } = getCtx();
43258
+ pruneVerificationRequests(db, now);
43259
+ const pending = db.raw.query(
43260
+ `SELECT id FROM verification_requests
43261
+ WHERE state = 'pending' AND expires_at > ?
43262
+ ORDER BY created_at LIMIT 20`
43263
+ ).all(now);
43264
+ void paths;
43265
+ await Promise.allSettled(pending.map((row) => dispatchVerificationRequest(row.id)));
43266
+ }
43267
+ function currentSecrets() {
43268
+ const { db, authToken } = getCtx();
43269
+ return codingSecrets(mergeSecretsIntoEnv(db, authToken));
43270
+ }
43271
+
43272
+ // ../daemon/src/lib/scheduler.ts
43273
+ var SCHEDULER_KEY = /* @__PURE__ */ Symbol.for("bazilion.scheduler");
43274
+ var TICK_MS = Number(process.env.BAZILION_SCHEDULER_TICK_MS ?? 5e3);
43275
+ function state2() {
43276
+ const g2 = globalThis;
43277
+ let s = g2[SCHEDULER_KEY];
43278
+ if (!s) {
43279
+ s = { timer: null, firing: /* @__PURE__ */ new Set(), cronCache: /* @__PURE__ */ new Map(), stopped: false };
43280
+ g2[SCHEDULER_KEY] = s;
43281
+ }
43282
+ return s;
43283
+ }
43284
+ function floorToMinute(ms) {
43285
+ return Math.floor(ms / 6e4) * 6e4;
43286
+ }
43287
+ function isDue(t, now, cronCache) {
43288
+ if (!t.enabled) return false;
43289
+ if (t.kind === "interval") {
43290
+ const every = (t.intervalSec ?? 0) * 1e3;
43291
+ if (every <= 0) return false;
43292
+ const baseline = t.lastFiredAt ?? t.createdAt;
43293
+ return now - baseline >= every;
43294
+ }
43295
+ if (t.kind === "cron") {
43296
+ if (!t.cronExpr) return false;
43297
+ let parsed = cronCache.get(t.cronExpr);
43298
+ if (!parsed) {
43299
+ try {
43300
+ parsed = parseCron(t.cronExpr);
43301
+ } catch {
43302
+ return false;
43303
+ }
43304
+ cronCache.set(t.cronExpr, parsed);
43305
+ }
43306
+ const nowFloor = floorToMinute(now);
43307
+ if (t.lastFiredAt && floorToMinute(t.lastFiredAt) === nowFloor) return false;
43308
+ return matchesCron(parsed, new Date(nowFloor));
43309
+ }
43310
+ return false;
43311
+ }
42046
43312
  function scheduledOccurrence(t, now) {
42047
43313
  if (t.kind === "cron") return floorToMinute(now);
42048
43314
  const baseline = t.lastFiredAt ?? t.createdAt;
@@ -42404,6 +43670,7 @@ async function tick() {
42404
43670
  work.push(fireInboxWake(agentId));
42405
43671
  }
42406
43672
  work.push(dispatchClaimableReviews(now));
43673
+ work.push(dispatchPendingVerifications(now));
42407
43674
  await Promise.allSettled(work);
42408
43675
  }
42409
43676
  function startScheduler() {
@@ -42463,6 +43730,7 @@ function bootstrap(paths) {
42463
43730
  recoverInterrupted2(db);
42464
43731
  recoverInterrupted(db);
42465
43732
  interruptCodingCommands(db);
43733
+ recoverInterruptedVerificationAttempts(db, VERIFICATION_DISPATCH_OWNER);
42466
43734
  reconcileApprovalHolds(db);
42467
43735
  recoverInterruptedResultDeliveries(db);
42468
43736
  reconcilePrivateResults(db);
@@ -42630,7 +43898,7 @@ async function authMiddleware(c, next) {
42630
43898
  }
42631
43899
 
42632
43900
  // ../daemon/src/routes/agents.ts
42633
- import { randomUUID as randomUUID34 } from "crypto";
43901
+ import { randomUUID as randomUUID37 } from "crypto";
42634
43902
  import { existsSync as existsSync18, readFileSync as readFileSync12 } from "fs";
42635
43903
  import { join as join28 } from "path";
42636
43904
  import { Hono } from "hono";
@@ -43955,7 +45223,7 @@ async function notifyTelegramQueueStatus(db, agentId, itemId) {
43955
45223
  }
43956
45224
 
43957
45225
  // ../daemon/src/lib/user-queue-admission.ts
43958
- import { randomUUID as randomUUID33 } from "crypto";
45226
+ import { randomUUID as randomUUID36 } from "crypto";
43959
45227
  async function enqueueTelegramInput(binding, message, attachments2, context = getCtx()) {
43960
45228
  validateInput(message, attachments2);
43961
45229
  const { db, paths, authToken } = context;
@@ -43974,7 +45242,7 @@ async function enqueueTelegramInput(binding, message, attachments2, context = ge
43974
45242
  const existing = findAttempt(db, "telegram", binding.authorization.attemptId);
43975
45243
  return db.raw.transaction(() => {
43976
45244
  const item = accept(db, {
43977
- id: existing?.id ?? randomUUID33(),
45245
+ id: existing?.id ?? randomUUID36(),
43978
45246
  agentId,
43979
45247
  teamId: existing?.teamId ?? agent.team.id,
43980
45248
  conversationId,
@@ -45794,7 +47062,7 @@ agentsRouter.post("/:id/chat", async (c) => {
45794
47062
  if (!message && attachments2.length === 0) {
45795
47063
  return c.json({ error: "message or an attachment is required" }, 400);
45796
47064
  }
45797
- const requestAttemptId = c.req.header("x-request-id") ?? randomUUID34();
47065
+ const requestAttemptId = c.req.header("x-request-id") ?? randomUUID37();
45798
47066
  let preparedTurn;
45799
47067
  try {
45800
47068
  preparedTurn = await prepareAgentTurn({
@@ -46257,6 +47525,9 @@ import { Bot as Bot2, InputFile as InputFile2 } from "grammy";
46257
47525
  import { Hono as Hono2 } from "hono";
46258
47526
 
46259
47527
  // ../daemon/src/lib/approval-delivery-plan.ts
47528
+ function isTelegramDeliveryPlan(plan) {
47529
+ return plan.kind === "telegram_text" || plan.kind === "telegram_typing" || plan.kind === "telegram_image" || plan.kind === "telegram_file";
47530
+ }
46260
47531
  var ApprovalDeliveryValidationError = class extends Error {
46261
47532
  constructor(code) {
46262
47533
  super(`approval_delivery_invalid: ${code}`);
@@ -46297,6 +47568,14 @@ function planApprovalDelivery(approval, context = {}) {
46297
47568
  return invalid3("question_binding");
46298
47569
  }
46299
47570
  }
47571
+ if (approval.payloadKind === "verification_request") {
47572
+ const payload = approval.payload;
47573
+ if (approval.operation !== "request_verification" || approval.origin !== "verification_request" || !isRecord3(payload) || Object.keys(payload).sort().join(",") !== "requestId" || typeof payload.requestId !== "string" || !/^[0-9a-f-]{36}$/i.test(payload.requestId))
47574
+ return invalid3("verification_request_payload");
47575
+ requireAttemptKind(approval, "verification_request");
47576
+ if (approval.attemptId !== payload.requestId) return invalid3("verification_request_attempt");
47577
+ return { kind: "verification_request", approval, payload: { requestId: payload.requestId } };
47578
+ }
46300
47579
  if (approval.payloadKind === "queued_user") {
46301
47580
  const payload = validateQueuedUserApproval(approval, context.queuedInput ?? (() => null));
46302
47581
  return { kind: "queued_user", approval, payload };
@@ -46678,6 +47957,40 @@ async function deliverQueuedApproval(approval) {
46678
47957
  }
46679
47958
  }
46680
47959
 
47960
+ // ../daemon/src/lib/verification/approval.ts
47961
+ function validateVerificationGrant(db, paths, requestId2) {
47962
+ const request2 = getVerificationRequestByIdSafe(db, requestId2);
47963
+ if (!request2) return "verification request is unknown or past its retention window";
47964
+ if (request2.state !== "awaiting_approval") {
47965
+ return `verification request is ${request2.state}, not awaiting approval`;
47966
+ }
47967
+ const team = safeTeam2(db, paths, request2.teamId);
47968
+ if (!team) return "verification request no longer names a known Team";
47969
+ const recipient = get(db, request2.recipientAgentId);
47970
+ if (!recipient || recipient.status === "archived") {
47971
+ return "the selected specialist is missing or archived";
47972
+ }
47973
+ if (recipient.teamId !== team.id) return "the selected specialist left this Team";
47974
+ if (!getSourceSnapshot(db, team.id, request2.snapshotId)) {
47975
+ return "the captured change is no longer inside its retention window";
47976
+ }
47977
+ return null;
47978
+ }
47979
+ function releaseVerificationGrant(db, requestId2) {
47980
+ const request2 = getVerificationRequestByIdSafe(db, requestId2);
47981
+ if (request2?.state === "awaiting_approval") setRequestState(db, requestId2, "pending");
47982
+ }
47983
+ function getVerificationRequestByIdSafe(db, requestId2) {
47984
+ return getVerificationRequestById(db, requestId2);
47985
+ }
47986
+ function safeTeam2(db, paths, teamId) {
47987
+ try {
47988
+ return requireTeam(db, paths, teamId);
47989
+ } catch {
47990
+ return null;
47991
+ }
47992
+ }
47993
+
46681
47994
  // ../daemon/src/routes/approvals.ts
46682
47995
  var approvalsRouter = new Hono2();
46683
47996
  approvalsRouter.use("*", async (_c, next) => {
@@ -46799,6 +48112,33 @@ approvalsRouter.post("/:id/approve", async (c) => {
46799
48112
  );
46800
48113
  return c.json({ error: "approval delivery failed", detail: error2.message }, 500);
46801
48114
  }
48115
+ if (pendingPlan.kind === "verification_request") {
48116
+ const { paths } = getCtx();
48117
+ const granted = communicationApprovals_exports.grantVerificationRequest(
48118
+ db,
48119
+ id,
48120
+ "authenticated_operator",
48121
+ (approval) => authorizeInSnapshot(db, {
48122
+ source: approval.source,
48123
+ target: approval.target,
48124
+ origin: approval.origin,
48125
+ attemptKind: approval.attemptKind,
48126
+ attemptId: approval.attemptId
48127
+ }),
48128
+ () => validateVerificationGrant(db, paths, pendingPlan.payload.requestId),
48129
+ () => releaseVerificationGrant(db, pendingPlan.payload.requestId)
48130
+ );
48131
+ if (!granted.granted) {
48132
+ return c.json(
48133
+ {
48134
+ error: granted.failureKind === "revalidation" ? "approval revalidation failed" : "approval delivery failed",
48135
+ detail: granted.error
48136
+ },
48137
+ 409
48138
+ );
48139
+ }
48140
+ return c.json(granted.approval);
48141
+ }
46802
48142
  if (pendingPlan.kind === "scheduler_trigger") {
46803
48143
  const granted = communicationApprovals_exports.grantSchedulerTrigger(
46804
48144
  db,
@@ -46921,6 +48261,9 @@ async function deliver(plan) {
46921
48261
  if (plan.kind === "scheduler_trigger") {
46922
48262
  return;
46923
48263
  }
48264
+ if (plan.kind === "verification_request") {
48265
+ return;
48266
+ }
46924
48267
  if (plan.kind === "agent_turn") {
46925
48268
  const preparedTurn = await prepareAgentTurn({
46926
48269
  invocation: createTrustedTurnInvocation({
@@ -47025,6 +48368,9 @@ async function deliver(plan) {
47025
48368
  if (failure) throw new Error(failure);
47026
48369
  return;
47027
48370
  }
48371
+ if (!isTelegramDeliveryPlan(plan)) {
48372
+ throw new Error("approval_delivery_invalid: no delivery handler for this plan kind");
48373
+ }
47028
48374
  const { db, authToken } = getCtx();
47029
48375
  if (plan.kind === "telegram_file" && plan.payload.result) {
47030
48376
  if (plan.approval.source.kind !== "agent") throw new Error("Missing result producer");
@@ -48078,7 +49424,7 @@ function createBackupArchive(paths, snapshot) {
48078
49424
  }
48079
49425
 
48080
49426
  // ../daemon/src/lib/daemon-liveness.ts
48081
- import { createHash as createHash17, randomUUID as randomUUID35 } from "crypto";
49427
+ import { createHash as createHash17, randomUUID as randomUUID38 } from "crypto";
48082
49428
  import {
48083
49429
  chmodSync as chmodSync2,
48084
49430
  closeSync as closeSync10,
@@ -48248,7 +49594,7 @@ function acquireDaemonLiveness(paths) {
48248
49594
  mkdirSync11(dirname6(resolve7(paths.home)), { recursive: true });
48249
49595
  const path = daemonLivenessPath(paths.home);
48250
49596
  mkdirSync11(dirname6(path), { recursive: true });
48251
- const instanceId = randomUUID35();
49597
+ const instanceId = randomUUID38();
48252
49598
  const startedAt = Date.now();
48253
49599
  let fd = null;
48254
49600
  let reclaimClaim = null;
@@ -48613,7 +49959,7 @@ miscRouter.get("/health/details", async (c) => {
48613
49959
  }
48614
49960
  }
48615
49961
  });
48616
- const report = {
49962
+ const report2 = {
48617
49963
  // Structural install health only. Protected work has an explicit, independent signal below.
48618
49964
  ok: pathChecks.home && pathChecks.db && pathChecks.auth && pathChecks.profiles && pathChecks.agents && pathChecks.skills && (database === null || database.ok) && parseErrors === 0 && shellSecurity.ok,
48619
49965
  protectedWorkBaselineReady: executionSecurity.protectedUnattendedTurns.baseRuntimeReady,
@@ -48647,7 +49993,7 @@ miscRouter.get("/health/details", async (c) => {
48647
49993
  decisions: { ...communicationDecisionMetrics }
48648
49994
  }
48649
49995
  };
48650
- return c.json(report);
49996
+ return c.json(report2);
48651
49997
  });
48652
49998
  function publicShellSecurityError(error2) {
48653
49999
  const message = error2 instanceof Error ? error2.message : String(error2);
@@ -48763,7 +50109,7 @@ import { bodyLimit } from "hono/body-limit";
48763
50109
  import { HTTPException } from "hono/http-exception";
48764
50110
 
48765
50111
  // ../daemon/src/lib/notification-control.ts
48766
- import { randomUUID as randomUUID36 } from "crypto";
50112
+ import { randomUUID as randomUUID39 } from "crypto";
48767
50113
 
48768
50114
  // ../daemon/src/lib/notification-authorization.ts
48769
50115
  function authorizeAttentionNotification(db, item, captured) {
@@ -48928,7 +50274,7 @@ var NotificationControl = class {
48928
50274
  );
48929
50275
  for (const item of items) byKind[item.kind]++;
48930
50276
  const value = {
48931
- id: randomUUID36(),
50277
+ id: randomUUID39(),
48932
50278
  settingsRevision: revision4,
48933
50279
  destinationId: binding.id,
48934
50280
  kinds,
@@ -49838,7 +51184,7 @@ async function parseImportInput(request2) {
49838
51184
  }
49839
51185
 
49840
51186
  // ../daemon/src/routes/team-templates.ts
49841
- import { randomUUID as randomUUID37 } from "crypto";
51187
+ import { randomUUID as randomUUID40 } from "crypto";
49842
51188
  import { Hono as Hono17 } from "hono";
49843
51189
  var teamTemplatesRouter = new Hono17();
49844
51190
  teamTemplatesRouter.get("/", (c) => {
@@ -49878,7 +51224,7 @@ teamTemplatesRouter.post("/import", async (c) => {
49878
51224
  if (!profiles_exports.get(db, parsed.profileId)) {
49879
51225
  throw new Error(`profile not found: ${parsed.profileId}`);
49880
51226
  }
49881
- const slotId = randomUUID37();
51227
+ const slotId = randomUUID40();
49882
51228
  keyToSlot.set(clientKey, slotId);
49883
51229
  return { ...parsed, slotId };
49884
51230
  });
@@ -50326,6 +51672,194 @@ function lineRange(request2, _captured) {
50326
51672
  return { start, end };
50327
51673
  }
50328
51674
 
51675
+ // ../daemon/src/lib/verification/capture.ts
51676
+ function captureVerificationRequest(db, paths, intent, env = process.env) {
51677
+ const team = safeTeam3(db, paths, intent.teamId);
51678
+ if (!team) return blocked2("unsupported", "the request does not name a known Team");
51679
+ const recipient = get(db, intent.recipientAgentId);
51680
+ if (!recipient) return blocked2("recipient_unavailable", "the selected specialist does not exist");
51681
+ if (recipient.teamId !== team.id) {
51682
+ return blocked2("recipient_not_same_team", "the selected specialist belongs to another Team");
51683
+ }
51684
+ if (recipient.status === "archived") {
51685
+ return blocked2("recipient_unavailable", "the selected specialist is archived");
51686
+ }
51687
+ if (intent.requesterKind === "agent") {
51688
+ const requester = get(db, intent.requesterAgentId);
51689
+ if (!requester) return blocked2("requester_unavailable", "the requesting Agent does not exist");
51690
+ if (requester.teamId !== team.id) {
51691
+ return blocked2("requester_unavailable", "the requesting Agent belongs to another Team");
51692
+ }
51693
+ if (requester.id === recipient.id) {
51694
+ return blocked2("unsupported", "a specialist cannot verify its own request");
51695
+ }
51696
+ }
51697
+ const snapshot = getSourceSnapshot(db, team.id, intent.snapshotId);
51698
+ if (!snapshot) {
51699
+ return blocked2(
51700
+ "snapshot_unavailable",
51701
+ "the captured change is unknown in this Team or past its retention window"
51702
+ );
51703
+ }
51704
+ if (!snapshot.complete) {
51705
+ return blocked2(
51706
+ "snapshot_incomplete",
51707
+ "the captured change has incomplete coverage, so a result could not be tied to it"
51708
+ );
51709
+ }
51710
+ const environment = admittedEnvironment(db, team.id, env);
51711
+ if (!environment) {
51712
+ return blocked2(
51713
+ "environment_unavailable",
51714
+ "the Team has no usable admitted environment to freeze with the request"
51715
+ );
51716
+ }
51717
+ if (intent.writablePaths && intent.writablePaths.length > 0) {
51718
+ const bounded3 = [];
51719
+ for (const path of intent.writablePaths) {
51720
+ if (typeof path !== "string" || path.length === 0 || path.length > 1e3) {
51721
+ return blocked2("unsupported", "declared writable paths are outside their bounded contract");
51722
+ }
51723
+ if (path.startsWith("/") || path.startsWith("~") || path.includes("\\")) {
51724
+ return blocked2("unsupported", `declared writable path must be Team-relative: ${path}`);
51725
+ }
51726
+ const parts = path.split("/").filter((part) => part && part !== ".");
51727
+ if (parts.length === 0 || parts.some((part) => part === "..")) {
51728
+ return blocked2(
51729
+ "unsupported",
51730
+ `declared writable path must be inside the workspace: ${path}`
51731
+ );
51732
+ }
51733
+ bounded3.push(parts.join("/"));
51734
+ }
51735
+ if (bounded3.length > 16) {
51736
+ return blocked2("unsupported", "too many declared writable paths");
51737
+ }
51738
+ environment.writablePaths = bounded3;
51739
+ }
51740
+ try {
51741
+ const request2 = createVerificationRequest(db, {
51742
+ teamId: team.id,
51743
+ requesterKind: intent.requesterKind,
51744
+ requesterAgentId: intent.requesterKind === "agent" ? intent.requesterAgentId : null,
51745
+ recipientAgentId: recipient.id,
51746
+ messageId: intent.messageId ?? null,
51747
+ sourceSessionId: intent.sourceSessionId ?? null,
51748
+ snapshotId: snapshot.snapshotId,
51749
+ snapshotComplete: snapshot.complete,
51750
+ head: snapshot.head,
51751
+ baseOid: snapshot.baseOid,
51752
+ environment,
51753
+ summary: intent.summary ?? null,
51754
+ checks: intent.checks
51755
+ });
51756
+ return { kind: "captured", request: request2 };
51757
+ } catch (error2) {
51758
+ return blocked2("unsupported", error2 instanceof Error ? error2.message : "invalid request");
51759
+ }
51760
+ }
51761
+ function admittedEnvironment(db, teamId, env) {
51762
+ try {
51763
+ const security = resolveShellSecurityConfig(env);
51764
+ const resolved = resolveTeamCodingEnvironment(db, teamId, env);
51765
+ if (!resolved.image) return null;
51766
+ return {
51767
+ image: resolved.image,
51768
+ sandbox: security.sandboxMode === "docker" ? "docker" : "off",
51769
+ ...resolved.coding ? { cwd: resolved.coding.cwd } : {},
51770
+ ...resolved.coding ? { env: { ...resolved.coding.env } } : {}
51771
+ };
51772
+ } catch {
51773
+ return null;
51774
+ }
51775
+ }
51776
+ function readVerificationSummary(db, paths, teamId, requestId2) {
51777
+ const team = safeTeam3(db, paths, teamId);
51778
+ if (!team) return null;
51779
+ const record3 = getVerificationRequest(db, team.id, requestId2);
51780
+ if (!record3) return null;
51781
+ const checks = listVerificationChecks(db, record3.id);
51782
+ const attempts = listVerificationAttempts(db, record3.id).map((attempt) => ({
51783
+ id: attempt.id,
51784
+ attemptNumber: attempt.attemptNumber,
51785
+ supersedesAttemptId: attempt.supersedesAttemptId,
51786
+ state: attempt.state,
51787
+ startedAt: attempt.startedAt,
51788
+ finishedAt: attempt.finishedAt,
51789
+ error: attempt.error,
51790
+ outcomes: listVerificationCheckOutcomes(db, attempt.id).map((outcome) => ({
51791
+ ordinal: outcome.ordinal,
51792
+ state: outcome.state,
51793
+ commandId: outcome.commandId,
51794
+ // Executed, but no receipt pointer: the receipt was pruned or expired, which is different from
51795
+ // never having recorded one.
51796
+ receiptUnavailable: outcome.commandId === null && ["succeeded", "failed", "timed_out", "cancelled"].includes(outcome.state),
51797
+ exitCode: outcome.exitCode,
51798
+ startedAt: outcome.startedAt,
51799
+ finishedAt: outcome.finishedAt
51800
+ }))
51801
+ }));
51802
+ return {
51803
+ request: toWireRequest(record3),
51804
+ checks: checks.map((check) => ({
51805
+ ordinal: check.ordinal,
51806
+ command: check.command,
51807
+ cwd: check.cwd,
51808
+ purpose: check.purpose,
51809
+ timeoutMs: check.timeoutMs
51810
+ })),
51811
+ attempts
51812
+ };
51813
+ }
51814
+ async function readVerificationReport(db, paths, teamId, requestId2) {
51815
+ const summary = readVerificationSummary(db, paths, teamId, requestId2);
51816
+ if (!summary) return null;
51817
+ const applicability = await readSnapshotApplicability(
51818
+ db,
51819
+ paths,
51820
+ summary.request.teamId,
51821
+ summary.request.snapshot.id
51822
+ );
51823
+ return {
51824
+ ...summary,
51825
+ applicability: {
51826
+ comparison: applicability.comparison,
51827
+ testedSnapshotId: applicability.comparison === "unknown" ? null : summary.request.snapshot.id
51828
+ }
51829
+ };
51830
+ }
51831
+ function toWireRequest(record3) {
51832
+ return {
51833
+ id: record3.id,
51834
+ teamId: record3.teamId,
51835
+ requester: record3.requesterKind === "agent" && record3.requesterAgentId ? { kind: "agent", agentId: record3.requesterAgentId } : { kind: "operator" },
51836
+ recipientAgentId: record3.recipientAgentId,
51837
+ messageId: record3.messageId,
51838
+ sourceSessionId: record3.sourceSessionId,
51839
+ snapshot: {
51840
+ id: record3.snapshotId,
51841
+ complete: record3.snapshotComplete,
51842
+ head: record3.head,
51843
+ baseOid: record3.baseOid
51844
+ },
51845
+ environment: record3.environment,
51846
+ summary: record3.summary,
51847
+ state: record3.state,
51848
+ createdAt: record3.createdAt,
51849
+ expiresAt: record3.expiresAt
51850
+ };
51851
+ }
51852
+ function blocked2(reason, detail3) {
51853
+ return { kind: "blocked", blocker: { reason, detail: detail3 } };
51854
+ }
51855
+ function safeTeam3(db, paths, teamId) {
51856
+ try {
51857
+ return requireTeam(db, paths, teamId);
51858
+ } catch {
51859
+ return null;
51860
+ }
51861
+ }
51862
+
50329
51863
  // ../daemon/src/routes/teams.ts
50330
51864
  var USER_MD_MAX_BYTES2 = 12e3;
50331
51865
  var teamsRouter = new Hono18();
@@ -50949,6 +52483,91 @@ function teamPolicyError(c, error2) {
50949
52483
  }
50950
52484
  return c.json({ error: message, code: "team_policy_invalid" }, 400);
50951
52485
  }
52486
+ teamsRouter.get("/:id/verifications", async (c) => {
52487
+ const { db, paths } = getCtx();
52488
+ c.header("Cache-Control", "no-store");
52489
+ try {
52490
+ const team = requireTeam(db, paths, c.req.param("id"));
52491
+ const requests = listVerificationRequests(db, team.id);
52492
+ const reports = requests.map((record3) => readVerificationSummary(db, paths, team.id, record3.id)).filter((summary) => summary !== null);
52493
+ return c.json({ requests: reports });
52494
+ } catch (error2) {
52495
+ return reviewFailure(c, error2);
52496
+ }
52497
+ });
52498
+ teamsRouter.post("/:id/verifications", async (c) => {
52499
+ const { db, paths } = getCtx();
52500
+ c.header("Cache-Control", "no-store");
52501
+ const body = await c.req.json().catch(() => null);
52502
+ if (!body || typeof body !== "object" || Array.isArray(body)) {
52503
+ return c.json({ error: "Invalid verification request" }, 400);
52504
+ }
52505
+ const input = body;
52506
+ if (typeof input.recipientAgentId !== "string" || typeof input.snapshotId !== "string" || !Array.isArray(input.checks) || input.checks.some(
52507
+ (check) => !check || typeof check.command !== "string" || typeof check.cwd !== "string" || typeof check.purpose !== "string" || !Number.isInteger(check.timeoutMs)
52508
+ )) {
52509
+ return c.json({ error: "Invalid verification request" }, 400);
52510
+ }
52511
+ try {
52512
+ const result = captureVerificationRequest(db, paths, {
52513
+ teamId: c.req.param("id"),
52514
+ requesterKind: "operator",
52515
+ requesterAgentId: null,
52516
+ recipientAgentId: input.recipientAgentId,
52517
+ snapshotId: input.snapshotId,
52518
+ checks: input.checks,
52519
+ summary: typeof input.summary === "string" ? input.summary : null,
52520
+ sourceSessionId: typeof input.sourceSessionId === "string" ? input.sourceSessionId : null,
52521
+ ...Array.isArray(input.writablePaths) ? { writablePaths: input.writablePaths } : {}
52522
+ });
52523
+ if (result.kind === "blocked") return c.json({ blocked: result.blocker }, 409);
52524
+ return c.json({ request: await report(db, paths, result.request) }, 201);
52525
+ } catch (error2) {
52526
+ return reviewFailure(c, error2);
52527
+ }
52528
+ });
52529
+ teamsRouter.get("/:id/verifications/:requestId", async (c) => {
52530
+ const { db, paths } = getCtx();
52531
+ c.header("Cache-Control", "no-store");
52532
+ try {
52533
+ const report2 = await readVerificationReport(
52534
+ db,
52535
+ paths,
52536
+ c.req.param("id"),
52537
+ c.req.param("requestId")
52538
+ );
52539
+ if (!report2) return c.json({ error: "Verification request not found" }, 404);
52540
+ return c.json({ request: report2 });
52541
+ } catch (error2) {
52542
+ return reviewFailure(c, error2);
52543
+ }
52544
+ });
52545
+ teamsRouter.post("/:id/verifications/:requestId/cancel", async (c) => {
52546
+ const { db, paths } = getCtx();
52547
+ c.header("Cache-Control", "no-store");
52548
+ try {
52549
+ const team = requireTeam(db, paths, c.req.param("id"));
52550
+ const record3 = getVerificationRequest(db, team.id, c.req.param("requestId"));
52551
+ if (!record3) return c.json({ error: "Verification request not found" }, 404);
52552
+ if (record3.state !== "pending" && record3.state !== "awaiting_approval" && record3.state !== "running") {
52553
+ return c.json({ error: `Verification request is already ${record3.state}` }, 409);
52554
+ }
52555
+ if (record3.state === "pending" || record3.state === "awaiting_approval") {
52556
+ setRequestState(db, record3.id, "cancelled");
52557
+ } else {
52558
+ const aborted2 = cancelVerificationDispatch(record3.id);
52559
+ if (!aborted2) {
52560
+ return c.json({ error: "Verification request is not cancelled yet; retry" }, 409);
52561
+ }
52562
+ }
52563
+ return c.json({ request: await readVerificationReport(db, paths, team.id, record3.id) });
52564
+ } catch (error2) {
52565
+ return reviewFailure(c, error2);
52566
+ }
52567
+ });
52568
+ async function report(db, paths, record3) {
52569
+ return readVerificationReport(db, paths, record3.teamId, record3.id);
52570
+ }
50952
52571
 
50953
52572
  // ../daemon/src/routes/telegram.ts
50954
52573
  import { Hono as Hono19 } from "hono";