Skip to content

Commit fd7386a

Browse files
christsoclaude
andcommitted
fix(deps): patch @clack/core to restore stdin raw mode on Windows
The block() function in @clack/core intentionally skips restoring stdin from raw mode on Windows, leaving it stuck after spinner stop(). This causes the TUI to freeze after repeated spinner usage as keypresses are consumed as raw data instead of generating proper events. Upstream: bombshell-dev/clack#408, PR bombshell-dev/clack#424 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 27c3949 commit fd7386a

File tree

3 files changed

+19
-0
lines changed

3 files changed

+19
-0
lines changed

bun.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,8 @@
6262
"engines": {
6363
"node": ">=18.0.0",
6464
"bun": ">=1.0.0"
65+
},
66+
"patchedDependencies": {
67+
"@clack/core@1.0.0": "patches/@clack%2Fcore@1.0.0.patch"
6568
}
6669
}

patches/@clack%2Fcore@1.0.0.patch

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
diff --git a/dist/index.mjs b/dist/index.mjs
2+
index 13b8d4d0dcc3a9ec92cc711c11bbdf2a5e43a599..af62036e2d9e7641f7a8cc19c003a40d9cdd1b35 100644
3+
--- a/dist/index.mjs
4+
+++ b/dist/index.mjs
5+
@@ -7,7 +7,7 @@ import w from"picocolors";import{stdout as R,stdin as q}from"node:process";impor
6+
`).map(i=>Et(i,e,s)).join(`
7+
`)}const At=["up","down","left","right","space","enter","cancel"],_={actions:new Set(At),aliases:new Map([["k","up"],["j","down"],["h","left"],["l","right"],["","cancel"],["escape","cancel"]]),messages:{cancel:"Canceled",error:"Something went wrong"},withGuide:!0};function It(t){if(t.aliases!==void 0){const e=t.aliases;for(const s in e){if(!Object.hasOwn(e,s))continue;const i=e[s];_.actions.has(i)&&(_.aliases.has(s)||_.aliases.set(s,i))}}if(t.messages!==void 0){const e=t.messages;e.cancel!==void 0&&(_.messages.cancel=e.cancel),e.error!==void 0&&(_.messages.error=e.error)}t.withGuide!==void 0&&(_.withGuide=t.withGuide!==!1)}function H(t,e){if(typeof t=="string")return _.aliases.get(t)===e;for(const s of t)if(s!==void 0&&H(s,e))return!0;return!1}function _t(t,e){if(t===e)return;const s=t.split(`
8+
`),i=e.split(`
9+
-`),r=Math.max(s.length,i.length),n=[];for(let u=0;u<r;u++)s[u]!==i[u]&&n.push(u);return{lines:n,numLinesBefore:s.length,numLinesAfter:i.length,numLines:r}}const bt=globalThis.process.platform.startsWith("win"),z=Symbol("clack:cancel");function Ct(t){return t===z}function T(t,e){const s=t;s.isTTY&&s.setRawMode(e)}function xt({input:t=q,output:e=R,overwrite:s=!0,hideCursor:i=!0}={}){const r=k.createInterface({input:t,output:e,prompt:"",tabSize:1});k.emitKeypressEvents(t,r),t instanceof J&&t.isTTY&&t.setRawMode(!0);const n=(u,{name:a,sequence:l})=>{const E=String(u);if(H([E,a,l],"cancel")){i&&e.write(I.show),process.exit(0);return}if(!s)return;const g=a==="return"?0:-1,m=a==="return"?-1:0;k.moveCursor(e,g,m,()=>{k.clearLine(e,1,()=>{t.once("keypress",n)})})};return i&&e.write(I.hide),t.once("keypress",n),()=>{t.off("keypress",n),i&&e.write(I.show),t instanceof J&&t.isTTY&&!bt&&t.setRawMode(!1),r.terminal=!1,r.close()}}const rt=t=>"columns"in t&&typeof t.columns=="number"?t.columns:80,nt=t=>"rows"in t&&typeof t.rows=="number"?t.rows:20;function Bt(t,e,s,i=s){const r=rt(t??R);return K(e,r-s.length,{hard:!0,trim:!1}).split(`
10+
+`),r=Math.max(s.length,i.length),n=[];for(let u=0;u<r;u++)s[u]!==i[u]&&n.push(u);return{lines:n,numLinesBefore:s.length,numLinesAfter:i.length,numLines:r}}const bt=globalThis.process.platform.startsWith("win"),z=Symbol("clack:cancel");function Ct(t){return t===z}function T(t,e){const s=t;s.isTTY&&s.setRawMode(e)}function xt({input:t=q,output:e=R,overwrite:s=!0,hideCursor:i=!0}={}){const r=k.createInterface({input:t,output:e,prompt:"",tabSize:1});k.emitKeypressEvents(t,r),t instanceof J&&t.isTTY&&t.setRawMode(!0);const n=(u,{name:a,sequence:l})=>{const E=String(u);if(H([E,a,l],"cancel")){i&&e.write(I.show),process.exit(0);return}if(!s)return;const g=a==="return"?0:-1,m=a==="return"?-1:0;k.moveCursor(e,g,m,()=>{k.clearLine(e,1,()=>{t.once("keypress",n)})})};return i&&e.write(I.hide),t.once("keypress",n),()=>{t.off("keypress",n),i&&e.write(I.show),t instanceof J&&t.isTTY&&t.setRawMode(!1),r.terminal=!1,r.close()}}const rt=t=>"columns"in t&&typeof t.columns=="number"?t.columns:80,nt=t=>"rows"in t&&typeof t.rows=="number"?t.rows:20;function Bt(t,e,s,i=s){const r=rt(t??R);return K(e,r-s.length,{hard:!0,trim:!1}).split(`
11+
`).map((n,u)=>`${u===0?i:s}${n}`).join(`
12+
`)}class x{input;output;_abortSignal;rl;opts;_render;_track=!1;_prevFrame="";_subscribers=new Map;_cursor=0;state="initial";error="";value;userInput="";constructor(e,s=!0){const{input:i=q,output:r=R,render:n,signal:u,...a}=e;this.opts=a,this.onKeypress=this.onKeypress.bind(this),this.close=this.close.bind(this),this.render=this.render.bind(this),this._render=n.bind(this),this._track=s,this._abortSignal=u,this.input=i,this.output=r}unsubscribe(){this._subscribers.clear()}setSubscriber(e,s){const i=this._subscribers.get(e)??[];i.push(s),this._subscribers.set(e,i)}on(e,s){this.setSubscriber(e,{cb:s})}once(e,s){this.setSubscriber(e,{cb:s,once:!0})}emit(e,...s){const i=this._subscribers.get(e)??[],r=[];for(const n of i)n.cb(...s),n.once&&r.push(()=>i.splice(i.indexOf(n),1));for(const n of r)n()}prompt(){return new Promise(e=>{if(this._abortSignal){if(this._abortSignal.aborted)return this.state="cancel",this.close(),e(z);this._abortSignal.addEventListener("abort",()=>{this.state="cancel",this.close()},{once:!0})}this.rl=ot.createInterface({input:this.input,tabSize:2,prompt:"",escapeCodeTimeout:50,terminal:!0}),this.rl.prompt(),this.opts.initialUserInput!==void 0&&this._setUserInput(this.opts.initialUserInput,!0),this.input.on("keypress",this.onKeypress),T(this.input,!0),this.output.on("resize",this.render),this.render(),this.once("submit",()=>{this.output.write(I.show),this.output.off("resize",this.render),T(this.input,!1),e(this.value)}),this.once("cancel",()=>{this.output.write(I.show),this.output.off("resize",this.render),T(this.input,!1),e(z)})})}_isActionKey(e,s){return e===" "}_setValue(e){this.value=e,this.emit("value",this.value)}_setUserInput(e,s){this.userInput=e??"",this.emit("userInput",this.userInput),s&&this._track&&this.rl&&(this.rl.write(this.userInput),this._cursor=this.rl.cursor)}_clearUserInput(){this.rl?.write(null,{ctrl:!0,name:"u"}),this._setUserInput("")}onKeypress(e,s){if(this._track&&s.name!=="return"&&(s.name&&this._isActionKey(e,s)&&this.rl?.write(null,{ctrl:!0,name:"h"}),this._cursor=this.rl?.cursor??0,this._setUserInput(this.rl?.line)),this.state==="error"&&(this.state="active"),s?.name&&(!this._track&&_.aliases.has(s.name)&&this.emit("cursor",_.aliases.get(s.name)),_.actions.has(s.name)&&this.emit("cursor",s.name)),e&&(e.toLowerCase()==="y"||e.toLowerCase()==="n")&&this.emit("confirm",e.toLowerCase()==="y"),this.emit("key",e?.toLowerCase(),s),s?.name==="return"){if(this.opts.validate){const i=this.opts.validate(this.value);i&&(this.error=i instanceof Error?i.message:i,this.state="error",this.rl?.write(this.userInput))}this.state!=="error"&&(this.state="submit")}H([e,s?.name,s?.sequence],"cancel")&&(this.state="cancel"),(this.state==="submit"||this.state==="cancel")&&this.emit("finalize"),this.render(),(this.state==="submit"||this.state==="cancel")&&this.close()}close(){this.input.unpipe(),this.input.removeListener("keypress",this.onKeypress),this.output.write(`
13+
`),T(this.input,!1),this.rl?.close(),this.rl=void 0,this.emit(`${this.state}`,this.value),this.unsubscribe()}restoreCursor(){const e=K(this._prevFrame,process.stdout.columns,{hard:!0,trim:!1}).split(`

0 commit comments

Comments
 (0)