@lovek4d/kickflip 0.6.0 → 0.6.1

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 (41) hide show
  1. package/CONTEXT.md +15 -11
  2. package/SKILL.md +7 -7
  3. package/bin/doctor.mjs +5 -4
  4. package/bin/install.mjs +3 -3
  5. package/board/bin/board.mjs +26 -12
  6. package/board/domain.mjs +7 -7
  7. package/board/headless.mjs +9 -9
  8. package/board/public/app-cards.js +23 -44
  9. package/board/public/app-lanes.js +4 -7
  10. package/board/public/app-threads.js +12 -8
  11. package/board/public/prototype-switcher.js +7 -2
  12. package/board/public/shell.js +4 -3
  13. package/board/public/sidebar.css +5 -0
  14. package/board/public/sidebar.js +3 -0
  15. package/board/public/style.css +11 -19
  16. package/board/public/ui-cards.js +21 -15
  17. package/board/public/ui-enums.js +2 -2
  18. package/board/public/ui-header.js +4 -6
  19. package/board/public/ui-hub.js +7 -4
  20. package/board/public/ui-order.js +1 -1
  21. package/board/public/ui-page-header.js +1 -1
  22. package/board/public/ui-sidebar.js +11 -5
  23. package/board/public/ui-snapshot.js +1 -1
  24. package/board/public/ui.js +3 -2
  25. package/board/public/view-hub.js +3 -1
  26. package/board/public/view-questions.js +1 -1
  27. package/board/server.mjs +20 -19
  28. package/board/stop.mjs +1 -1
  29. package/board/store.mjs +27 -25
  30. package/board/transcript.mjs +2 -2
  31. package/hooks-plugin/hooks/board-data-gate.mjs +9 -6
  32. package/hub/front-door.mjs +1 -1
  33. package/hub/hub.mjs +1 -1
  34. package/hub/sessions.mjs +2 -2
  35. package/hub/try.mjs +7 -7
  36. package/hub/usage.mjs +3 -3
  37. package/package.json +1 -1
  38. package/shared/card-prs.mjs +1 -1
  39. package/shared/machine-gate.mjs +2 -2
  40. package/shared/tailscale.mjs +1 -1
  41. package/shared/usage-gate.mjs +1 -1
