@usebitl/cli 0.1.10 → 0.1.12

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/web/index.html CHANGED
@@ -14,7 +14,7 @@
14
14
  <meta property="og:description" content="AI 코딩 에이전트(Claude Code, Codex 등) 작업 현황판. 나를 기다리는 작업을 놓치지 않게. Claude Code·Codex 작업 내용은 종단간 암호화." />
15
15
  <meta property="og:image" content="https://usebitl.com/icon-512.png" />
16
16
  <title>BITL</title>
17
- <script type="module" crossorigin src="/assets/index-BqtWjy33.js"></script>
17
+ <script type="module" crossorigin src="/assets/index-DTnW4H6T.js"></script>
18
18
  <link rel="stylesheet" crossorigin href="/assets/index-P_OV048r.css">
19
19
  </head>
20
20
  <body>
package/web/sw.js CHANGED
@@ -1,3 +1,3 @@
1
- (function(){var e=/^s1\.[A-Za-z0-9_-]{87}\.[A-Za-z0-9_-]{16}\.[A-Za-z0-9_-]+$/,t=()=>globalThis.crypto.subtle,n=new TextEncoder,r=new TextDecoder(`utf-8`,{fatal:!0});function i(e){let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)}function a(e){if(!/^[A-Za-z0-9_-]*$/.test(e))throw Error(`invalid base64url`);let t=atob(e.replace(/-/g,`+`).replace(/_/g,`/`)+`=`.repeat((4-e.length%4)%4));return Uint8Array.from(t,e=>e.charCodeAt(0))}function o(e){let t=e.length-1;for(;t>=0&&e[t]===0;)t--;if(t<0||e[t]!==128)throw Error(`invalid padding`);return e.subarray(0,t)}async function s(e,i,s){if(i.startsWith(`s1.`)){if(!e.inbox)throw Error(`no inbox key`);return u(e.inbox,i,s)}let c=i.split(`.`);if(c.length!==4||c[0]!==`v1`)throw Error(`unknown format`);if(c[1]!==e.kid)throw Error(`different key`);let l=await t().decrypt({name:`AES-GCM`,iv:a(c[2]),additionalData:n.encode(s)},e.enc,a(c[3]));return r.decode(o(new Uint8Array(l)))}var c={name:`ECDH`,namedCurve:`P-256`};async function l(e,r,i){let a=await t().importKey(`raw`,e,`HKDF`,!1,[`deriveKey`]);return t().deriveKey({name:`HKDF`,hash:`SHA-256`,salt:new Uint8Array(r),info:n.encode(`bitl/v1/inbox`)},a,{name:`AES-GCM`,length:256},!1,[i])}async function u(i,s,u){let d=s.split(`.`);if(d.length!==4||!e.test(s))throw Error(`unknown format`);let f=a(d[1]),p=await t().importKey(`raw`,f,c,!1,[]),m=await t().deriveBits({name:`ECDH`,public:p},i,256),h=await t().decrypt({name:`AES-GCM`,iv:a(d[2]),additionalData:n.encode(u)},await l(m,f,`decrypt`),a(d[3]));return r.decode(o(new Uint8Array(h)))}var d=e=>`approval:${e}`;async function f(e,t,n){let r=JSON.parse(await s(e,n,d(t)));if(typeof r?.tool!=`string`||typeof r.summary!=`string`)throw Error(`invalid approval request`);return r}var p=new WeakMap;function m(e){let t=p.get(e);return t||(t=globalThis.crypto.subtle.importKey(`raw`,e.master,`HKDF`,!1,[`deriveKey`]).then(e=>globalThis.crypto.subtle.deriveKey({name:`HKDF`,hash:`SHA-256`,salt:new Uint8Array,info:new TextEncoder().encode(`bitl/v1/approve`)},e,{name:`HMAC`,hash:`SHA-256`,length:256},!1,[`sign`,`verify`])),p.set(e,t)),t}var h=(e,t)=>new TextEncoder().encode(`bitl/approval/v1\n${e}\n${t}`);async function g(e,t,n){let r=await globalThis.crypto.subtle.sign(`HMAC`,await m(e),h(t,n));return i(new Uint8Array(r))}new TextEncoder;var _=`bitl-mv9juty3`;self.addEventListener(`install`,e=>{e.waitUntil(caches.open(_).then(e=>e.addAll([`/app`,`/manifest.webmanifest`,`/icon-192.png`])).then(()=>self.skipWaiting()))}),self.addEventListener(`activate`,e=>{e.waitUntil(caches.keys().then(e=>Promise.all(e.filter(e=>e.startsWith(`bitl-`)&&e!==_).map(e=>caches.delete(e)))).then(()=>self.clients.claim()))}),self.addEventListener(`fetch`,e=>{let t=e.request;if(t.method!==`GET`)return;let n=new URL(t.url);if(!(n.origin!==self.location.origin||n.pathname.startsWith(`/api/`))){if(t.mode===`navigate`){e.respondWith(fetch(t).then(e=>(e.ok&&caches.open(_).then(t=>t.put(n.pathname,e.clone())),e)).catch(async()=>await caches.match(n.pathname)??await caches.match(`/app`)??Response.error()));return}n.pathname.startsWith(`/assets/`)&&e.respondWith(caches.match(t).then(e=>e??fetch(t).then(e=>(e.ok&&caches.open(_).then(n=>n.put(t,e.clone())),e))))}});function v(){return new Promise(e=>{let t=indexedDB.open(`bitl`,1);t.onupgradeneeded=()=>t.result.createObjectStore(`keys`),t.onerror=()=>e(null),t.onsuccess=()=>{let n=t.result;try{let t=n.transaction(`keys`,`readonly`).objectStore(`keys`).get(`content`);t.onsuccess=()=>e(t.result??null),t.onerror=()=>e(null)}catch{e(null)}finally{n.close()}}})}var y={ko:{headline:{permission:`권한 승인이 필요해요`,question:`질문에 답해주세요`,plan:`계획 승인이 필요해요`,elicitation:`입력이 필요해요`,input:`입력이 필요해요`},waiting:`나를 기다리고 있어요`,error:`오류로 멈췄어요`,oneWaiting:`작업 1건이 나를 기다리고 있어요`,settled:{allow:`✓ 허용됨`,deny:`✕ 거부됨`,cancelled:`터미널에서 답했어요`,expired:`시간이 지나 터미널로 넘어갔어요`},settledTitle:`승인 요청 끝남`,settledOther:`끝났어요`,approval:`승인 요청`,approvalLocked:`🔒 이 기기의 키로 요청 내용을 열 수 없어요. 눌러서 확인하세요.`,allow:`허용`,deny:`거부`,failNoKey:`이 기기에 키가 없어 답할 수 없어요. 앱을 열어 확인하세요.`,failNetwork:`보내지 못했어요 (네트워크). 앱을 열어 다시 답하세요.`,failSettled:`이미 다른 곳에서 답했거나 PC 가 터미널에서 승인하기로 했어요.`,failGone:`요청이 끝났어요 (시간이 지남).`},en:{headline:{permission:`Needs your permission`,question:`Has a question for you`,plan:`Needs plan approval`,elicitation:`Needs your input`,input:`Needs your input`},waiting:`Waiting for you`,error:`Stopped with an error`,oneWaiting:`1 task is waiting for you`,settled:{allow:`✓ Allowed`,deny:`✕ Denied`,cancelled:`Answered in the terminal`,expired:`Timed out — moved to the terminal`},settledTitle:`Approval request ended`,settledOther:`Ended`,approval:`Approval request`,approvalLocked:`🔒 This device’s key can’t decrypt the request. Tap to check.`,allow:`Allow`,deny:`Deny`,failNoKey:`No key on this device, so it can’t answer. Open the app to check.`,failNetwork:`Couldn’t send (network). Open the app and answer again.`,failSettled:`Already answered elsewhere, or the PC chose to approve in the terminal.`,failGone:`The request has ended (timed out).`}};async function b(){try{let e=await(await caches.open(`bitl.prefs`)).match(`/lang`),t=e?await e.text():``;if(t===`ko`||t===`en`)return y[t]}catch{}return self.navigator.language.toLowerCase().startsWith(`ko`)?y.ko:y.en}var x=e=>`approval:${e}`;async function S(e){let t=x(e.id),n=await b();await self.registration.showNotification(n.settledTitle,{body:n.settled[e.status]??n.settledOther,icon:`/icon-192.png`,badge:`/badge-96.png`,tag:t,silent:!0,data:{key:e.key}}),await new Promise(e=>setTimeout(e,4e3));for(let e of await self.registration.getNotifications({tag:t}))e.close()}async function C(e){let t=await v(),n=e.request;if(!n){let t=await fetch(`/api/approvals/${encodeURIComponent(e.id)}`).catch(()=>null);n=t?.ok?(await t.json()).request:void 0}let r=t&&n?await f(t,e.id,n).catch(()=>void 0):void 0;for(let t of await self.registration.getNotifications({tag:e.key}))t.close();let i=await b();await self.registration.showNotification(r?.project?`${r.project} · ${i.approval}`:i.approval,{body:r?[r.summary,r.description].filter(Boolean).join(`
1
+ (function(){var e=/^s1\.[A-Za-z0-9_-]{87}\.[A-Za-z0-9_-]{16}\.[A-Za-z0-9_-]+$/,t=()=>globalThis.crypto.subtle,n=new TextEncoder,r=new TextDecoder(`utf-8`,{fatal:!0});function i(e){let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)}function a(e){if(!/^[A-Za-z0-9_-]*$/.test(e))throw Error(`invalid base64url`);let t=atob(e.replace(/-/g,`+`).replace(/_/g,`/`)+`=`.repeat((4-e.length%4)%4));return Uint8Array.from(t,e=>e.charCodeAt(0))}function o(e){let t=e.length-1;for(;t>=0&&e[t]===0;)t--;if(t<0||e[t]!==128)throw Error(`invalid padding`);return e.subarray(0,t)}async function s(e,i,s){if(i.startsWith(`s1.`)){if(!e.inbox)throw Error(`no inbox key`);return u(e.inbox,i,s)}let c=i.split(`.`);if(c.length!==4||c[0]!==`v1`)throw Error(`unknown format`);if(c[1]!==e.kid)throw Error(`different key`);let l=await t().decrypt({name:`AES-GCM`,iv:a(c[2]),additionalData:n.encode(s)},e.enc,a(c[3]));return r.decode(o(new Uint8Array(l)))}var c={name:`ECDH`,namedCurve:`P-256`};async function l(e,r,i){let a=await t().importKey(`raw`,e,`HKDF`,!1,[`deriveKey`]);return t().deriveKey({name:`HKDF`,hash:`SHA-256`,salt:new Uint8Array(r),info:n.encode(`bitl/v1/inbox`)},a,{name:`AES-GCM`,length:256},!1,[i])}async function u(i,s,u){let d=s.split(`.`);if(d.length!==4||!e.test(s))throw Error(`unknown format`);let f=a(d[1]),p=await t().importKey(`raw`,f,c,!1,[]),m=await t().deriveBits({name:`ECDH`,public:p},i,256),h=await t().decrypt({name:`AES-GCM`,iv:a(d[2]),additionalData:n.encode(u)},await l(m,f,`decrypt`),a(d[3]));return r.decode(o(new Uint8Array(h)))}var d=e=>`approval:${e}`;async function f(e,t,n){let r=JSON.parse(await s(e,n,d(t)));if(typeof r?.tool!=`string`||typeof r.summary!=`string`)throw Error(`invalid approval request`);return r}var p=new WeakMap;function m(e){let t=p.get(e);return t||(t=globalThis.crypto.subtle.importKey(`raw`,e.master,`HKDF`,!1,[`deriveKey`]).then(e=>globalThis.crypto.subtle.deriveKey({name:`HKDF`,hash:`SHA-256`,salt:new Uint8Array,info:new TextEncoder().encode(`bitl/v1/approve`)},e,{name:`HMAC`,hash:`SHA-256`,length:256},!1,[`sign`,`verify`])),p.set(e,t)),t}var h=(e,t)=>new TextEncoder().encode(`bitl/approval/v1\n${e}\n${t}`);async function g(e,t,n){let r=await globalThis.crypto.subtle.sign(`HMAC`,await m(e),h(t,n));return i(new Uint8Array(r))}new TextEncoder;var _=`bitl-mvaxy934`;self.addEventListener(`install`,e=>{e.waitUntil(caches.open(_).then(e=>e.addAll([`/app`,`/manifest.webmanifest`,`/icon-192.png`])).then(()=>self.skipWaiting()))}),self.addEventListener(`activate`,e=>{e.waitUntil(caches.keys().then(e=>Promise.all(e.filter(e=>e.startsWith(`bitl-`)&&e!==_).map(e=>caches.delete(e)))).then(()=>self.clients.claim()))}),self.addEventListener(`fetch`,e=>{let t=e.request;if(t.method!==`GET`)return;let n=new URL(t.url);if(!(n.origin!==self.location.origin||n.pathname.startsWith(`/api/`))){if(t.mode===`navigate`){e.respondWith(fetch(t).then(e=>(e.ok&&caches.open(_).then(t=>t.put(n.pathname,e.clone())),e)).catch(async()=>await caches.match(n.pathname)??await caches.match(`/app`)??Response.error()));return}n.pathname.startsWith(`/assets/`)&&e.respondWith(caches.match(t).then(e=>e??fetch(t).then(e=>(e.ok&&caches.open(_).then(n=>n.put(t,e.clone())),e))))}});function v(){return new Promise(e=>{let t=indexedDB.open(`bitl`,1);t.onupgradeneeded=()=>t.result.createObjectStore(`keys`),t.onerror=()=>e(null),t.onsuccess=()=>{let n=t.result;try{let t=n.transaction(`keys`,`readonly`).objectStore(`keys`).get(`content`);t.onsuccess=()=>e(t.result??null),t.onerror=()=>e(null)}catch{e(null)}finally{n.close()}}})}var y={ko:{headline:{permission:`권한 승인이 필요해요`,question:`질문에 답해주세요`,plan:`계획 승인이 필요해요`,elicitation:`입력이 필요해요`,input:`입력이 필요해요`},waiting:`나를 기다리고 있어요`,error:`오류로 멈췄어요`,oneWaiting:`작업 1건이 나를 기다리고 있어요`,settled:{allow:`✓ 허용됨`,deny:`✕ 거부됨`,cancelled:`터미널에서 답했어요`,expired:`시간이 지나 터미널로 넘어갔어요`},settledTitle:`승인 요청 끝남`,settledOther:`끝났어요`,approval:`승인 요청`,approvalLocked:`🔒 이 기기의 키로 요청 내용을 열 수 없어요. 눌러서 확인하세요.`,allow:`허용`,deny:`거부`,failNoKey:`이 기기에 키가 없어 답할 수 없어요. 앱을 열어 확인하세요.`,failNetwork:`보내지 못했어요 (네트워크). 앱을 열어 다시 답하세요.`,failSettled:`이미 다른 곳에서 답했거나 PC 가 터미널에서 승인하기로 했어요.`,failGone:`요청이 끝났어요 (시간이 지남).`},en:{headline:{permission:`Needs your permission`,question:`Has a question for you`,plan:`Needs plan approval`,elicitation:`Needs your input`,input:`Needs your input`},waiting:`Waiting for you`,error:`Stopped with an error`,oneWaiting:`1 task is waiting for you`,settled:{allow:`✓ Allowed`,deny:`✕ Denied`,cancelled:`Answered in the terminal`,expired:`Timed out — moved to the terminal`},settledTitle:`Approval request ended`,settledOther:`Ended`,approval:`Approval request`,approvalLocked:`🔒 This device’s key can’t decrypt the request. Tap to check.`,allow:`Allow`,deny:`Deny`,failNoKey:`No key on this device, so it can’t answer. Open the app to check.`,failNetwork:`Couldn’t send (network). Open the app and answer again.`,failSettled:`Already answered elsewhere, or the PC chose to approve in the terminal.`,failGone:`The request has ended (timed out).`}};async function b(){try{let e=await(await caches.open(`bitl.prefs`)).match(`/lang`),t=e?await e.text():``;if(t===`ko`||t===`en`)return y[t]}catch{}return self.navigator.language.toLowerCase().startsWith(`ko`)?y.ko:y.en}var x=e=>`approval:${e}`;async function S(e){let t=x(e.id),n=await b();await self.registration.showNotification(n.settledTitle,{body:n.settled[e.status]??n.settledOther,icon:`/icon-192.png`,badge:`/badge-96.png`,tag:t,silent:!0,data:{key:e.key}}),await new Promise(e=>setTimeout(e,4e3));for(let e of await self.registration.getNotifications({tag:t}))e.close()}async function C(e){let t=await v(),n=e.request;if(!n){let t=await fetch(`/api/approvals/${encodeURIComponent(e.id)}`).catch(()=>null);n=t?.ok?(await t.json()).request:void 0}let r=t&&n?await f(t,e.id,n).catch(()=>void 0):void 0;for(let t of await self.registration.getNotifications({tag:e.key}))t.close();let i=await b();await self.registration.showNotification(r?.project?`${r.project} · ${i.approval}`:i.approval,{body:r?[r.summary,r.description].filter(Boolean).join(`
2
2
  `):i.approvalLocked,icon:`/icon-192.png`,badge:`/badge-96.png`,tag:x(e.id),data:{key:e.key,approvalId:e.id,readable:!!r},requireInteraction:!0,actions:r?[{action:`allow`,title:i.allow},{action:`deny`,title:i.deny}]:[{action:`deny`,title:i.deny}]})}async function w(e,t,n){let[r,i]=await Promise.all([v(),b()]),a=t=>self.registration.showNotification(i.approval,{body:t,icon:`/icon-192.png`,badge:`/badge-96.png`,tag:x(e),data:{key:n}});if(!r)return a(i.failNoKey);let o=await fetch(`/api/approvals/${encodeURIComponent(e)}/decide`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({decision:t,sig:await g(r,e,t)})}).catch(()=>null);if(!o)return a(i.failNetwork);if(o.status===409)return a(i.failSettled);if(!o.ok)return a(i.failGone)}async function T(e){if(e&&`kind`in e&&e.kind===`approval`)return C(e);if(e&&`kind`in e&&e.kind===`approval-settled`)return S(e);let t=e,n=await b();if(t&&(await self.registration.getNotifications()).some(e=>e.data?.approvalId&&e.data.key===t.key))return;if(!t||t.v!==1){await self.registration.showNotification(`BITL`,{body:n.oneWaiting,icon:`/icon-192.png`,tag:`bitl`});return}let r=await v(),i=async e=>r&&e?s(r,e,t.key).catch(()=>void 0):void 0,[a,o,c,l]=await Promise.all([i(t.sealed.title),i(t.sealed.activity),i(t.sealed.project),i(t.sealed.message)]),u=t.status===`error`?n.error:n.headline[t.reason??``]??n.waiting,d=(e,t)=>e.length>t?`${e.slice(0,t-1)}…`:e,f=[o??l,a&&a!==o?a:void 0].filter(Boolean).map(e=>d(e,140));await self.registration.showNotification(c?`${c} · ${u}`:u,{body:f.length?f.join(`
3
3
  `):n.oneWaiting,icon:`/icon-192.png`,badge:`/badge-96.png`,tag:t.key,data:{key:t.key},renotify:!0}),await self.navigator.setAppBadge?.(t.attention).catch(()=>{})}self.addEventListener(`push`,e=>{let t=null;try{t=e.data?.json()??null}catch{}e.waitUntil(T(t))}),self.addEventListener(`notificationclick`,e=>{e.notification.close();let t=e.notification.data,n=t?.key;if(t?.approvalId&&(e.action===`allow`||e.action===`deny`)){e.waitUntil(w(t.approvalId,e.action,n));return}let r=n?`/app#s=${encodeURIComponent(n)}`:`/app`;e.waitUntil((async()=>{let e=(await self.clients.matchAll({type:`window`,includeUncontrolled:!0})).find(e=>new URL(e.url).origin===self.location.origin);if(e){await e.focus(),e.postMessage({type:`open-session`,key:n});return}await self.clients.openWindow(r)})())})})();