thinkpool-pair 0.7.368 → 0.7.369
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.
- package/package.json +1 -1
- package/publish-manifest.json +5 -5
- package/scheduled-runs.mjs +1 -1
package/package.json
CHANGED
package/publish-manifest.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": 1,
|
|
3
3
|
"package": "thinkpool-pair",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.369",
|
|
5
5
|
"kind": "minified",
|
|
6
6
|
"minifiedModules": 111,
|
|
7
|
-
"sourceModuleBytes":
|
|
8
|
-
"artifactModuleBytes":
|
|
7
|
+
"sourceModuleBytes": 1618548,
|
|
8
|
+
"artifactModuleBytes": 717390,
|
|
9
9
|
"files": {
|
|
10
|
-
"package.json": "
|
|
10
|
+
"package.json": "1250381500ae71c9f6a827db543ed12cb9a0922ca33a875b15d714d2bac87d9a",
|
|
11
11
|
"LICENSE": "8a030197ca1cad9669909ca14c9ad15cf48d9fe551da526ccaf1fca993eddb23",
|
|
12
12
|
"bridge.mjs": "834340034800baff27c409f1e01fcde3727bf647812d4ec66219d7464c4c0ed7",
|
|
13
13
|
"bridge-service.sh": "b64f27c473ca8f3a49190fd08c23947ab14ca9958d70b6fa53c7bddc2be91403",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"evidence-citations.mjs": "865032925532c0f7a4b3f0ed484c85fa53237a7f46d79640714cd483b493b98d",
|
|
65
65
|
"error-recovery.mjs": "0ace80add28fa72b49a3f3a716f247e3ef9816671c09749b3863867700beae32",
|
|
66
66
|
"pair-control-authority.mjs": "7a95f101153dcc6dd0633b5a01595bf2979cd0c4bf50cfc6cd44bb7612ef40a5",
|
|
67
|
-
"scheduled-runs.mjs": "
|
|
67
|
+
"scheduled-runs.mjs": "c139e7d47dd7a12c73149502b5d02409e96f4ccafaf28a9ab6889e5b101931e9",
|
|
68
68
|
"scheduled-run-admission.mjs": "3a2098d904c3aff571bf314e0182d5636d25d242cef52207e70f9dc1618c94f5",
|
|
69
69
|
"event-id.mjs": "9ebd6dc404cc8c799c660b3d1fb397bd39a6181128d3a91f7bab5f42c55d4e9d",
|
|
70
70
|
"event-bounds.mjs": "aa8eb8517c4aa81b3378f71401ed39c550cdc80e28e3a57ab46d0a5ef5c7c9c1",
|
package/scheduled-runs.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{randomUUID as e}from"node:crypto";import{SPAWN as t,spawnDecision as n}from"./cross-terminal.mjs";const i=new Set(["once","daily","weekly"]),r=new Set(["claude","codex","hermes"]),d=new Set(["delivered","needs_decision","failed","canceled"]),o=new Set(["artifact","preview","commit","test","flow_task","control_item"]),c=/(?:sk-[a-z0-9_-]{8,}|gsk_[a-z0-9_-]{8,}|AIza[a-z0-9_-]{8,}|gh[pousr]_[a-z0-9]{20,}|github_pat_[a-z0-9_]{20,}|xox[baprs]-[a-z0-9-]{10,}|AKIA[0-9A-Z]{16}|sbp_[a-z0-9]{20,}|eyJ[a-z0-9_-]{16,}\.[a-z0-9_-]{16,}\.[a-z0-9_-]{8,}|bearer\s+[a-z0-9._-]{8,}|(?:token|secret|api[_-]?key|authorization)\s*=)/i,a=/(?:^|\s)(?:~\/|\/Users\/|\/home\/|\/private\/|\/tmp\/|[A-Za-z]:\\|\.\.[\\/])/i,u=/^[A-Za-z0-9][A-Za-z0-9._:@-]{0,159}$/,s=/^[A-Za-z0-9][A-Za-z0-9._:-]{0,119}$/,l=new Map,_=new Set([15,30,60]);export const scheduledRunsEnabled=(e=process.env.TP_SCHEDULED_RUNS_ENABLED)=>"1"===e;export const scheduledRunsCapability=(e=process.env.TP_SCHEDULED_RUNS_ENABLED)=>Object.freeze({enabled:scheduledRunsEnabled(e)});const p=(e,t)=>"string"==typeof e&&e.trim().length>0&&e.length<=t&&!c.test(e)&&!a.test(e),m=e=>e instanceof Date?e:new Date(e),f=e=>!Number.isNaN(m(e).getTime()),h=(e,t)=>{let n=l.get(e);n||(n=new Intl.DateTimeFormat("en-CA",{timeZone:e,weekday:"short",hour:"2-digit",minute:"2-digit",hourCycle:"h23"}),l.set(e,n));const i=Object.fromEntries(n.formatToParts(t).filter(e=>"literal"!==e.type).map(e=>[e.type,e.value]));return{weekday:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"].indexOf(i.weekday),time:`${i.hour}:${i.minute}`}};export function scheduleValidationError(e={}){if(!e||"object"!=typeof e||!i.has(e.kind))return"invalid_kind";if(!p(e.title,120)||!p(e.prompt,12e3))return"unsafe_or_invalid_text";if(!r.has(e.runtime))return"invalid_runtime";if(!(null==e.provider||p(e.provider,80)&&u.test(e.provider)))return"invalid_provider";if(!(null==e.model||p(e.model,160)&&u.test(e.model)))return"invalid_model";if(!Number.isInteger(e.maxRuntimeMinutes)||e.maxRuntimeMinutes<1||e.maxRuntimeMinutes>30)return"invalid_max_runtime";try{new Intl.DateTimeFormat("en",{timeZone:e.timezone})}catch{return"invalid_timezone"}return"once"!==e.kind||f(e.at)?null==e.intervalMinutes||_.has(e.intervalMinutes)?"once"!==e.kind&&!/^\d{2}:\d{2}$/.test(e.time)||"once"!==e.kind&&(Number(e.time.slice(0,2))>23||Number(e.time.slice(3))>59)?"invalid_local_time":"weekly"===e.kind&&(!Number.isInteger(e.weekday)||e.weekday<0||e.weekday>6)?"invalid_weekday":null:"invalid_interval":"invalid_once_time"}export function normalizeSchedule(e={},t=new Date){const n=scheduleValidationError(e);if(n)return Object.freeze({ok:!1,code:n});const i={kind:e.kind,title:e.title.trim(),prompt:e.prompt.trim(),runtime:e.runtime,provider:e.provider||null,model:e.model||null,timezone:e.timezone,maxRuntimeMinutes:e.maxRuntimeMinutes,..."once"===e.kind?{at:m(e.at).toISOString()}:{time:e.time,..."weekly"===e.kind?{weekday:e.weekday}:{},...e.intervalMinutes?{interval_minutes:e.intervalMinutes}:{}}},r=nextScheduledAt(i,t);return r?Object.freeze({ok:!0,value:Object.freeze(i),nextRunAt:r.toISOString()}):Object.freeze({ok:!1,code:"schedule_exhausted"})}export function nextScheduledAt(e,t=new Date){if("once"===e?.kind){const n=m(e.at);return f(n)&&n.getTime()>m(t).getTime()?n:null}const n=Number(e?.interval_minutes);if(_.has(n))return new Date(m(t).getTime()+6e4*n);const i=6e4*Math.floor(m(t).getTime()/6e4)+6e4;for(let t=i,n=i+3456e7;t<n;t+=6e4){const n=h(e.timezone,new Date(t));if(n.time===e.time&&("daily"===e.kind||n.weekday===e.weekday))return new Date(t)}return null}export function classifyRunOutcome({result:e=null,evidenceRefs:t=[],pendingControls:n=[],runId:i=null,canceled:r=!1}={}){if("runtime_limit"===e?.subtype)return Object.freeze({outcome:"failed",code:"runtime_limit"});if(r||["aborted","canceled","cancelled","interrupted"].includes(e?.subtype))return Object.freeze({outcome:"canceled",code:"canceled"});const d=(Array.isArray(t)?t:[]).filter(e=>e&&o.has(e.type)&&"string"==typeof e.id&&u.test(e.id)).slice(0,16);if(d.length)return Object.freeze({outcome:"delivered",code:"evidence_delivered",evidence:d});const c=(Array.isArray(n)?n:[]).find(e=>"pending"===e?.status&&e?.id&&e?.request_context?.run_id&&(!i||e.request_context.run_id===i)&&Number.isSafeInteger(Number(e.source_event_from_seq)));return c?Object.freeze({outcome:"needs_decision",code:"pending_pair_control",controlItemId:c.id}):"success"===e?.subtype?Object.freeze({outcome:"failed",code:"missing_deliverable"}):Object.freeze({outcome:"failed",code:e?.subtype||"runtime_failed"})}export function sanitizeScheduledOutcomeIntent({runId:e,result:t=null,evidenceRefs:n=[],canceled:i=!1}={}){if("string"!=typeof e||!u.test(e))return null;const r="string"==typeof t?.subtype&&s.test(t.subtype)?t.subtype:"runtime_failed";return Object.freeze({runId:e,result:Object.freeze({subtype:r}),evidenceRefs:Object.freeze((d=n,(Array.isArray(d)?d:[]).filter(e=>e&&o.has(e.type)&&"string"==typeof e.id&&u.test(e.id)).slice(0,16).map(e=>Object.freeze({type:e.type,id:e.id})))),canceled:!0===i});var d}export function scheduledRunDeadlineRequired({runId:e,deadlineAt:t,outcomeRecorded:n=!1,outcomePending:i=null}={}){return Boolean(e&&Number.isFinite(t)&&!n&&!i)}export function scheduledOutcomeReconciliationComplete(e=[]){return Array.isArray(e)&&0===e.length}export function scheduledRunSpawnAdmission({spawnTimes:e=[],now:i=Date.now(),totalLive:r=0,disabled:d=!1}={},o=t){const c={...t,...o||{}},a=(Array.isArray(e)?e:[]).filter(e=>Number.isFinite(e)&&e>i-c.windowMs).slice(-(c.perWindowCap||1)),u=n({hop:0,spawnTimes:a,now:i,spawnedLive:0,totalLive:r,plan:"free",disabled:d},c);return Object.freeze({...u,spawnTimes:Object.freeze(u.ok?[...a,i].slice(-c.perWindowCap):a)})}export function preflightScheduledRun({schedule:e,occurrence:t,ownerId:n,bridgeId:i,bridgeFencing:r,providerAvailable:d,capsOk:o=!0,now:c=new Date}={}){return e?.enabled?t?.id&&t.schedule_revision===e.revision?!n||!i||!Number.isSafeInteger(r)||r<1||t.owner_id!==n||t.bridge_id!==i||t.bridge_fencing!==r?Object.freeze({ok:!1,code:"owner_bridge_mismatch"}):o?"function"==typeof d&&d(e)?!t.lease_expires_at||m(t.lease_expires_at).getTime()<=m(c).getTime()?Object.freeze({ok:!1,code:"lease_expired"}):Object.freeze({ok:!0,code:"admitted"}):Object.freeze({ok:!1,code:"provider_unavailable"}):Object.freeze({ok:!1,code:"runtime_cap_exceeded"}):Object.freeze({ok:!1,code:"stale_schedule_revision"}):Object.freeze({ok:!1,code:"schedule_disabled"})}const b=async({fetchImpl:e,supabaseUrl:t,headers:n,name:i,body:r})=>{const d=await e(`${String(t).replace(/\/$/,"")}/rest/v1/rpc/${i}`,{method:"POST",headers:n,body:JSON.stringify(r)});if(!d?.ok)throw new Error(`${i}_failed`);return d.json()};export async function pollDueScheduledRuns({enabled:t=!1,fetchImpl:n=globalThis.fetch,supabaseUrl:i,anonKey:r,token:d,roomCode:o,bridgeId:c,bridgeFencing:a,ownerId:s,providerAvailable:l,openTerminal:_,admitRun:p,releaseRun:f,makeTerminalId:h=e,capsOk:y=()=>!0,now:g=new Date}={}){if(!t)return Object.freeze({ok:!1,code:"feature_disabled",runs:[]});if(!("function"==typeof n&&i&&r&&d&&o&&c&&Number.isSafeInteger(a))||a<1||!s||"function"!=typeof _||"function"!=typeof p||"function"!=typeof f||"function"!=typeof h)return Object.freeze({ok:!1,code:"runner_unavailable",runs:[]});const w={apikey:r,Authorization:`Bearer ${d}`,"Content-Type":"application/json"},k=String(o).trim().toUpperCase();try{const e=await b({fetchImpl:n,supabaseUrl:i,headers:w,name:"expire_code_scheduled_runs",body:{p_room_code:k,p_bridge_id:c,p_bridge_fencing:a,p_limit:24}});if(!e?.ok)throw new Error("expire_code_scheduled_runs_failed");const t=await b({fetchImpl:n,supabaseUrl:i,headers:w,name:"list_due_code_schedules",body:{p_room_code:k,p_limit:12}}),r=[];for(const e of Array.isArray(t)?t:[]){if(String(e?.session_code||"").trim().toUpperCase()!==k){r.push({scheduleId:e?.id,code:"room_scope_mismatch"});continue}if(!y(e)){r.push({scheduleId:e.id,code:"runtime_cap_exceeded"});continue}if("function"!=typeof l||!l(e)){r.push({scheduleId:e.id,code:"provider_unavailable"});continue}const t=h();if("string"!=typeof t||!u.test(t)){r.push({scheduleId:e.id,code:"terminal_id_unavailable"});continue}const d={...e.schedule_spec||{},kind:e.schedule_kind||e.kind,timezone:e.timezone},o="once"===d.kind?new Date("9999-12-31T23:59:00.000Z"):nextScheduledAt(d,new Date(e.next_run_at));if(!o){r.push({scheduleId:e.id,code:"next_run_invalid"});continue}const v=`${e.id}:${e.next_run_at}`,z=Math.min(1860,Math.max(60,60*e.max_runtime_minutes+60)),I=m(g).getTime()+1e3*z;let x=null;try{x=await p({schedule:e,runId:v,terminalId:t,deadlineAt:I})}catch{x=null}if(!x?.ok){r.push({scheduleId:e.id,code:x?.code||"spawn_not_admitted"});continue}let O=!1;try{const d=await b({fetchImpl:n,supabaseUrl:i,headers:w,name:"claim_due_code_schedule",body:{p_schedule_id:e.id,p_expected_revision:e.revision,p_bridge_id:c,p_bridge_fencing:a,p_occurrence_key:v,p_lease_seconds:z}});if(!d?.ok||!d?.run){r.push({scheduleId:e.id,code:d?.code||"claim_failed"});continue}const u=preflightScheduledRun({schedule:e,occurrence:d.run,ownerId:s,bridgeId:c,bridgeFencing:a,providerAvailable:l,capsOk:!0,now:g});if(!u.ok){r.push({scheduleId:e.id,runId:d.run.id,code:u.code});continue}const p=await b({fetchImpl:n,supabaseUrl:i,headers:w,name:"open_code_scheduled_run",body:{p_run_id:d.run.id,p_bridge_id:c,p_bridge_fencing:a,p_terminal_id:t,p_next_run_at:o.toISOString()}});if(!p?.ok){r.push({scheduleId:e.id,runId:d.run.id,code:p?.code||"open_not_persisted"});continue}const m=p.run||d.run;let f=null;try{f=await _({schedule:e,run:m,terminalId:t,admission:x.lease})}catch{f=null}if(f){O=!0,r.push({scheduleId:e.id,runId:d.run.id,code:"opened"});continue}const h=await b({fetchImpl:n,supabaseUrl:i,headers:w,name:"finish_code_scheduled_run",body:{p_run_id:d.run.id,p_bridge_id:c,p_bridge_fencing:a,p_outcome:"failed",p_outcome_code:"terminal_open_failed",p_evidence_refs:[],p_decision_item_id:null}});r.push({scheduleId:e.id,runId:d.run.id,code:h?.ok?"open_failed":h?.code||"open_failed_unrecorded"})}finally{if(!O)try{await f(x.lease)}catch{}}}return Object.freeze({ok:!0,code:"polled",runs:Object.freeze(r)})}catch{return Object.freeze({ok:!1,code:"runner_read_failed",runs:[]})}}export async function finishScheduledRun({fetchImpl:e=globalThis.fetch,supabaseUrl:t,anonKey:n,token:i,roomCode:r,runId:d,bridgeId:o,bridgeFencing:c,result:a,evidenceRefs:u,canceled:s=!1}={}){if(!(t&&n&&i&&r&&d&&o&&Number.isSafeInteger(c))||c<1)return Object.freeze({ok:!1,code:"outcome_unavailable"});const l={apikey:n,Authorization:`Bearer ${i}`,"Content-Type":"application/json"};try{const n=classifyRunOutcome({result:a,evidenceRefs:u,pendingControls:await b({fetchImpl:e,supabaseUrl:t,headers:l,name:"list_code_pair_controls",body:{p_session_code:String(r).toUpperCase(),p_status:"pending",p_limit:100}}),runId:d,canceled:s}),i=await b({fetchImpl:e,supabaseUrl:t,headers:l,name:"finish_code_scheduled_run",body:{p_run_id:d,p_outcome:n.outcome,p_outcome_code:n.code,p_bridge_id:o,p_bridge_fencing:c,p_evidence_refs:n.evidence||[],p_decision_item_id:n.controlItemId||null}});return Object.freeze({ok:Boolean(i?.ok),code:i?.code||"outcome_write_failed",outcome:n})}catch{return Object.freeze({ok:!1,code:"outcome_write_failed"})}}export async function finishScheduledRunWithRetry(e={},{attempts:t=3,delays:n=[100,400],sleep:i=e=>new Promise(t=>setTimeout(t,e))}={}){const r=Math.max(1,Math.min(5,Number.isInteger(t)?t:3));let d=Object.freeze({ok:!1,code:"outcome_write_failed"});for(let t=0;t<r;t++){if(d=await finishScheduledRun(e),d.ok)return d;t+1<r&&await i(Math.max(0,Math.min(5e3,Number(n[t]??n.at(-1)??0)||0)))}return d}export{d as OUTCOMES};
|
|
1
|
+
import{randomUUID as e}from"node:crypto";import{SPAWN as t,spawnDecision as n}from"./cross-terminal.mjs";const i=new Set(["once","daily","weekly"]),r=new Set(["claude","codex","hermes"]),d=new Set(["delivered","needs_decision","failed","canceled"]),o=new Set(["artifact","preview","commit","test","flow_task","control_item"]),c=/(?:sk-[a-z0-9_-]{8,}|gsk_[a-z0-9_-]{8,}|AIza[a-z0-9_-]{8,}|gh[pousr]_[a-z0-9]{20,}|github_pat_[a-z0-9_]{20,}|xox[baprs]-[a-z0-9-]{10,}|AKIA[0-9A-Z]{16}|sbp_[a-z0-9]{20,}|eyJ[a-z0-9_-]{16,}\.[a-z0-9_-]{16,}\.[a-z0-9_-]{8,}|bearer\s+[a-z0-9._-]{8,}|(?:token|secret|api[_-]?key|authorization)\s*=)/i,a=/(?:^|\s)(?:~\/|\/Users\/|\/home\/|\/private\/|\/tmp\/|[A-Za-z]:\\|\.\.[\\/])/i,u=/^[A-Za-z0-9][A-Za-z0-9._:@-]{0,159}$/,s=/^[A-Za-z0-9][A-Za-z0-9._:-]{0,119}$/,l=new Map,_=new Set([15,30,60]);export const scheduledRunsEnabled=(e=process.env.TP_SCHEDULED_RUNS_ENABLED)=>"1"===e;export const scheduledRunsCapability=(e=process.env.TP_SCHEDULED_RUNS_ENABLED)=>Object.freeze({enabled:scheduledRunsEnabled(e)});const p=(e,t)=>"string"==typeof e&&e.trim().length>0&&e.length<=t&&!c.test(e)&&!a.test(e),m=e=>e instanceof Date?e:new Date(e),f=e=>!Number.isNaN(m(e).getTime()),h=(e,t)=>{let n=l.get(e);n||(n=new Intl.DateTimeFormat("en-CA",{timeZone:e,weekday:"short",hour:"2-digit",minute:"2-digit",hourCycle:"h23"}),l.set(e,n));const i=Object.fromEntries(n.formatToParts(t).filter(e=>"literal"!==e.type).map(e=>[e.type,e.value]));return{weekday:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"].indexOf(i.weekday),time:`${i.hour}:${i.minute}`}};export function scheduleValidationError(e={}){if(!e||"object"!=typeof e||!i.has(e.kind))return"invalid_kind";if(!p(e.title,120)||!p(e.prompt,12e3))return"unsafe_or_invalid_text";if(!r.has(e.runtime))return"invalid_runtime";if(!(null==e.provider||p(e.provider,80)&&u.test(e.provider)))return"invalid_provider";if(!(null==e.model||p(e.model,160)&&u.test(e.model)))return"invalid_model";if(!Number.isInteger(e.maxRuntimeMinutes)||e.maxRuntimeMinutes<1||e.maxRuntimeMinutes>30)return"invalid_max_runtime";try{new Intl.DateTimeFormat("en",{timeZone:e.timezone})}catch{return"invalid_timezone"}return"once"!==e.kind||f(e.at)?null==e.intervalMinutes||_.has(e.intervalMinutes)?"once"!==e.kind&&!/^\d{2}:\d{2}$/.test(e.time)||"once"!==e.kind&&(Number(e.time.slice(0,2))>23||Number(e.time.slice(3))>59)?"invalid_local_time":"weekly"===e.kind&&(!Number.isInteger(e.weekday)||e.weekday<0||e.weekday>6)?"invalid_weekday":null:"invalid_interval":"invalid_once_time"}export function normalizeSchedule(e={},t=new Date){const n=scheduleValidationError(e);if(n)return Object.freeze({ok:!1,code:n});const i={kind:e.kind,title:e.title.trim(),prompt:e.prompt.trim(),runtime:e.runtime,provider:e.provider||null,model:e.model||null,timezone:e.timezone,maxRuntimeMinutes:e.maxRuntimeMinutes,..."once"===e.kind?{at:m(e.at).toISOString()}:{time:e.time,..."weekly"===e.kind?{weekday:e.weekday}:{},...e.intervalMinutes?{interval_minutes:e.intervalMinutes}:{}}},r=nextScheduledAt(i,t);return r?Object.freeze({ok:!0,value:Object.freeze(i),nextRunAt:r.toISOString()}):Object.freeze({ok:!1,code:"schedule_exhausted"})}export function nextScheduledAt(e,t=new Date){if("once"===e?.kind){const n=m(e.at);return f(n)&&n.getTime()>m(t).getTime()?n:null}const n=Number(e?.interval_minutes);if(_.has(n))return new Date(m(t).getTime()+6e4*n);const i=6e4*Math.floor(m(t).getTime()/6e4)+6e4;for(let t=i,n=i+3456e7;t<n;t+=6e4){const n=h(e.timezone,new Date(t));if(n.time===e.time&&("daily"===e.kind||n.weekday===e.weekday))return new Date(t)}return null}export function classifyRunOutcome({result:e=null,evidenceRefs:t=[],pendingControls:n=[],runId:i=null,canceled:r=!1}={}){if("runtime_limit"===e?.subtype)return Object.freeze({outcome:"failed",code:"runtime_limit"});if(r||["aborted","canceled","cancelled","interrupted"].includes(e?.subtype))return Object.freeze({outcome:"canceled",code:"canceled"});const d=(Array.isArray(t)?t:[]).filter(e=>e&&o.has(e.type)&&"string"==typeof e.id&&u.test(e.id)).slice(0,16);if(d.length)return Object.freeze({outcome:"delivered",code:"evidence_delivered",evidence:d});const c=(Array.isArray(n)?n:[]).find(e=>"pending"===e?.status&&e?.id&&e?.request_context?.run_id&&(!i||e.request_context.run_id===i)&&Number.isSafeInteger(Number(e.source_event_from_seq)));return c?Object.freeze({outcome:"needs_decision",code:"pending_pair_control",controlItemId:c.id}):"success"===e?.subtype?Object.freeze({outcome:"failed",code:"missing_deliverable"}):Object.freeze({outcome:"failed",code:e?.subtype||"runtime_failed"})}export function sanitizeScheduledOutcomeIntent({runId:e,result:t=null,evidenceRefs:n=[],canceled:i=!1}={}){if("string"!=typeof e||!u.test(e))return null;const r="string"==typeof t?.subtype&&s.test(t.subtype)?t.subtype:"runtime_failed";return Object.freeze({runId:e,result:Object.freeze({subtype:r}),evidenceRefs:Object.freeze((d=n,(Array.isArray(d)?d:[]).filter(e=>e&&o.has(e.type)&&"string"==typeof e.id&&u.test(e.id)).slice(0,16).map(e=>Object.freeze({type:e.type,id:e.id})))),canceled:!0===i});var d}export function scheduledRunDeadlineRequired({runId:e,deadlineAt:t,outcomeRecorded:n=!1,outcomePending:i=null}={}){return Boolean(e&&Number.isFinite(t)&&!n&&!i)}export function scheduledOutcomeReconciliationComplete(e=[]){return Array.isArray(e)&&0===e.length}export function scheduledRunSpawnAdmission({spawnTimes:e=[],now:i=Date.now(),totalLive:r=0,disabled:d=!1}={},o=t){const c={...t,...o||{}},a=(Array.isArray(e)?e:[]).filter(e=>Number.isFinite(e)&&e>i-c.windowMs).slice(-(c.perWindowCap||1)),u=n({hop:0,spawnTimes:a,now:i,spawnedLive:0,totalLive:r,plan:"free",disabled:d},c);return Object.freeze({...u,spawnTimes:Object.freeze(u.ok?[...a,i].slice(-c.perWindowCap):a)})}export function preflightScheduledRun({schedule:e,occurrence:t,ownerId:n,bridgeId:i,bridgeFencing:r,providerAvailable:d,capsOk:o=!0,now:c=new Date}={}){return e?.enabled?t?.id&&t.schedule_revision===e.revision?!n||!i||!Number.isSafeInteger(r)||r<1||t.owner_id!==n||t.bridge_id!==i||t.bridge_fencing!==r?Object.freeze({ok:!1,code:"owner_bridge_mismatch"}):o?"function"==typeof d&&d(e)?!t.lease_expires_at||m(t.lease_expires_at).getTime()<=m(c).getTime()?Object.freeze({ok:!1,code:"lease_expired"}):Object.freeze({ok:!0,code:"admitted"}):Object.freeze({ok:!1,code:"provider_unavailable"}):Object.freeze({ok:!1,code:"runtime_cap_exceeded"}):Object.freeze({ok:!1,code:"stale_schedule_revision"}):Object.freeze({ok:!1,code:"schedule_disabled"})}const b=async({fetchImpl:e,supabaseUrl:t,headers:n,name:i,body:r})=>{const d=await e(`${String(t).replace(/\/$/,"")}/rest/v1/rpc/${i}`,{method:"POST",headers:n,body:JSON.stringify(r)});if(!d?.ok)throw new Error(`${i}_failed`);return d.json()};export async function pollDueScheduledRuns({enabled:t=!1,fetchImpl:n=globalThis.fetch,supabaseUrl:i,anonKey:r,token:d,roomCode:o,bridgeId:c,bridgeFencing:a,ownerId:s,providerAvailable:l,openTerminal:_,admitRun:p,releaseRun:f,makeTerminalId:h=e,capsOk:y=()=>!0,now:g=new Date}={}){if(!t)return Object.freeze({ok:!1,code:"feature_disabled",runs:[]});if(!("function"==typeof n&&i&&r&&d&&o&&c&&Number.isSafeInteger(a))||a<1||!s||"function"!=typeof _||"function"!=typeof p||"function"!=typeof f||"function"!=typeof h)return Object.freeze({ok:!1,code:"runner_unavailable",runs:[]});const w={apikey:r,Authorization:`Bearer ${d}`,"Content-Type":"application/json"},k=String(o).trim().toUpperCase();try{const e=await b({fetchImpl:n,supabaseUrl:i,headers:w,name:"expire_code_scheduled_runs",body:{p_room_code:k,p_bridge_id:c,p_bridge_fencing:a,p_limit:24}});if(!e?.ok)throw new Error("expire_code_scheduled_runs_failed");const t=await b({fetchImpl:n,supabaseUrl:i,headers:w,name:"list_due_code_schedules",body:{p_room_code:k,p_limit:12}}),r=[];for(const e of Array.isArray(t)?t:[]){if(String(e?.session_code||"").trim().toUpperCase()!==k){r.push({scheduleId:e?.id,code:"room_scope_mismatch"});continue}if(!y(e)){r.push({scheduleId:e.id,code:"runtime_cap_exceeded"});continue}if("function"!=typeof l||!l(e)){r.push({scheduleId:e.id,code:"provider_unavailable"});continue}const t=h();if("string"!=typeof t||!u.test(t)){r.push({scheduleId:e.id,code:"terminal_id_unavailable"});continue}const d={...e.schedule_spec||{},kind:e.schedule_kind||e.kind,timezone:e.timezone},o="once"===d.kind?new Date("9999-12-31T23:59:00.000Z"):nextScheduledAt(d,new Date(e.next_run_at));if(!o){r.push({scheduleId:e.id,code:"next_run_invalid"});continue}const v=`${e.id}:${m(e.next_run_at).toISOString()}`,z=Math.min(1860,Math.max(60,60*e.max_runtime_minutes+60)),I=m(g).getTime()+1e3*z;let x=null;try{x=await p({schedule:e,runId:v,terminalId:t,deadlineAt:I})}catch{x=null}if(!x?.ok){r.push({scheduleId:e.id,code:x?.code||"spawn_not_admitted"});continue}let O=!1;try{const d=await b({fetchImpl:n,supabaseUrl:i,headers:w,name:"claim_due_code_schedule",body:{p_schedule_id:e.id,p_expected_revision:e.revision,p_bridge_id:c,p_bridge_fencing:a,p_occurrence_key:v,p_lease_seconds:z}});if(!d?.ok||!d?.run){r.push({scheduleId:e.id,code:d?.code||"claim_failed"});continue}const u=preflightScheduledRun({schedule:e,occurrence:d.run,ownerId:s,bridgeId:c,bridgeFencing:a,providerAvailable:l,capsOk:!0,now:g});if(!u.ok){r.push({scheduleId:e.id,runId:d.run.id,code:u.code});continue}const p=await b({fetchImpl:n,supabaseUrl:i,headers:w,name:"open_code_scheduled_run",body:{p_run_id:d.run.id,p_bridge_id:c,p_bridge_fencing:a,p_terminal_id:t,p_next_run_at:o.toISOString()}});if(!p?.ok){r.push({scheduleId:e.id,runId:d.run.id,code:p?.code||"open_not_persisted"});continue}const m=p.run||d.run;let f=null;try{f=await _({schedule:e,run:m,terminalId:t,admission:x.lease})}catch{f=null}if(f){O=!0,r.push({scheduleId:e.id,runId:d.run.id,code:"opened"});continue}const h=await b({fetchImpl:n,supabaseUrl:i,headers:w,name:"finish_code_scheduled_run",body:{p_run_id:d.run.id,p_bridge_id:c,p_bridge_fencing:a,p_outcome:"failed",p_outcome_code:"terminal_open_failed",p_evidence_refs:[],p_decision_item_id:null}});r.push({scheduleId:e.id,runId:d.run.id,code:h?.ok?"open_failed":h?.code||"open_failed_unrecorded"})}finally{if(!O)try{await f(x.lease)}catch{}}}return Object.freeze({ok:!0,code:"polled",runs:Object.freeze(r)})}catch{return Object.freeze({ok:!1,code:"runner_read_failed",runs:[]})}}export async function finishScheduledRun({fetchImpl:e=globalThis.fetch,supabaseUrl:t,anonKey:n,token:i,roomCode:r,runId:d,bridgeId:o,bridgeFencing:c,result:a,evidenceRefs:u,canceled:s=!1}={}){if(!(t&&n&&i&&r&&d&&o&&Number.isSafeInteger(c))||c<1)return Object.freeze({ok:!1,code:"outcome_unavailable"});const l={apikey:n,Authorization:`Bearer ${i}`,"Content-Type":"application/json"};try{const n=classifyRunOutcome({result:a,evidenceRefs:u,pendingControls:await b({fetchImpl:e,supabaseUrl:t,headers:l,name:"list_code_pair_controls",body:{p_session_code:String(r).toUpperCase(),p_status:"pending",p_limit:100}}),runId:d,canceled:s}),i=await b({fetchImpl:e,supabaseUrl:t,headers:l,name:"finish_code_scheduled_run",body:{p_run_id:d,p_outcome:n.outcome,p_outcome_code:n.code,p_bridge_id:o,p_bridge_fencing:c,p_evidence_refs:n.evidence||[],p_decision_item_id:n.controlItemId||null}});return Object.freeze({ok:Boolean(i?.ok),code:i?.code||"outcome_write_failed",outcome:n})}catch{return Object.freeze({ok:!1,code:"outcome_write_failed"})}}export async function finishScheduledRunWithRetry(e={},{attempts:t=3,delays:n=[100,400],sleep:i=e=>new Promise(t=>setTimeout(t,e))}={}){const r=Math.max(1,Math.min(5,Number.isInteger(t)?t:3));let d=Object.freeze({ok:!1,code:"outcome_write_failed"});for(let t=0;t<r;t++){if(d=await finishScheduledRun(e),d.ok)return d;t+1<r&&await i(Math.max(0,Math.min(5e3,Number(n[t]??n.at(-1)??0)||0)))}return d}export{d as OUTCOMES};
|