@@ -1 +1 @@
1
- var P=Object.defineProperty;var t=(e,s)=>P(e,"name",{value:s,configurable:!0});import W from"node:fs";import f from"node:os";import j from"node:path";import{usageReader as F}from"../hub/usage.mjs";import{readSettingsFile as h,writeSettingsFile as $,readCodexShare as H,readClaudeModel as U}from"../hub/push.mjs";import{FOREVER as C,durationEnd as I,storedEnd as v}from"../hub/duration.mjs";import{codexStatus as G,codexStatusReader as L,effectiveCodexShare as B}from"./codex.mjs";import{MACHINE_NORMAL as z,readMachineState as J}from"./machine-gate.mjs";const K=t(e=>Number.isInteger(e)&&e>=50&&e<=100&&e%5===0,"validPauseAt"),l=t(e=>Number(e),"timeOf"),T=["five_hour","seven_day"],b=t((e,s)=>e===C||typeof e=="string"&&Date.parse(e)>l(s)?e:null,"pausedUntil");function V(e,s=new Date){if(e==="off")return null;const o=I(new Date(l(s)),e);if(!o)throw Object.assign(new Error("A pause ends after now and within 30 days: <n>m, <n>h, <n>d, <n>w, forever or a date and time; or off."),{status:400});return v(o)}t(V,"pauseEnd");const q=t(e=>e===C?"until the owner resumes it":`until ${e}`,"pauseUntilWords");function Q({claude:e,codex:s,pauseAt:o=90,keepGoing:n,hubPause:a,boardPause:u,machine:r=z,now:d=Date.now()}={}){const c=K(o)?o:90,x=t(w=>c===100?null:T.find(i=>{const p=w?.[i];return p?.state==="live"&&Number.isFinite(p.used_percentage)&&p.used_percentage>=c&&(!p.resets_at||Date.parse(p.resets_at)>l(d))})||null,"past"),g=t((w,i)=>({window:i,used:i?w[i].used_percentage:null,resets_at:i?w[i].resets_at:null}),"details"),m=x(e),k=g(e,m),R=m&&n?.window===m&&Math.abs(Date.parse(n.until)-Date.parse(k.resets_at))<=3e5&&l(d)<Date.parse(n.until),M=x(s),S={past:!!M,...g(s,M)},_=b(a,d)?"hub":b(u,d)?"board":null;return _?{pause_at:c,state:"paused",manual:_,window:null,used:null,resets_at:b(_==="hub"?a:u,d),codex:S,machine:r}:{pause_at:c,state:m?R?"going":"paused":"normal",manual:null,...k,codex:S,machine:r}}t(Q,"usageGate");const X=t(e=>{try{return JSON.parse(W.readFileSync(j.join(e,"board.json"),"utf8"))||{}}catch{return{}}},"readBoardJson"),Y=t((e,s=Date.now())=>b(X(e).paused_until,s),"boardPausedUntil"),D=new Map;function A({home:e=f.homedir(),now:s=Date.now(),dir:o=null}={}){let n=D.get(e);n||(n={now:l(s)},n.usage=F({home:e,now:t(()=>n.now,"now")}),n.codex=L({home:e,now:t(()=>n.now,"now")}),D.set(e,n)),n.now=l(s);const a=h(e);return Q({...n.usage({codexShare:H(n.codex(),e)}),pauseAt:a.pauseAt,keepGoing:a.keepGoing,hubPause:a.paused_until,boardPause:o?Y(o,s):null,machine:J(e),now:s})}t(A,"readUsageGate");function le(e,{home:s=f.homedir(),now:o=new Date}={}){const n=V(e,o),{paused_until:a,...u}=h(s);return $(n?{...u,paused_until:n}:u,s),n}t(le,"setHubPause");function pe(e,{home:s=f.homedir()}={}){if(!/^(?:50|55|60|65|70|75|80|85|90|95|100)$/.test(String(e)))throw Object.assign(new Error("pause-at takes 50..100 in steps of 5"),{status:400});$({...h(s),pauseAt:Number(e)},s)}t(pe,"setPauseAt");function fe(e,{home:s=f.homedir(),now:o=Date.now()}={}){if(!["on","off"].includes(e))throw Object.assign(new Error("keep-going takes on or off"),{status:400});const n=h(s);if(e==="on"){const a=A({home:s,now:o});if(a.state!=="paused")throw Object.assign(new Error("Nothing is paused."),{status:409});n.keepGoing={window:a.window,until:a.resets_at}}else delete n.keepGoing;$(n,s)}t(fe,"setKeepGoing");const he=t(e=>{try{return["github-change","check-github","card-unblocked","overnight-triage","pr-review","owner-check-broken"].includes(JSON.parse(e).kind)}catch{return!1}},"heldUsageEvent");function xe({home:e=f.homedir(),now:s=Date.now(),card:o={}}={}){const n=G({home:e}),a={codex:n.reason??"usable",claudeModel:U(e),size:o.size??null,cardModel:o.model??null},u=t(d=>{const{model:c,reason:x}=Z(a.claudeModel,o);return{kind:"claude",model:c,reason:`${d} ${x}`,inputs:a}},"claude");if(!n.usable)return u(n.words);if(a.codexShare=B(h(e).codexShare,n),a.codexShare==="off")return u("Codex share is off.");const r=A({home:e,now:s});return Object.assign(a,{pauseAt:r.pause_at,codexUsage:r.codex}),r.codex.past?u(`Codex is at ${Math.round(r.codex.used)}%, past the ${r.pause_at}% line until ${r.codex.resets_at}.`):{kind:"codex",reason:`Codex share is ${a.codexShare} and Codex is under the ${r.pause_at}% line.`,inputs:a}}t(xe,"builderPick");const E={opus:"Opus",sonnet:"Sonnet"};function Z(e,s){return e!=="auto"?{model:e,reason:`Claude model is ${E[e]}.`}:s.model?{model:s.model,reason:`Claude model is Auto and the card asks for Claude ${E[s.model]}.`}:s.size==="small"?{model:"sonnet",reason:"Claude model is Auto and the card is small."}:{model:"opus",reason:"Claude model is Auto and the card isn't small."}}t(Z,"claudePick");const N={hub:["the hub","Pause hub in Hub settings"],board:["this board","Pause board in Board settings"]},ee=t(e=>e.manual?`Work is paused: the owner paused ${N[e.manual][0]} ${q(e.resets_at)}. ${N[e.manual][1]} resumes it.`:e.state==="paused"?se(e):y(e),"pauseReason"),y=t(e=>`Work is held: this Mac is busy (${e.machine.reason}). It starts again when the Mac eases.`,"busyReason"),me="Held: this Mac is busy. It starts again when the Mac eases.",we=t(e=>e.state==="paused"||e.machine.state==="busy","holdsWork"),be=t(e=>`usage paused ${e.resets_at} ${e.manual?`manual ${e.manual}`:`${e.window} ${e.used}%`}`,"pausedLine"),se=t(e=>`Work is paused: Claude's ${O(e.window)} usage is at ${Math.round(e.used)}%. Resumes at ${e.resets_at}. The owner can tap Keep going on the Hub page.`,"usagePauseReason"),_e=t((e,s)=>!!e.manual||e.machine.state==="busy"||(s==="codex"?e.codex.past:e.state==="paused"),"heldFor"),O=t(e=>e==="five_hour"?"5-hour":"weekly","windowWord"),$e=t((e,s)=>s==="codex"&&!e.manual&&e.codex.past?`Codex is paused: its ${O(e.codex.window)} usage is at ${Math.round(e.codex.used)}%, past the ${e.pause_at}% line. Resumes at ${e.codex.resets_at}.`:s==="codex"&&!e.manual?y(e):ee(e),"pauseReasonFor");export{me as MACHINE_HELD_LINE,Y as boardPausedUntil,xe as builderPick,_e as heldFor,he as heldUsageEvent,we as holdsWork,V as pauseEnd,ee as pauseReason,$e as pauseReasonFor,q as pauseUntilWords,be as pausedLine,A as readUsageGate,le as setHubPause,fe as setKeepGoing,pe as setPauseAt,Q as usageGate,K as validPauseAt};
1
+ var v=Object.defineProperty;var n=(e,s)=>v(e,"name",{value:s,configurable:!0});import B from"node:fs";import x from"node:os";import I from"node:path";import{usageReader as U}from"../hub/usage.mjs";import{readSettingsFile as _,writeSettingsFile as $,readCodexShare as G,readClaudeModel as L}from"../hub/push.mjs";import{FOREVER as N,durationEnd as T,storedEnd as z}from"../hub/duration.mjs";import{codexStatus as J,codexStatusReader as K,effectiveCodexShare as V}from"./codex.mjs";import{MACHINE_NORMAL as q,readMachineState as Q}from"./machine-gate.mjs";const X=n(e=>Number.isInteger(e)&&e>=50&&e<=100&&e%5===0,"validPauseAt"),c=n(e=>Number(e),"timeOf"),R=["five_hour","seven_day"],b=n((e,s)=>e===N||typeof e=="string"&&Date.parse(e)>c(s)?e:null,"pausedUntil");function Y(e,s=new Date){if(e==="off")return null;const o=T(new Date(c(s)),e);if(!o)throw Object.assign(new Error("A pause ends after now and within 30 days: <n>m, <n>h, <n>d, <n>w, forever or a date and time; or off."),{status:400});return z(o)}n(Y,"pauseEnd");const Z=n(e=>e===N?"until the owner resumes it":`until ${e}`,"pauseUntilWords");function ee({claude:e,codex:s,pauseAt:o=90,keepGoing:t,hubPause:a,boardPause:r,machine:u=q,start:w=null,now:i=Date.now()}={}){const p=X(o)?o:90,D=n(l=>p===100?null:R.find(d=>{const f=l?.[d];return f?.state==="live"&&Number.isFinite(f.used_percentage)&&f.used_percentage>=p&&(!f.resets_at||Date.parse(f.resets_at)>c(i))})||null,"past"),k=n((l,d)=>({window:d,used:d?l[d].used_percentage:null,resets_at:d?l[d].resets_at:null}),"details"),m=D(e),A=k(e,m),C=n((l,d,f)=>l?.window===d&&Math.abs(Date.parse(l.until)-Date.parse(f))<=3e5&&c(i)<Date.parse(l.until),"covers"),j=m&&!t?.near&&C(t,m,A.resets_at),h=m?null:te(e,p,i);h&&(h.going=!!t?.near&&C(t,h.window,h.resets_at),h.waiting=!h.going&&!!w&&!w.reported&&c(i)-Date.parse(w.at)<se);const M=D(s),E={past:!!M,...k(s,M)},g=b(a,i)?"hub":b(r,i)?"board":null;return g?{pause_at:p,state:"paused",manual:g,window:null,used:null,resets_at:b(g==="hub"?a:r,i),near:null,codex:E,machine:u}:{pause_at:p,state:m?j?"going":"paused":"normal",manual:null,...A,near:h,codex:E,machine:u}}n(ee,"usageGate");const se=10*6e4,y=n(e=>2*e-100,"nearFrom");function te(e,s,o){if(s===100)return null;const t=R.find(a=>{const r=e?.[a];return r?.state==="live"&&Number.isFinite(r.used_percentage)&&r.used_percentage>=y(s)&&(!r.resets_at||Date.parse(r.resets_at)>c(o))});return t?{window:t,used:e[t].used_percentage,resets_at:e[t].resets_at,from:y(s)}:null}n(te,"nearOf");const ne=n(e=>{try{return JSON.parse(B.readFileSync(I.join(e,"board.json"),"utf8"))||{}}catch{return{}}},"readBoardJson"),ae=n((e,s=Date.now())=>b(ne(e).paused_until,s),"boardPausedUntil"),O=new Map;function W({home:e=x.homedir(),now:s=Date.now(),dir:o=null}={}){let t=O.get(e);t||(t={now:c(s)},t.usage=U({home:e,now:n(()=>t.now,"now")}),t.codex=K({home:e,now:n(()=>t.now,"now")}),O.set(e,t)),t.now=c(s);const a=_(e);return ee({...t.usage({codexShare:G(t.codex(),e)}),pauseAt:a.pauseAt,keepGoing:a.keepGoing,hubPause:a.paused_until,boardPause:o?ae(o,s):null,machine:Q(e),now:s})}n(W,"readUsageGate");function be(e,{home:s=x.homedir(),now:o=new Date}={}){const t=Y(e,o),{paused_until:a,...r}=_(s);return $(t?{...r,paused_until:t}:r,s),t}n(be,"setHubPause");function ge(e,{home:s=x.homedir()}={}){if(!/^(?:50|55|60|65|70|75|80|85|90|95|100)$/.test(String(e)))throw Object.assign(new Error("pause-at takes 50..100 in steps of 5"),{status:400});$({..._(s),pauseAt:Number(e)},s)}n(ge,"setPauseAt");function $e(e,{home:s=x.homedir(),now:o=Date.now()}={}){if(!["on","off"].includes(e))throw Object.assign(new Error("keep-going takes on or off"),{status:400});const t=_(s);if(e==="on"){const a=W({home:s,now:o});if(a.state==="paused")t.keepGoing={window:a.window,until:a.resets_at};else if(a.near)t.keepGoing={window:a.near.window,until:a.near.resets_at,near:!0};else throw Object.assign(new Error("Nothing is paused."),{status:409})}else delete t.keepGoing;$(t,s)}n($e,"setKeepGoing");const Se=n(e=>{try{return["github-change","check-github","card-unblocked","overnight-triage","pr-review","owner-check-broken"].includes(JSON.parse(e).kind)}catch{return!1}},"heldUsageEvent");function De({home:e=x.homedir(),now:s=Date.now(),card:o={}}={}){const t=J({home:e}),a={codex:t.reason??"usable",claudeModel:L(e),size:o.size??null,cardModel:o.model??null},r=n(w=>{const{model:i,reason:p}=oe(a.claudeModel,o);return{kind:"claude",model:i,reason:`${w} ${p}`,inputs:a}},"claude");if(!t.usable)return r(t.words);if(a.codexShare=V(_(e).codexShare,t),a.codexShare==="off")return r("Codex share is off.");const u=W({home:e,now:s});return Object.assign(a,{pauseAt:u.pause_at,codexUsage:u.codex}),u.codex.past?r(`Codex is at ${Math.round(u.codex.used)}%, past the ${u.pause_at}% line until ${u.codex.resets_at}.`):{kind:"codex",reason:`Codex share is ${a.codexShare} and Codex is under the ${u.pause_at}% line.`,inputs:a}}n(De,"builderPick");const F={opus:"Opus",sonnet:"Sonnet"};function oe(e,s){return e!=="auto"?{model:e,reason:`Claude model is ${F[e]}.`}:s.model?{model:s.model,reason:`Claude model is Auto and the card asks for Claude ${F[s.model]}.`}:s.size==="small"?{model:"sonnet",reason:"Claude model is Auto and the card is small."}:{model:"opus",reason:"Claude model is Auto and the card isn't small."}}n(oe,"claudePick");const H={hub:["the hub","Pause hub in Hub settings"],board:["this board","Pause board in Board settings"]},re=n(e=>e.manual?`Work is paused: the owner paused ${H[e.manual][0]} ${Z(e.resets_at)}. ${H[e.manual][1]} resumes it.`:e.state==="paused"?ie(e):e.machine.state==="busy"||!e.near?.waiting?P(e):ue(e),"pauseReason"),ue=n(e=>`Work is held: Claude's ${S(e.near.window)} usage is at ${Math.round(e.near.used)}%, near the ${e.pause_at}% line, so agents start one at a time, each once the last one has reported its usage. The owner can tap Keep going on the Hub page.`,"nearReason"),P=n(e=>`Work is held: the host is busy (${e.machine.reason}). It starts again when the host eases.`,"busyReason"),ke="Held: the host is busy. It starts again when the host eases.",Ae=n(e=>e.state==="paused"||e.machine.state==="busy","holdsWork"),Ce=n(e=>`usage paused ${e.resets_at} ${e.manual?`manual ${e.manual}`:`${e.window} ${e.used}%`}`,"pausedLine"),ie=n(e=>`Work is paused: Claude's ${S(e.window)} usage is at ${Math.round(e.used)}%. Resumes at ${e.resets_at}. The owner can tap Keep going on the Hub page.`,"usagePauseReason"),de=n((e,s)=>!!e.manual||e.machine.state==="busy"||(s==="codex"?e.codex.past:e.state==="paused"),"heldFor"),Me=n((e,s)=>de(e,s)||s!=="codex"&&!!e.near?.waiting,"launchHeld"),S=n(e=>e==="five_hour"?"5-hour":"weekly","windowWord"),Ee=n((e,s)=>s==="codex"&&!e.manual&&e.codex.past?`Codex is paused: its ${S(e.codex.window)} usage is at ${Math.round(e.codex.used)}%, past the ${e.pause_at}% line. Resumes at ${e.codex.resets_at}.`:s==="codex"&&!e.manual?P(e):re(e),"pauseReasonFor");export{ke as MACHINE_HELD_LINE,ae as boardPausedUntil,De as builderPick,de as heldFor,Se as heldUsageEvent,Ae as holdsWork,Me as launchHeld,Y as pauseEnd,re as pauseReason,Ee as pauseReasonFor,Z as pauseUntilWords,Ce as pausedLine,W as readUsageGate,be as setHubPause,$e as setKeepGoing,ge as setPauseAt,ee as usageGate,X as validPauseAt};