thinkpool-pair 0.7.422 → 0.7.424

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/host-auth.mjs ADDED
@@ -0,0 +1 @@
1
+ import e from"node:fs";import r from"node:os";import t from"node:path";import{randomUUID as o}from"node:crypto";export const HOST_AUTH_TTL_MS=9e5;export const HOST_AUTH_SERVICES=Object.freeze([{id:"github",name:"GitHub"},{id:"vercel",name:"Vercel"},{id:"supabase",name:"Supabase"}]);const n=Object.freeze({vercel:"53.3.1",supabase:"2.116.0"}),i=new Set(["connected","failed","cancelled","expired"]);export function stripAnsi(e){return String(e||"").replace(/\x1B\][^\x07]*(?:\x07|\x1B\\)/g,"").replace(/\x1B\[[0-?]*[ -/]*[@-~]/g,"").replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g,"")}export function parseHostAuthOutput(e,r,t){const o=stripAnsi(`${r||""}${t||""}`).slice(-16e3),n=(o.match(/https:\/\/[^\s]+/g)||[]).map(r=>function(e,r){try{const t=new URL(String(r||"").replace(/[),.;]+$/,""));if("https:"!==t.protocol)return null;if("github"===e&&"github.com"===t.hostname&&"/login/device"===t.pathname)return t.toString();if("vercel"===e&&"vercel.com"===t.hostname&&"/oauth/device"===t.pathname)return t.toString();if("supabase"===e&&"supabase.com"===t.hostname&&"/dashboard/cli/login"===t.pathname)return t.toString()}catch{}return null}(e,r)).find(Boolean)||null;let i=null;if("vercel"===e&&n)try{i=new URL(n).searchParams.get("user_code")}catch{}i||"github"!==e||(i=o.match(/(?:one-time\s+(?:OAuth\s+)?code|code)\s*:?\s*([A-Z0-9]{4}-[A-Z0-9]{4})/i)?.[1]||null);const s="supabase"===e&&/enter your verification code/i.test(o);return{buffer:o,verificationUri:n,userCode:i?String(i).toUpperCase():null,needsInput:s}}function s(r,o=process.env){const n=String(o.PATH||"").split(t.delimiter).filter(Boolean),i="win32"===process.platform?["",".exe",".cmd",".bat"]:[""];return n.some(o=>i.some(n=>{try{return e.accessSync(t.join(o,`${r}${n}`),e.constants.X_OK),!0}catch{return!1}}))}export function resolveHostAuthCommand(e,{env:r=process.env,has:t=s}={}){return HOST_AUTH_SERVICES.some(r=>r.id===e)?"github"===e?t("gh",r)?{command:"gh",args:["auth","login","--hostname","github.com","--web","--git-protocol","https","--skip-ssh-key"]}:null:"vercel"===e&&t("vercel",r)?{command:"vercel",args:["login"]}:"supabase"===e&&t("supabase",r)?{command:"supabase",args:["login","--no-browser"]}:t("npx",r)?"vercel"===e?{command:"npx",args:["--yes",`vercel@${n.vercel}`,"login"]}:"supabase"===e?{command:"npx",args:["--yes",`supabase@${n.supabase}`,"login","--no-browser"]}:null:null:null}function a(e=process.env){const r={...e,NO_COLOR:"1",TERM:"xterm-256color",GH_BROWSER:"false",BROWSER:"false"};for(const e of Object.keys(r))(/^(?:CODEX|CLAUDE|CI$)/.test(e)||/^(?:GH_TOKEN|GITHUB_TOKEN|VERCEL_TOKEN|SUPABASE_ACCESS_TOKEN)$/.test(e))&&delete r[e];return r}function c(e){return e?{flowId:e.flowId,service:e.service,phase:e.phase,verificationUri:e.verificationUri||null,userCode:e.userCode||null,needsInput:!0===e.needsInput,expiresAt:e.expiresAt,error:e.error||null}:null}async function u(){const e=await import("node-pty");return e.default||e}export function createHostAuthManager({loadPty:e=u,resolveCommand:t=resolveHostAuthCommand,now:n=()=>Date.now(),setTimer:s=setTimeout,clearTimer:l=clearTimeout,env:p=process.env,cwd:d=r.homedir()}={}){let h=null;const f=()=>{if(h&&!i.has(h.phase)){h.phase="expired",h.error="This login expired. Start a new one.",h.cancelRequested=!0;try{h.proc?.kill()}catch{}}};return{start:async r=>{if(!HOST_AUTH_SERVICES.some(e=>e.id===r))return{ok:!1,error:"Unsupported host account."};if(h&&!i.has(h.phase))return{ok:!1,error:"Finish or cancel the current login first.",flow:c(h)};const u=t(r,{env:p});if(!u)return{ok:!1,error:"github"===r?"GitHub CLI is not installed on this bridge.":"Neither this provider CLI nor npx is available on this bridge."};let m;try{m=await e()}catch{return{ok:!1,error:"Remote login needs PTY support. Update or reinstall this bridge."}}const g=n();h={flowId:o(),service:r,phase:"starting",startedAt:g,expiresAt:g+9e5,buffer:"",verificationUri:null,userCode:null,needsInput:!1,error:null,cancelRequested:!1,proc:null,timer:null,githubGitConfirmed:!1,githubBrowserConfirmed:!1};try{return h.proc=m.spawn(u.command,u.args,{name:"xterm-256color",cols:100,rows:28,cwd:d,env:a(p)}),h.proc.onData(e=>{if(!h||i.has(h.phase))return;"github"===r&&String(e).includes("")&&h.proc?.write("");const t=parseHostAuthOutput(r,h.buffer,e);h.buffer=t.buffer,"github"===r&&!h.githubGitConfirmed&&/authenticate git with your github credentials/i.test(h.buffer)&&(h.githubGitConfirmed=!0,h.proc?.write("y\r")),"github"===r&&!h.githubBrowserConfirmed&&/press enter to open .*github\.com.*browser/i.test(h.buffer)&&(h.githubBrowserConfirmed=!0,h.proc?.write("\r")),t.verificationUri&&(h.verificationUri=t.verificationUri),t.userCode&&(h.userCode=t.userCode),t.needsInput&&(h.needsInput=!0),h.verificationUri&&(h.phase="action_required")}),h.proc.onExit(({exitCode:e})=>{h&&(h.timer&&l(h.timer),h.timer=null,h.cancelRequested||"expired"===h.phase?"expired"!==h.phase&&(h.phase="cancelled"):0===e?(h.phase="connected",h.error=null):(h.phase="failed",h.error="The provider did not complete this login. Start a new one."),h.buffer="",h.proc=null)}),h.timer=s(f,9e5),h.timer?.unref?.(),{ok:!0,flow:c(h)}}catch{return h?.timer&&l(h.timer),h.phase="failed",h.error="The provider login could not be started on this bridge.",h.proc=null,{ok:!1,error:h.error,flow:c(h)}}},status:e=>!h||e&&h.flowId!==e?null:c(h),submit:(e,r)=>{if(!h||h.flowId!==e)return{ok:!1,error:"This login is no longer active."};if("supabase"!==h.service||!h.needsInput||"action_required"!==h.phase)return{ok:!1,error:"This login is not waiting for a verification code."};const t=String(r||"").trim();if(!/^[A-Za-z0-9_-]{4,128}$/.test(t))return{ok:!1,error:"Enter the verification code shown by Supabase."};try{return h.proc?.write(`${t}\r`),h.needsInput=!1,h.phase="waiting",{ok:!0,flow:c(h)}}catch{return{ok:!1,error:"The verification code could not be delivered."}}},cancel:e=>{if(!h||h.flowId!==e)return{ok:!1,error:"This login is no longer active."};if(i.has(h.phase))return{ok:!0,flow:c(h)};h.cancelRequested=!0,h.phase="cancelled",h.error=null,h.timer&&l(h.timer),h.timer=null;try{h.proc?.kill()}catch{}return h.proc=null,h.buffer="",{ok:!0,flow:c(h)}}}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thinkpool-pair",
3
- "version": "0.7.422",
3
+ "version": "0.7.424",
4
4
  "description": "Connect Claude Code, Codex, or Hermes on your computer to a thinkpool Code room.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",
@@ -16,6 +16,7 @@
16
16
  "turn-receipt.mjs",
17
17
  "host-memory.mjs",
18
18
  "host-capacity.mjs",
19
+ "host-auth.mjs",
19
20
  "keep-awake.mjs",
20
21
  "sdk-smoke.mjs",
21
22
  "sdk-admission.mjs",
@@ -1,21 +1,22 @@
1
1
  {
2
2
  "format": 1,
3
3
  "package": "thinkpool-pair",
4
- "version": "0.7.422",
4
+ "version": "0.7.424",
5
5
  "kind": "minified",
6
- "minifiedModules": 142,
7
- "sourceModuleBytes": 1869140,
8
- "artifactModuleBytes": 853592,
6
+ "minifiedModules": 143,
7
+ "sourceModuleBytes": 1884566,
8
+ "artifactModuleBytes": 861748,
9
9
  "files": {
10
- "package.json": "50b208fe37b1b774c6c692ef6391f2d2505558ff7a204b4132da02433e5455ca",
10
+ "package.json": "30ea2d7ad63c994106c485e465a560618019cd03f48afaaa312bad4bff7546fc",
11
11
  "LICENSE": "8a030197ca1cad9669909ca14c9ad15cf48d9fe551da526ccaf1fca993eddb23",
12
- "bridge.mjs": "2cd1640b61ca6cd2f6e21122d650f9342450debe4861bf9ce024f9096271e9b6",
12
+ "bridge.mjs": "a5c51c1cfc4f1e906a02d2f0ecc6aa2a0e275556359102fe24f3b743f11b648a",
13
13
  "bridge-service.sh": "b64f27c473ca8f3a49190fd08c23947ab14ca9958d70b6fa53c7bddc2be91403",
14
14
  "command-guidance.mjs": "b9b967b59ff4e77c9613abb0f28858bf3ac5b106a509e471039777b53bec3e29",
15
15
  "abort-turn-barrier.mjs": "3734a5b7e2e940ec6d7fa8b5b04935e1429a23d1bd9e92b2ac2a2ecd9f77c75e",
16
16
  "turn-receipt.mjs": "4945f32699112aeb86bd2ca371e61c6534b7135b395e957697852cf4fef61989",
17
17
  "host-memory.mjs": "44dab373e0a11b5f9ed1e5f1105643b51b1ce417781efb207a569d991865b4ae",
18
18
  "host-capacity.mjs": "13f127951dc9d5adffc6b8da0617977e6c4aaefdf0e72d92c7fdb84ee8ad9a12",
19
+ "host-auth.mjs": "8f7ce9af058f7d844494c0f870b8d4b8f762d8c88ff6e49090a5e61431637cdd",
19
20
  "keep-awake.mjs": "6c0a51409321f2564082b414b00696d22a740ca98180b1f628828c5fe19995c7",
20
21
  "sdk-smoke.mjs": "dfe509863ede8a12780914939740f7f9fee36d3980f8fcb57803a33593ac4056",
21
22
  "sdk-admission.mjs": "eb33725cc33347b900c75289eae7917f6ce3526203711515aecd48d43b3c895d",
@@ -102,7 +103,7 @@
102
103
  "session-search.mjs": "d606fbab5c47357071e4919107aa00ad090f6e7d7e6dc929e0ac5a4d0cb2c538",
103
104
  "session-store.mjs": "fa3f7a27a8a7c49bb89364fb28c9c2680f7f487d4b4125329ab4a0ba9362bd8c",
104
105
  "side-lane.mjs": "6a6bc6d8041872ba4472d70fd1cece62607417982a72b8721f4fbed77655cc6d",
105
- "worker-completion.mjs": "72210efc40e5b3861e60fedff9cd455956563c6874270617e85573e58b5586a0",
106
+ "worker-completion.mjs": "3eab6abf9cde32e62b8bef676023bd59759836f88887d578d2db2e9fa092a151",
106
107
  "cross-terminal.mjs": "1e8b3320b0bd79ee8d532cc2fbf1825e46428c1c4c5efbb3877c69e1e8e3a21e",
107
108
  "cloud-session-transcript.mjs": "1e8b3000d628eac0cff171901d6fed13983528b42e23e277583ef65bf8f9fa2b",
108
109
  "pair-bus.mjs": "cbc28cee7f4f06b2213091e0b7b07d61c1d01f0ff207c5c6d808cd616ece221e",
@@ -146,7 +147,7 @@
146
147
  "service.mjs": "412ee48ad7b1dd281063f30f2519b077aa4cc92305e6780ac226293756f6e6f8",
147
148
  "supervisor-ready.mjs": "7d5e4ebe3c7a93e0888dd335fb4556a670e55a80a89b861c8a44feac159cd840",
148
149
  "presence.mjs": "2516ebb4474a8f45dd881530335c2174af9cde44be8eed6896ff8c62497b6e2b",
149
- "account.mjs": "baf751dfb696d85035f00214390148ad4f7418636ef3ea84e86197f09dedc33d",
150
+ "account.mjs": "0380949c3fa360880fc0aaede372d8592ae0d07140c2fd667d2dd4639a762ee6",
150
151
  "auth-store.mjs": "c4d41ee7cdc34c2002c6dd50d32e53ace0a3f03a116ffa930ed94a437e247625",
151
152
  "key-shape.mjs": "a4113293d52eeba39b05e70a3e0345abc1ddc181b4f236b413bde0ae11a3f646",
152
153
  "supabase-key.mjs": "041bde6cf50b15f6426daaf738374abc9647861d8c1dd3d85cedc45684271888",
@@ -1 +1 @@
1
- export const WORKER_COMPLETION_CAP=24;export const CASCADE_KEY_CAP=80;export const CASCADE_TASK_CAP=120;export const CASCADE_DEPENDENCY_CAP=16;export const CASCADE_WAVE_TASK_CAP=24;const e=(e,r=160)=>String(e||"").replace(/\s+/g," ").trim().slice(0,r),r=(r,t)=>{const a=e(r,t);return/^[A-Za-z0-9][A-Za-z0-9._:-]*$/.test(a)?a:null},t=/^[a-f0-9]{40}(?:[a-f0-9]{24})?$/,a=new Set(["clean","dirty","unavailable"]);export function normalizeCascadeMetadata(e){if(!e||"object"!=typeof e||Array.isArray(e))return null;const t=r(e.cascadeId,80),a=r(e.taskKey,120),n=r(e.waveId,80),o="wave"===e.wakePolicy?"wave":"immediate"===e.wakePolicy?"immediate":null;if(!(t&&a&&n&&o))return null;const s=[...new Set((Array.isArray(e.dependencyKeys)?e.dependencyKeys:[]).map(e=>r(e,120)).filter(Boolean))].slice(0,16),c=[...new Set((Array.isArray(e.expectedTaskKeys)?e.expectedTaskKeys:[]).map(e=>r(e,120)).filter(Boolean))].slice(0,24);return"wave"!==o||c.length&&c.includes(a)?{cascadeId:t,taskKey:a,waveId:n,dependencyKeys:s,expectedTaskKeys:c,wakePolicy:o}:null}export function workerCompletionRecord({workerId:r,workerName:n,turnRev:o,subtype:s,cascade:c,resultSummary:i,git:l}={}){const d=e(r,80),u=Math.max(0,Number(o)||0);if(!d||!u)return null;const w={workerId:d,workerRef:d.slice(0,8),workerName:e(n,80)||null,turnRev:u,outcome:s&&"success"!==s?e(s,40):"completed"},y=normalizeCascadeMetadata(c);y&&(w.cascade=y);const m=e(i,280).replace(/(?:[A-Za-z0-9._-]+[\\/]){1,}[A-Za-z0-9._-]+/g,"[path redacted]");m&&(w.resultSummary=m);const h=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return null;const r=a.has(e.worktreeState)?e.worktreeState:null;if(!r)return null;const n={worktreeState:r},o=String(e.headSha||"").trim().toLowerCase();return t.test(o)&&(n.headSha=o),"boolean"==typeof e.headChanged&&(n.headChanged=e.headChanged),Number.isSafeInteger(e.changedFileCount)&&e.changedFileCount>=0&&e.changedFileCount<=1e5&&(n.changedFileCount=e.changedFileCount),n}(l);return h&&(w.git=h),w}export function selectWorkerCompletionBatch(e){const r=(Array.isArray(e)?e:[]).filter(e=>e?.workerId&&Number(e?.turnRev)>0).slice(-24),t=r.filter(e=>"wave"!==e?.cascade?.wakePolicy);if(t.length)return t;const a=new Set;for(const e of r){const t=normalizeCascadeMetadata(e?.cascade);if(!t||"wave"!==t.wakePolicy)continue;const n=`${t.cascadeId}:${t.waveId}`;if(a.has(n))continue;a.add(n);const o=r.filter(e=>e?.cascade?.cascadeId===t.cascadeId&&e?.cascade?.waveId===t.waveId),s=new Set(o.map(e=>e?.cascade?.taskKey).filter(Boolean));if(t.expectedTaskKeys.every(e=>s.has(e)))return o}return[]}export function enqueueWorkerCompletion(e,r,t=24){const a=(Array.isArray(e)?e:[]).filter(e=>e?.workerId&&Number(e?.turnRev)>0);if(!r?.workerId||Number(r?.turnRev)<=0)return a.slice(-t);const n=`${r.workerId}:${r.turnRev}`;return[...a.filter(e=>`${e.workerId}:${e.turnRev}`!==n),r].slice(-t)}export function acknowledgeWorkerCompletions(e,r){const t=new Set((Array.isArray(r)?r:[]).filter(e=>e?.workerId&&Number(e?.turnRev)>0).map(e=>`${e.workerId}:${e.turnRev}`));return(Array.isArray(e)?e:[]).filter(e=>e?.workerId&&Number(e?.turnRev)>0).filter(e=>!t.has(`${e.workerId}:${e.turnRev}`))}export function workerCompletionPrompt(r){const t=(Array.isArray(r)?r:[]).filter(e=>e?.workerId&&Number(e?.turnRev)>0).slice(-24);if(!t.length)return"";const a=t.map(r=>{const t=r.workerName?`${r.workerName} (${r.workerRef||String(r.workerId).slice(0,8)})`:r.workerRef||String(r.workerId).slice(0,8),a=normalizeCascadeMetadata(r.cascade),n=a?.dependencyKeys?.slice(0,3)||[],o=n.length?`; after=${n.map(r=>e(r,40)).join(",")}${a.dependencyKeys.length>n.length?",+"+(a.dependencyKeys.length-n.length):""}`:"",s=a?` [cascade: ${a.cascadeId}/${a.waveId}; task=${a.taskKey}${o}]`:"",c=r.git?` [git: ${r.git.worktreeState}${r.git.headSha?`, ${r.git.headSha.slice(0,8)}`:""}${Number.isSafeInteger(r.git.changedFileCount)?`, ${r.git.changedFileCount} changed`:""}]`:"",i=r.resultSummary?` — ${r.resultSummary}`:"";return`- ${t}: ${r.outcome||"completed"}${s}${c}${i}`}).join("\n");return`[thinkpool worker completion signal]\nYour owned worker lane${1===t.length?" has finished and is":"s have finished and are"} idle:\n${a}\n\nContinue the current task now. Call read_terminal exactly once for each finished worker, requesting only the last 8 lines unless its compact handback needs slightly more, then verify and integrate its result. Leave each finished worker visible in Ensemble so a person can review it and dismiss it with the X. Do not call close_terminal merely because a worker finished. Do not wait for a person to prompt you.`}
1
+ export const WORKER_COMPLETION_CAP=24;export const CASCADE_KEY_CAP=80;export const CASCADE_TASK_CAP=120;export const CASCADE_DEPENDENCY_CAP=16;export const CASCADE_WAVE_TASK_CAP=24;const e=(e,r=160)=>String(e||"").replace(/\s+/g," ").trim().slice(0,r),r=(r,t)=>{const a=e(r,t);return/^[A-Za-z0-9][A-Za-z0-9._:-]*$/.test(a)?a:null},t=/^[a-f0-9]{40}(?:[a-f0-9]{24})?$/,a=new Set(["clean","dirty","unavailable"]);export function normalizeCascadeMetadata(e){if(!e||"object"!=typeof e||Array.isArray(e))return null;const t=r(e.cascadeId,80),a=r(e.taskKey,120),n=r(e.waveId,80),o="wave"===e.wakePolicy?"wave":"immediate"===e.wakePolicy?"immediate":null;if(!(t&&a&&n&&o))return null;const c=[...new Set((Array.isArray(e.dependencyKeys)?e.dependencyKeys:[]).map(e=>r(e,120)).filter(Boolean))].slice(0,16),s=[...new Set((Array.isArray(e.expectedTaskKeys)?e.expectedTaskKeys:[]).map(e=>r(e,120)).filter(Boolean))].slice(0,24);return"wave"!==o||s.length&&s.includes(a)?{cascadeId:t,taskKey:a,waveId:n,dependencyKeys:c,expectedTaskKeys:s,wakePolicy:o}:null}export function workerCompletionRecord({workerId:r,workerName:n,turnRev:o,subtype:c,cascade:s,resultSummary:i,git:l}={}){const d=e(r,80),u=Math.max(0,Number(o)||0);if(!d||!u)return null;const m={workerId:d,workerRef:d.slice(0,8),workerName:e(n,80)||null,turnRev:u,outcome:c&&"success"!==c?e(c,40):"completed"},w=normalizeCascadeMetadata(s);w&&(m.cascade=w);const y=e(i,280).replace(/(?:[A-Za-z0-9._-]+[\\/]){1,}[A-Za-z0-9._-]+/g,"[path redacted]");y&&(m.resultSummary=y);const f=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return null;const r=a.has(e.worktreeState)?e.worktreeState:null;if(!r)return null;const n={worktreeState:r},o=String(e.headSha||"").trim().toLowerCase();return t.test(o)&&(n.headSha=o),"boolean"==typeof e.headChanged&&(n.headChanged=e.headChanged),Number.isSafeInteger(e.changedFileCount)&&e.changedFileCount>=0&&e.changedFileCount<=1e5&&(n.changedFileCount=e.changedFileCount),n}(l);return f&&(m.git=f),m}export function selectWorkerCompletionBatch(e){const r=(Array.isArray(e)?e:[]).filter(e=>e?.workerId&&Number(e?.turnRev)>0).slice(-24),t=r.filter(e=>!0!==e?.collected&&"wave"!==e?.cascade?.wakePolicy);if(t.length)return t;const a=new Set;for(const e of r){const t=normalizeCascadeMetadata(e?.cascade);if(!t||"wave"!==t.wakePolicy)continue;const n=`${t.cascadeId}:${t.waveId}`;if(a.has(n))continue;a.add(n);const o=r.filter(e=>e?.cascade?.cascadeId===t.cascadeId&&e?.cascade?.waveId===t.waveId),c=new Set(o.map(e=>e?.cascade?.taskKey).filter(Boolean));if(t.expectedTaskKeys.every(e=>c.has(e))){const e=o.filter(e=>!0!==e.collected);if(e.length)return e}}return[]}export function enqueueWorkerCompletion(e,r,t=24){const a=(Array.isArray(e)?e:[]).filter(e=>e?.workerId&&Number(e?.turnRev)>0);if(!r?.workerId||Number(r?.turnRev)<=0)return a.slice(-t);const n=`${r.workerId}:${r.turnRev}`;return a.some(e=>`${e.workerId}:${e.turnRev}`===n)?a.slice(-t):[...a,r].slice(-t)}const n=e=>`${e.workerId}:${e.turnRev}`,o=e=>`${e.cascadeId}:${e.waveId}`;function c(e){const r=(Array.isArray(e)?e:[]).filter(e=>e?.workerId&&Number(e?.turnRev)>0),t=new Map;for(const e of r){const r=normalizeCascadeMetadata(e.cascade);if(!r||"wave"!==r.wakePolicy)continue;const a=o(r);t.has(a)||t.set(a,[]),t.get(a).push({item:e,meta:r})}const a=new Set;for(const[e,r]of t){const t=new Set(r.map(({meta:e})=>e.taskKey));r.every(({meta:e})=>e.expectedTaskKeys.every(e=>t.has(e)))&&r.every(({item:e})=>!0===e.collected)&&a.add(e)}return r.filter(e=>{const r=normalizeCascadeMetadata(e.cascade);return r&&"wave"===r.wakePolicy?!a.has(o(r)):!0!==e.collected})}function s(e,r){return c((Array.isArray(e)?e:[]).filter(e=>e?.workerId&&Number(e?.turnRev)>0).map(e=>r.has(n(e))&&!0!==e.collected?{...e,collected:!0}:e))}export function acknowledgeWorkerCompletions(e,r){return s(e,new Set((Array.isArray(r)?r:[]).filter(e=>e?.workerId&&Number(e?.turnRev)>0).map(n)))}export function acknowledgeWorkerCompletionRead(e,r){const t=String(r||"").trim();return t?s(e,new Set((Array.isArray(e)?e:[]).filter(e=>e?.workerId===t&&Number(e?.turnRev)>0).map(n))):c(e)}export function workerCompletionPrompt(r){const t=(Array.isArray(r)?r:[]).filter(e=>e?.workerId&&Number(e?.turnRev)>0&&!0!==e.collected).slice(-24);if(!t.length)return"";const a=t.map(r=>{const t=r.workerName?`${r.workerName} (${r.workerRef||String(r.workerId).slice(0,8)})`:r.workerRef||String(r.workerId).slice(0,8),a=normalizeCascadeMetadata(r.cascade),n=a?.dependencyKeys?.slice(0,3)||[],o=n.length?`; after=${n.map(r=>e(r,40)).join(",")}${a.dependencyKeys.length>n.length?",+"+(a.dependencyKeys.length-n.length):""}`:"",c=a?` [cascade: ${a.cascadeId}/${a.waveId}; task=${a.taskKey}${o}]`:"",s=r.git?` [git: ${r.git.worktreeState}${r.git.headSha?`, ${r.git.headSha.slice(0,8)}`:""}${Number.isSafeInteger(r.git.changedFileCount)?`, ${r.git.changedFileCount} changed`:""}]`:"",i=r.resultSummary?` — ${r.resultSummary}`:"";return`- ${t}: ${r.outcome||"completed"}${c}${s}${i}`}).join("\n");return`[thinkpool worker completion signal]\nYour owned worker lane${1===t.length?" has finished and is":"s have finished and are"} idle:\n${a}\n\nContinue the current task now. Call read_terminal exactly once for each finished worker, requesting only the last 8 lines unless its compact handback needs slightly more, then verify and integrate its result. Leave each finished worker visible in Ensemble so a person can review it and dismiss it with the X. Do not call close_terminal merely because a worker finished. Do not wait for a person to prompt you.`}