hivefloor 0.1.0 → 0.1.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.
- package/bin.mjs +14 -14
- package/package.json +1 -1
package/bin.mjs
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{a as e,c as t,o as n,r,s as i,t as a}from"./urls-CuA4EHSE.mjs";import{createRequire as o}from"node:module";import{spawn as s}from"node:child_process";import{createHash as c,createHmac as l,randomBytes as u}from"node:crypto";import{homedir as d}from"node:os";import{createInterface as f}from"node:readline/promises";import{
|
|
3
|
-
`)}\n`)}async function
|
|
4
|
-
`)}\n`),1;let s=JSON.stringify(o.config);if(Buffer.byteLength(s)>5120)return t.stderr(`hivefloor: ${r} is too large for a Worker variable (5120 bytes). Shorten names or remove projects.\n`),1;let c=
|
|
5
|
-
`),p)}const
|
|
6
|
-
`)}`}}async function Pe(e,t,n){let r=
|
|
2
|
+
import{a as e,c as t,o as n,r,s as i,t as a}from"./urls-CuA4EHSE.mjs";import{createRequire as o}from"node:module";import{spawn as s}from"node:child_process";import{createHash as c,createHmac as l,randomBytes as u}from"node:crypto";import{homedir as d}from"node:os";import{createInterface as f}from"node:readline/promises";import{constants as p,existsSync as m,realpathSync as h}from"node:fs";import{appendFile as g,copyFile as _,mkdir as v,readFile as y,readdir as ee,realpath as te,rename as ne,rm as b,stat as x,writeFile as re}from"node:fs/promises";import{basename as S,dirname as C,join as w,posix as ie,relative as ae,resolve as T,win32 as oe}from"node:path";import{parseArgs as E}from"node:util";function se(e,t,n){return l(`sha256`,e).update(`${String(t)}.${n}`).digest(`hex`)}async function ce(e,t){let n=Math.floor(t.now()/1e3);try{return(await t.fetch(t.endpoint,{method:`POST`,headers:{"content-type":`application/json`,"x-office-timestamp":String(n),"x-office-signature":se(t.secret,n,e),...t.dryRun===!0?{"x-office-dry-run":`1`}:{}},body:e,redirect:`error`,signal:AbortSignal.timeout(1500)})).status}catch{return}}function le(e){if(e!==void 0)try{return h(e)}catch{return e}}function ue(e,t){return{file:e,args:t!==void 0&&/\.(c|m)?js$/.test(t)?[t]:[]}}function de(e,t,n=`both`){let r=0,i=e.length;if(n===`both`)for(;r<i&&t.includes(e.charAt(r));)r++;for(;i>r&&t.includes(e.charAt(i-1));)i--;return e.slice(r,i)}function fe(e,t){return/^[A-Za-z0-9_@%+=:,./\\-]+$/.test(e)?e:t?`"${e.replaceAll(`"`,`""`)}"`:`'${e.replaceAll(`'`,`'\\''`)}'`}function pe(e){return e!==void 0&&/\.(c|m)?js$/.test(e)}function me(e){let t=t=>fe(t,e.windows);return pe(e.script)?/[\\/]_npx[\\/]/.test(e.script)?{command:`npx --yes hivefloor@${e.version} hook`,warning:`You ran init through npx, so every hook call will start npx. Install hivefloor globally (npm install -g hivefloor) or use the standalone binary, then run init again.`}:{command:`${t(e.execPath)} ${t(e.script)} hook`}:{command:`${t(e.execPath)} hook`}}function he(e){let t;try{t=new URL(e.trim())}catch{return}if(t.protocol!==`https:`&&t.protocol!==`http:`)return;let n=de(t.pathname,`/`,`end`),r=n.endsWith(`/ingest`)?n.slice(0,-7):n;return`${t.origin}${r}/ingest`}function ge(e){return e.replace(/\/ingest$/,``)}function D(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function _e(e){if(!(e.length===0||e.length>8388608))try{let t=JSON.parse(e);return D(t)?t:void 0}catch{return}}function O(e,t){let n=e?.[t];return typeof n==`string`&&n.length>0?n:void 0}function ve(e,t){let n=e?.[t];return D(n)?n:void 0}function k(e,t){let n=e?.[t];return Array.isArray(n)?n:[]}function A(e,t){let n=e.trim();return(n===`~`||n.startsWith(`~/`)||n.startsWith(`~\\`))&&(n=t.home+n.slice(1)),t.windows&&(n=n.replaceAll(`\\`,`/`).toLowerCase()),n=n.replace(/\/{2,}/g,`/`),n.length>1&&n.endsWith(`/`)&&(n=n.slice(0,-1)),n}function ye(e,t){return t===`/`||e===t||e.startsWith(`${t}/`)}function be(e,t,n){let r=A(e,n),i;for(let e of t){let t=A(e.path,n);ye(r,t)&&(i===void 0||t.length>i.length)&&(i={length:t.length,project:e})}return i?.project.public!==!0||i.project.name===void 0?{isPublic:!1}:{isPublic:!0,name:i.project.name}}function j(e){return D(e)&&typeof e.name==`string`?e.name:void 0}function xe(e,t,n){return e.map((e,r)=>r===t?n:e)}function Se(e,t,n,r){let i=A(t,r),a=e.findIndex(e=>D(e)&&typeof e.path==`string`&&A(e.path,r)===i),o=e[a];if(!D(o))return{projects:[...e,{path:t,public:!0,name:n}],change:`added`};if(o.public===!0&&o.name===n)return{projects:e,change:`unchanged`};let s=o.public===!0?j(o):void 0;return{projects:xe(e,a,{...o,public:!0,name:n}),change:`updated`,...s===void 0?{}:{previousName:s}}}function Ce(e,t){let n=t.name.toLowerCase(),r=e.findIndex(e=>j(e)?.trim().toLowerCase()===n),i=e[r],a=j(i);return!D(i)||a===void 0?{kind:`ok`,projects:[...e,t],change:`added`}:a===t.name?t.color===void 0||i.color===t.color?{kind:`ok`,projects:e,change:`unchanged`}:{kind:`ok`,projects:xe(e,r,{...i,color:t.color}),change:`updated`}:{kind:`conflict`,existing:a}}async function M(e){try{return JSON.parse(await y(e,`utf8`))}catch{return}}async function N(e,t,n=384){await v(C(e),{recursive:!0,mode:448});let r=`${e}.${u(6).toString(`hex`)}.tmp`;try{await re(r,t,{mode:n}),await ne(r,e)}catch(e){throw await b(r,{force:!0}),e}}async function we(e,t){let n;try{n=await ee(e)}catch{return}await Promise.all(n.filter(e=>e.startsWith(t)).map(t=>b(w(e,t),{force:!0})))}function P(e,t,n){let r=n?oe:ie,i=e.HIVEFLOOR_HOME??(n?r.join(e.APPDATA??r.join(t,`AppData`,`Roaming`),`hivefloor`):r.join(e.XDG_CONFIG_HOME??r.join(t,`.config`),`hivefloor`)),a=w(i,`state`);return{dir:i,config:w(i,`config.json`),secret:w(i,`secret`),stateDir:a,configCache:w(a,`config.cache.json`),debugLog:w(i,`debug.log`),recordings:w(i,`recordings`)}}function Te(e,t,n){return w(e,n===void 0?`${t}.json`:`${t}.${n}.json`)}function Ee(e){return w(e.stateDir,`office.cache.json`)}async function F(e){let t;try{t=await y(e.config,`utf8`)}catch{return}try{let e=JSON.parse(t);return D(e)?e:null}catch{return null}}async function I(e,t){let n=`${JSON.stringify(t,null,2)}\n`,{checkMachineConfig:r}=await import(`./validate-config-WKKxO7uI.mjs`),i=r(n);return i.ok&&await N(e.config,n),i}function L(e,...t){e.stdout(`${t.join(`
|
|
3
|
+
`)}\n`)}async function R(e){let t;try{t=await y(e.config,`utf8`)}catch{return}let n=c(`sha256`).update(t).digest(`hex`),r=await M(e.configCache);if(D(r)&&r.digest===n&&D(r.config))return r.config;let{validateMachineConfig:i}=await import(`./validate-config-WKKxO7uI.mjs`),a=i(t);return a!==void 0&&await N(e.configCache,JSON.stringify({digest:n,config:a})),a}async function z(e){try{let t=(await y(e.secret,`utf8`)).trim();return t.length>0?t:void 0}catch{return}}async function De(e){for(let t of[e,w(e,`apps`,`relay`)]){let n=await Oe(e,t);if(n!==void 0)return n}}async function Oe(e,t){try{let n=o(w(t,`package.json`)).resolve(`wrangler/package.json`),r=ae(h(e),h(n));if(r.startsWith(`..`)||T(r)===r)return;let i=JSON.parse(await y(n,`utf8`)),a=D(i)?i.bin:void 0,s=typeof a==`string`?a:D(a)&&typeof a.wrangler==`string`?a.wrangler:void 0;return s===void 0?void 0:w(C(n),s)}catch{return}}const ke={config:{type:`string`,default:`office.config.json`},"wrangler-config":{type:`string`,default:w(`apps`,`relay`,`wrangler.jsonc`)},"dry-run":{type:`boolean`},"push-secret":{type:`boolean`}};async function Ae(e,t){let n=P(e.env,e.home,e.windows),r=await z(n);if(r!==void 0)return t?r:void 0;if(!t){if(!e.interactive)return;let t=await e.ask(`Create a secret and set it on the relay? This replaces any secret it already has. [Y/n] `);if(/^n/i.test(t.trim()))return}let i=e.randomSecret();return await N(n.secret,`${i}\n`,384),i}async function je(e,t){let{values:n}=E({args:[...e],options:ke,strict:!0}),r=T(t.cwd,n.config),i;try{i=await y(r,`utf8`)}catch{return t.stderr(`hivefloor: no ${r}. Copy office.config.example.json to office.config.json and edit it.\n`),1}let{checkOfficeConfig:a}=await import(`./validate-config-WKKxO7uI.mjs`),o=a(i);if(!o.ok)return t.stderr(`hivefloor: ${r} is invalid:\n ${o.problems.join(`
|
|
4
|
+
`)}\n`),1;let s=JSON.stringify(o.config);if(Buffer.byteLength(s)>5120)return t.stderr(`hivefloor: ${r} is too large for a Worker variable (5120 bytes). Shorten names or remove projects.\n`),1;let c=T(t.cwd,n[`wrangler-config`]),l=await De(t.cwd);if(!m(c)||l===void 0)return t.stderr(`hivefloor: run deploy from your Hivefloor checkout after pnpm install (looked for ${c} and Wrangler).\n`),1;L(t,`✓ ${r} is valid (${String(o.config.publicProjects.length)} public projects).`);let u=t.script!==void 0&&/\.(c|m)?js$/.test(t.script)?t.execPath:`node`,d=await t.runProcess(u,[l,`deploy`,`--config`,c,`--var`,`OFFICE_CONFIG:${s}`,...n[`dry-run`]===!0?[`--dry-run`]:[]]);if(d!==0)return d;if(n[`dry-run`]===!0)return L(t,``,`Dry run: nothing was deployed and no secret was set.`),0;let f=await Ae(t,n[`push-secret`]===!0);if(f===void 0)return L(t,``,await z(P(t.env,t.home,t.windows))===void 0?`This machine has no secret, so the relay was left as it is. To create one and set it: hivefloor deploy --push-secret`:`Deployed. Next: hivefloor init --url <your office URL>`),0;let p=await t.runProcess(u,[l,`secret`,`put`,`HIVEFLOOR_SECRET`,`--config`,c],f);return p===0?(L(t,``,`✓ Secret set on the relay.`,`Next: hivefloor init --url <your office URL>`),0):(t.stderr(`hivefloor: deployed, but setting the secret failed. Run: hivefloor deploy --push-secret
|
|
5
|
+
`),p)}const B=`office.config.json`,Me={path:{type:`string`},"office-config":{type:`string`},color:{type:`string`},deploy:{type:`boolean`}};function Ne(e,t){return{kind:`failed`,message:`${e} is invalid:\n ${t.join(`
|
|
6
|
+
`)}`}}async function Pe(e,t,n){let r=T(n.cwd,e??B),i;try{i=await y(r,`utf8`)}catch{return e===void 0?{kind:`absent`}:{kind:`failed`,message:`no ${r}. Check the path given to --office-config.`}}let{checkOfficeConfig:a}=await import(`./validate-config-WKKxO7uI.mjs`),o=a(i);if(!o.ok)return Ne(r,o.problems);let s=JSON.parse(i),c=s.publicProjects,l=Ce(Array.isArray(c)?c:[],t);if(l.kind===`conflict`)return{kind:`failed`,message:`${r} already lists "${l.existing}", and names can't differ only by case. Use that exact name, or rename it there first.`};if(l.change===`unchanged`)return{kind:`ready`,path:r,change:`unchanged`,text:i};let u=`${JSON.stringify({...s,publicProjects:l.projects},null,2)}\n`,d=a(u);return d.ok?Buffer.byteLength(JSON.stringify(d.config))>5120?{kind:`failed`,message:`adding "${t.name}" makes ${r} too large for a Worker variable (5120 bytes). Shorten names or remove projects.`}:{kind:`ready`,path:r,change:l.change,text:u}:Ne(r,d.problems)}async function Fe(e,t){if(e===void 0)return t.cwd;try{let n=await te(T(t.cwd,e));return(await x(n)).isDirectory()?n:void 0}catch{return}}async function Ie(e,t){let n=await te(e),{mode:r}=await x(n);await N(n,t,r&511)}function Le(e,t){let n=S(e),r=n===B?`hivefloor deploy`:`hivefloor deploy --config ${fe(n,t.windows)}`;return C(e)===t.cwd?r:`${r} (from ${C(e)})`}function Re(e,t,n){if(e.kind!==`ready`)return[`No ${B} in ${n.cwd}, so the relay rejects "${t.name}" until you add it there.`,`Add this to "publicProjects" in ${B}, in your Hivefloor checkout:`,` ${JSON.stringify(t)}`,`Then run hivefloor deploy from that checkout, or run this again with --office-config PATH.`];let r=Le(e.path,n);return e.change===`unchanged`?[`If the relay doesn't know "${t.name}" yet, run: ${r}`]:[`Next: ${r}. The relay rejects "${t.name}" until it is deployed.`]}async function ze(e,t){let{values:n,positionals:r}=E({args:[...e],options:Me,strict:!0,allowPositionals:!0}),[i,a]=r;if(i===void 0||a!==void 0)return t.stderr(`Usage: hivefloor add-project NAME [--path DIR] [--office-config FILE] [--color #RRGGBB] [--deploy]
|
|
7
7
|
`),2;let o=e=>(t.stderr(`hivefloor: ${e}\n`),1),s=i.trim(),c=n.color===void 0?{name:s}:{name:s,color:n.color},{publicProjectProblems:l}=await import(`./validate-config-WKKxO7uI.mjs`),u=l(c);if(u.length>0)return o(`"${s}" can't be a public project:\n ${u.join(`
|
|
8
|
-
`)}`);let d=
|
|
9
|
-
`)}`)}let _=m.kind===`ready`&&m.change!==`unchanged`;_&&await Ie(m.path,m.text);let v=[...g.change===`unchanged`?[]:[`✓ ${p} is public as "${s}" in ${d.config}`],..._?[`✓ ${m.change===`added`?`Added`:`Recoloured`} "${s}" (${m.path})`]:[]];return I(t,...v.length>0?v:[`Nothing to change: ${p} is already public as "${s}".`]),g.previousName!==void 0&&I(t,`! "${g.previousName}" stays in ${z}. Remove it there if nothing else uses it.`),I(t,`! Anyone viewing the office can see this project's name and its task titles.`),m.kind===`ready`&&n.deploy===!0?je([`--config`,m.path],{...t,cwd:S(m.path)}):(I(t,``,...Re(m,c,t)),0)}const Be=/* @__PURE__ */ new Map([[`Read`,`reading`],[`Glob`,`reading`],[`Grep`,`reading`],[`LSP`,`reading`],[`ListMcpResourcesTool`,`reading`],[`ReadMcpResourceTool`,`reading`],[`Edit`,`coding`],[`MultiEdit`,`coding`],[`Write`,`coding`],[`NotebookEdit`,`coding`],[`WebFetch`,`research`],[`WebSearch`,`research`],[`Agent`,`delegating`],[`Task`,`delegating`],[`SendMessage`,`delegating`],[`ListAgents`,`delegating`],[`SubagentHandback`,`delegating`],[`Workflow`,`delegating`],[`TaskStop`,`delegating`],[`TaskCreate`,`planning`],[`TaskUpdate`,`planning`],[`TaskGet`,`planning`],[`TaskList`,`planning`],[`TodoWrite`,`planning`],[`EnterPlanMode`,`planning`],[`ExitPlanMode`,`planning`],[`AskUserQuestion`,`planning`],[`Monitor`,`monitoring`],[`CronCreate`,`monitoring`],[`CronDelete`,`monitoring`],[`CronList`,`monitoring`],[`ScheduleWakeup`,`monitoring`],[`EnterWorktree`,`vcs`],[`ExitWorktree`,`vcs`],[`RemoteTrigger`,`integration`]]),Ve=/* @__PURE__ */ new Set([`Bash`,`PowerShell`]),He=/* @__PURE__ */ new Set([`vitest`,`jest`,`pytest`,`mocha`,`playwright`,`cypress`,`rspec`,`phpunit`,`ava`,`karma`,`jasmine`,`nextest`]),Ue=/* @__PURE__ */ new Set([`test`,`tests`,`e2e`,`test-ci`]),We=/* @__PURE__ */ new Set([`git`,`gh`,`glab`,`hg`,`svn`,`jj`]);function Ge(e){let t=e.slice(Math.max(e.lastIndexOf(`/`),e.lastIndexOf(`\\`))+1);return t.endsWith(`.exe`)?t.slice(0,-4):t}function Ke(e){return He.has(Ge(e))||Ue.has(e)||e.startsWith(`test:`)}function qe(e){let t=!1;for(let n of e.toLowerCase().split(/&&|\|\||[;|\n]/)){let e=n.split(/\s+/).filter(e=>e.length>0&&!e.includes(`=`)),[r]=e;if(r!==void 0){if(We.has(Ge(r)))t=!0;else if(e.some(Ke))return`testing`}}return t?`vcs`:`terminal`}function Je(e){if(!e.startsWith(`mcp__`))return;let t=e.slice(5),n=t.indexOf(`__`),r=n===-1?t:t.slice(0,n);return r.length>0?r:void 0}function Ye(e,t,n){if(Ve.has(e))return qe(D(t,`command`)??``);let r=Je(e);return r===void 0?Be.get(e)??`working`:(E(n)&&Object.hasOwn(n,r)?n[r]:void 0)??`integration`}const Xe=/* @__PURE__ */ new Set([`start`,`end`,`spawn`,`done`,`idle`]);function Ze(e,t,n){return e===void 0||Xe.has(t.kind)||e.kind!==t.kind||e.cat!==t.cat||e.goal!==t.goal?!0:n-e.at>=10}function Qe(e){let t={v:1,t:e.t,seq:e.seq,sid:e.sid,role:e.role,kind:e.kind};return e.aid!==void 0&&(t.aid=e.aid),e.kind===`tool`&&e.cat!==void 0&&(t.cat=e.cat),e.project!==void 0&&(t.project=e.project,e.goal!==void 0&&(t.goal=e.goal)),t}function $e(e,t){return Math.floor(e/t)*t}const et=/[\u0000-\u001f\u007f-\u009f]+/g;function tt(e,t){if(e.length<=t)return e;let n=``;for(let r of e){if(n.length+r.length>t-1)break;n+=r}return`${n.trimEnd()}…`}function nt(e,t){let n=e.trim().toLowerCase();if(n.startsWith(t.privatePrefix.toLowerCase())||t.blockWords.some(e=>n.includes(e.toLowerCase())))return;let i=tt(e.replace(et,` `).split(/\s+/).filter(e=>e.length>0&&!r(e)).join(` `),t.maxLength);return i.length>0&&!r(i)?i:void 0}function rt(e,t){return e.tasks.find(e=>e.id===t)?.subject}function it(e,t){if(t.fromTaskList){let n=(e.activeTask===void 0?void 0:rt(e,e.activeTask))??e.todo;if(n!==void 0)return nt(n,t)}if(t.fromSessionTitle&&e.title!==void 0)return nt(e.title,t)}function B(e,t){let n=e.tasks.filter(e=>e.id!==t.id);return{...e,tasks:[...n,t].slice(-50)}}function at(e,t){if(t===void 0||e.activeTask!==t)return e;let n={...e};return delete n.activeTask,n}function ot(e,t){let n=D(t,`taskId`)??D(t,`task_id`)??D(t,`id`);if(n===void 0)return e;let r=D(t,`subject`),i=r===void 0?e:B(e,{id:n,subject:r}),a=D(t,`status`);return a===`in_progress`?{...i,activeTask:n}:a===`completed`||a===`deleted`?at(i,n):i}function st(e,t){let n=O(t,`todos`).find(e=>E(e)&&e.status===`in_progress`),r=E(n)?D(n,`activeForm`)??D(n,`content`):void 0;if(r!==void 0)return{...e,todo:r};let i={...e};return delete i.todo,i}function ct(e,t){let n=D(t,`session_title`),r=n===void 0?e:{...e,title:n};switch(D(t,`hook_event_name`)??``){case`TaskCreated`:{let e=D(t,`task_id`),n=D(t,`task_subject`);return e===void 0||n===void 0?r:B(r,{id:e,subject:n})}case`TaskCompleted`:return at(r,D(t,`task_id`));case`PreToolUse`:{let e=D(t,`tool_name`),n=ve(t,`tool_input`);return e===`TaskUpdate`?ot(r,n):e===`TodoWrite`?st(r,n):r}default:return r}}function lt(e){return(/* @__PURE__ */ new Date(e*1e3)).toISOString().slice(0,10)}function ut(e,t){return l(`sha256`,e).update(`hivefloor:salt:${t}`).digest(`hex`)}function dt(e,t){return l(`sha256`,e).update(t).digest(`hex`).slice(0,6)}function ft(e){return c(`sha256`).update(e).digest(`hex`).slice(0,16)}function pt(e,t){return e!==void 0&&e!==`claude`&&t.includes(e)?e:i}function mt(e,t){let{payload:n,config:r}=e,i=t===void 0?`main`:`agent`;switch(D(n,`hook_event_name`)??``){case`SessionStart`:return{kind:`start`,target:`main`};case`UserPromptSubmit`:return{kind:`thinking`,target:`main`};case`Stop`:return t===void 0?{kind:`idle`,target:`main`}:void 0;case`SessionEnd`:return{kind:`end`,target:`main`};case`SubagentStart`:return t===void 0?void 0:{kind:`spawn`,target:i};case`SubagentStop`:return t===void 0||e.agent===void 0?void 0:{kind:`done`,target:i};case`PreToolUse`:{let e=D(n,`tool_name`);return e===void 0?void 0:{kind:`tool`,cat:Ye(e,ve(n,`tool_input`),r.mcpCategories),target:i}}default:return}}function ht(e,t,n){return{kind:e.kind,at:n,...e.cat===void 0?{}:{cat:e.cat},...t===void 0?{}:{goal:t}}}function V(e){let{payload:n,config:r,now:i}=e,a=D(n,`session_id`);if(a===void 0)return{};let o=D(n,`agent_id`),s=e.session??{v:1,seq:0,saltDay:lt(i),goal:{tasks:[]}},c={...s,goal:ct(s.goal,n)},l=JSON.stringify(c)===JSON.stringify(e.session)?{}:{session:c},u=mt(e,o);if(u===void 0)return l;let d=be(D(n,`cwd`)??``,r.projects,e.paths),f=u.target===`main`,p=f?c:e.agent??{seq:0},m=f&&d.isPublic?it(c.goal,r.goals):void 0;if(!Ze(p.last,{kind:u.kind,...u.cat?{cat:u.cat}:{},...m?{goal:m}:{}},i))return l;let h=ut(e.secret,c.saltDay),g=Qe({t:$e(i,r.timestampRoundingSec),seq:p.seq,sid:dt(h,a),...f||o===void 0?{}:{aid:dt(h,o)},role:f?t:pt(D(n,`agent_type`),r.publicAgentTypes),kind:u.kind,...u.cat===void 0?{}:{cat:u.cat},...d.name===void 0?{}:{project:d.name},...m===void 0?{}:{goal:m}}),_={seq:p.seq+1,last:ht(u,m,i)};return f?{event:g,session:{...c,..._},...u.kind===`end`?{remove:`session`}:{}}:{event:g,...l,agent:{v:1,..._},...u.kind===`done`?{remove:`agent`}:{}}}const H=[`SessionStart`,`UserPromptSubmit`,`PreToolUse`,`Stop`,`SubagentStart`,`SubagentStop`,`TaskCreated`,`TaskCompleted`,`SessionEnd`];function gt(e){return de(e,`"'`)}function _t(e){let t=e.trim().split(/\s+/).map(gt);return t.some((e,n)=>e.toLowerCase().includes(`hivefloor`)&&t[n+1]===`hook`)}function U(e){return E(e)&&e.type===`command`&&typeof e.command==`string`&&_t(e.command)}function W(e,t){let n=e[t];return Array.isArray(n)?n:[]}function G(e){return E(e)&&Array.isArray(e.hooks)?e.hooks:[]}function vt(e){return{type:`command`,command:e,async:!0}}function yt(e,t){let n=E(e.hooks)?{...e.hooks}:{},r=[],i=vt(t);for(let e of H){let t=W(n,e),a=t.flatMap(G).filter(U);(a.length!==1||JSON.stringify(a[0])!==JSON.stringify(i))&&(n[e]=[...bt(t),{hooks:[i]}],r.push(e))}return{settings:r.length===0?e:{...e,hooks:n},events:r}}function bt(e){return e.flatMap(e=>{let t=G(e);if(!E(e)||!t.some(U))return[e];let n=t.filter(e=>!U(e));return n.length===0?[]:[{...e,hooks:n}]})}function xt(e){let t=e.hooks;if(!E(t))return{settings:e,events:[]};let n={},r=[];for(let[e,i]of Object.entries(t)){let a=W(t,e);if(!a.flatMap(G).some(U)){n[e]=i;continue}let o=bt(a);o.length>0&&(n[e]=o),r.push(e)}if(r.length===0)return{settings:e,events:r};let i=Object.keys(n).length>0;return{settings:Object.fromEntries(Object.entries(e).flatMap(([e,t])=>e===`hooks`?i?[[e,n]]:[]:[[e,t]])),events:r}}function St(e){if(!E(e.hooks))return[];let t=e.hooks;return Object.keys(t).flatMap(e=>W(t,e).flatMap(G).filter(U).map(t=>{let n=t;return{event:e,command:String(n.command),async:n.async===!0}}))}const K=(e,t,n)=>n===void 0?{status:e,title:t}:{status:e,title:t,detail:n};function Ct(e,t){let n=t===null?NaN:Date.parse(t);if(Number.isNaN(n))return K(`warn`,`Clock`,`The relay sent no usable Date header.`);let r=Math.round((e-n)/1e3);return Math.abs(r)>30?K(`warn`,`Clock`,`Your clock is ${String(Math.abs(r))} s ${r>0?`ahead of`:`behind`} the relay. Beyond 60 s every event is rejected; sync your clock.`):K(`ok`,`Clock`,`Within ${String(Math.abs(r))} s of the relay.`)}function wt(e,t,n){return(E(e)?O(e,t):[]).flatMap(e=>{if(n===void 0)return typeof e==`string`?[e]:[];let t=E(e)?D(e,n):void 0;return t===void 0?[]:[t]})}function Tt(e,t){let n=new Set(wt(t,`publicProjects`,`name`)),r=new Set(wt(t,`agentTypes`)),i=e.projects.flatMap(e=>e.public&&e.name!==void 0&&!n.has(e.name)?[e.name]:[]),a=e.publicAgentTypes.filter(e=>!r.has(e));return[i.length===0?K(`ok`,`Public projects`,`Every public project is known to the relay.`):K(`fail`,`Public projects`,`Not in the relay's office.config.json: ${i.join(`, `)}. Their events are rejected; add them there and redeploy, or fix the names here.`),a.length===0?K(`ok`,`Agent types`,`Every public agent type is known to the relay.`):K(`warn`,`Agent types`,`Not in the relay's agentTypes: ${a.join(`, `)}. Those subagents are rejected; add them there or remove them from publicAgentTypes.`)]}function Et(e){switch(e){case 204:case 200:return K(`ok`,`Signed test event`,`The relay accepted it (dry run: the office did not change).`);case 401:case 403:return K(`fail`,`Signed test event`,`The relay rejected the signature. The secret here and the relay secret differ: run init --rotate and update the relay secret.`);case 400:case 422:return K(`fail`,`Signed test event`,`The relay rejected the event. A project or agent name is probably missing from the relay config.`);case 404:return K(`fail`,`Signed test event`,`No relay at this address. Check the office URL, or deploy the relay.`);case 413:return K(`fail`,`Signed test event`,`The relay said the event is too large; this is a bug, please report it.`);case 429:return K(`warn`,`Signed test event`,`The relay is over Cloudflare's daily limit and pauses until the reset.`);case void 0:return K(`fail`,`Signed test event`,`Could not reach the relay (network error or 1.5 s timeout).`);default:return K(`fail`,`Signed test event`,`The relay answered ${String(e)}.`)}}function Dt(e){let t=new Set(e.map(e=>e.event)),n=H.filter(e=>!t.has(e));return e.length===0?K(`fail`,`Claude Code hooks`,`Not registered. Run hivefloor init.`):n.length>0?K(`fail`,`Claude Code hooks`,`Missing for ${n.join(`, `)}. Run hivefloor init.`):e.some(e=>!e.async)?K(`warn`,`Claude Code hooks`,`Some hooks are not async, so Claude Code waits for them. Run hivefloor init.`):new Set(e.map(e=>e.command)).size>1?K(`warn`,`Claude Code hooks`,`Hooks run different commands. Run hivefloor init.`):K(`ok`,`Claude Code hooks`,`Registered for ${String(H.length)} events: ${e[0]?.command??``}`)}function Ot(e){let t={ok:`✓`,warn:`!`,fail:`✗`};return e.map(e=>`${t[e.status]} ${e.title}${e.detail===void 0?``:`: ${e.detail}`}`).join(`
|
|
10
|
-
`)}function q(e,t){return
|
|
11
|
-
`),1;let s=await
|
|
12
|
-
`),1;let c=a.projects,l=Array.isArray(c)?c:[],u=await
|
|
13
|
-
`)}\n`),1;f.push(`Wrote ${r.config}`)}(s.created||await
|
|
14
|
-
`)}\n`),1}return
|
|
15
|
-
`),1;let{event:a}=V({payload:i,config:r,secret:await
|
|
8
|
+
`)}`);let d=P(t.env,t.home,t.windows),f=await F(d);if(f===void 0)return o(`no ${d.config}. Run hivefloor init first.`);if(f===null)return o(`${d.config} is not a JSON object. Fix or delete it first.`);let p=await Fe(n.path,t);if(p===void 0)return o(`${String(n.path)} is not a folder.`);let m=await Pe(n[`office-config`],c,t);if(m.kind===`failed`)return o(m.message);if(m.kind===`absent`&&n.deploy===!0)return o(`--deploy needs ${B}, and there is none in ${t.cwd}. Run from your Hivefloor checkout or pass --office-config PATH. Nothing was changed.`);let h=f.projects,g=Se(Array.isArray(h)?h:[],p,s,{home:t.home,windows:t.windows});if(g.change!==`unchanged`){let e=await I(d,{...f,projects:g.projects});if(!e.ok)return o(`the config would be invalid:\n ${e.problems.join(`
|
|
9
|
+
`)}`)}let _=m.kind===`ready`&&m.change!==`unchanged`;_&&await Ie(m.path,m.text);let v=[...g.change===`unchanged`?[]:[`✓ ${p} is public as "${s}" in ${d.config}`],..._?[`✓ ${m.change===`added`?`Added`:`Recoloured`} "${s}" (${m.path})`]:[]];return L(t,...v.length>0?v:[`Nothing to change: ${p} is already public as "${s}".`]),g.previousName!==void 0&&L(t,`! "${g.previousName}" stays in ${B}. Remove it there if nothing else uses it.`),L(t,`! Anyone viewing the office can see this project's name and its task titles.`),m.kind===`ready`&&n.deploy===!0?je([`--config`,m.path],{...t,cwd:C(m.path)}):(L(t,``,...Re(m,c,t)),0)}const Be=/* @__PURE__ */ new Map([[`Read`,`reading`],[`Glob`,`reading`],[`Grep`,`reading`],[`LSP`,`reading`],[`ListMcpResourcesTool`,`reading`],[`ReadMcpResourceTool`,`reading`],[`Edit`,`coding`],[`MultiEdit`,`coding`],[`Write`,`coding`],[`NotebookEdit`,`coding`],[`WebFetch`,`research`],[`WebSearch`,`research`],[`Agent`,`delegating`],[`Task`,`delegating`],[`SendMessage`,`delegating`],[`ListAgents`,`delegating`],[`SubagentHandback`,`delegating`],[`Workflow`,`delegating`],[`TaskStop`,`delegating`],[`TaskCreate`,`planning`],[`TaskUpdate`,`planning`],[`TaskGet`,`planning`],[`TaskList`,`planning`],[`TodoWrite`,`planning`],[`EnterPlanMode`,`planning`],[`ExitPlanMode`,`planning`],[`AskUserQuestion`,`planning`],[`Monitor`,`monitoring`],[`CronCreate`,`monitoring`],[`CronDelete`,`monitoring`],[`CronList`,`monitoring`],[`ScheduleWakeup`,`monitoring`],[`EnterWorktree`,`vcs`],[`ExitWorktree`,`vcs`],[`RemoteTrigger`,`integration`]]),Ve=/* @__PURE__ */ new Set([`Bash`,`PowerShell`]),He=/* @__PURE__ */ new Set([`vitest`,`jest`,`pytest`,`mocha`,`playwright`,`cypress`,`rspec`,`phpunit`,`ava`,`karma`,`jasmine`,`nextest`]),Ue=/* @__PURE__ */ new Set([`test`,`tests`,`e2e`,`test-ci`]),We=/* @__PURE__ */ new Set([`git`,`gh`,`glab`,`hg`,`svn`,`jj`]);function Ge(e){let t=e.slice(Math.max(e.lastIndexOf(`/`),e.lastIndexOf(`\\`))+1);return t.endsWith(`.exe`)?t.slice(0,-4):t}function Ke(e){return He.has(Ge(e))||Ue.has(e)||e.startsWith(`test:`)}function qe(e){let t=!1;for(let n of e.toLowerCase().split(/&&|\|\||[;|\n]/)){let e=n.split(/\s+/).filter(e=>e.length>0&&!e.includes(`=`)),[r]=e;if(r!==void 0){if(We.has(Ge(r)))t=!0;else if(e.some(Ke))return`testing`}}return t?`vcs`:`terminal`}function Je(e){if(!e.startsWith(`mcp__`))return;let t=e.slice(5),n=t.indexOf(`__`),r=n===-1?t:t.slice(0,n);return r.length>0?r:void 0}function Ye(e,t,n){if(Ve.has(e))return qe(O(t,`command`)??``);let r=Je(e);return r===void 0?Be.get(e)??`working`:(D(n)&&Object.hasOwn(n,r)?n[r]:void 0)??`integration`}const Xe=/* @__PURE__ */ new Set([`start`,`end`,`spawn`,`done`,`idle`]);function Ze(e,t,n){return e===void 0||Xe.has(t.kind)||e.kind!==t.kind||e.cat!==t.cat||e.goal!==t.goal?!0:n-e.at>=10}function Qe(e){let t={v:1,t:e.t,seq:e.seq,sid:e.sid,role:e.role,kind:e.kind};return e.aid!==void 0&&(t.aid=e.aid),e.kind===`tool`&&e.cat!==void 0&&(t.cat=e.cat),e.project!==void 0&&(t.project=e.project,e.goal!==void 0&&(t.goal=e.goal)),t}function $e(e,t){return Math.floor(e/t)*t}const et=/[\u0000-\u001f\u007f-\u009f]+/g;function tt(e,t){if(e.length<=t)return e;let n=``;for(let r of e){if(n.length+r.length>t-1)break;n+=r}return`${n.trimEnd()}…`}function nt(e,t){let n=e.trim().toLowerCase();if(n.startsWith(t.privatePrefix.toLowerCase())||t.blockWords.some(e=>n.includes(e.toLowerCase())))return;let i=tt(e.replace(et,` `).split(/\s+/).filter(e=>e.length>0&&!r(e)).join(` `),t.maxLength);return i.length>0&&!r(i)?i:void 0}function rt(e,t){return e.tasks.find(e=>e.id===t)?.subject}function it(e,t){if(t.fromTaskList){let n=(e.activeTask===void 0?void 0:rt(e,e.activeTask))??e.todo;if(n!==void 0)return nt(n,t)}if(t.fromSessionTitle&&e.title!==void 0)return nt(e.title,t)}function at(e,t){let n=e.tasks.filter(e=>e.id!==t.id);return{...e,tasks:[...n,t].slice(-50)}}function ot(e,t){if(t===void 0||e.activeTask!==t)return e;let n={...e};return delete n.activeTask,n}function st(e,t){let n=O(t,`taskId`)??O(t,`task_id`)??O(t,`id`);if(n===void 0)return e;let r=O(t,`subject`),i=r===void 0?e:at(e,{id:n,subject:r}),a=O(t,`status`);return a===`in_progress`?{...i,activeTask:n}:a===`completed`||a===`deleted`?ot(i,n):i}function ct(e,t){let n=k(t,`todos`).find(e=>D(e)&&e.status===`in_progress`),r=D(n)?O(n,`activeForm`)??O(n,`content`):void 0;if(r!==void 0)return{...e,todo:r};let i={...e};return delete i.todo,i}function lt(e,t){let n=O(t,`session_title`),r=n===void 0?e:{...e,title:n};switch(O(t,`hook_event_name`)??``){case`TaskCreated`:{let e=O(t,`task_id`),n=O(t,`task_subject`);return e===void 0||n===void 0?r:at(r,{id:e,subject:n})}case`TaskCompleted`:return ot(r,O(t,`task_id`));case`PreToolUse`:{let e=O(t,`tool_name`),n=ve(t,`tool_input`);return e===`TaskUpdate`?st(r,n):e===`TodoWrite`?ct(r,n):r}default:return r}}function ut(e){return(/* @__PURE__ */ new Date(e*1e3)).toISOString().slice(0,10)}function dt(e,t){return l(`sha256`,e).update(`hivefloor:salt:${t}`).digest(`hex`)}function ft(e,t){return l(`sha256`,e).update(t).digest(`hex`).slice(0,6)}function pt(e){return c(`sha256`).update(e).digest(`hex`).slice(0,16)}function mt(e,t){return e!==void 0&&e!==`claude`&&t.includes(e)?e:i}function ht(e,t){let{payload:n,config:r}=e,i=t===void 0?`main`:`agent`;switch(O(n,`hook_event_name`)??``){case`SessionStart`:return{kind:`start`,target:`main`};case`UserPromptSubmit`:return{kind:`thinking`,target:`main`};case`Stop`:return t===void 0?{kind:`idle`,target:`main`}:void 0;case`SessionEnd`:return{kind:`end`,target:`main`};case`SubagentStart`:return t===void 0?void 0:{kind:`spawn`,target:i};case`SubagentStop`:return t===void 0||e.agent===void 0?void 0:{kind:`done`,target:i};case`PreToolUse`:{let e=O(n,`tool_name`);return e===void 0?void 0:{kind:`tool`,cat:Ye(e,ve(n,`tool_input`),r.mcpCategories),target:i}}default:return}}function gt(e,t,n){return{kind:e.kind,at:n,...e.cat===void 0?{}:{cat:e.cat},...t===void 0?{}:{goal:t}}}function V(e){let{payload:n,config:r,now:i}=e,a=O(n,`session_id`);if(a===void 0)return{};let o=O(n,`agent_id`),s=e.session??{v:1,seq:0,saltDay:ut(i),goal:{tasks:[]}},c={...s,goal:lt(s.goal,n)},l=JSON.stringify(c)===JSON.stringify(e.session)?{}:{session:c},u=ht(e,o);if(u===void 0)return l;let d=be(O(n,`cwd`)??``,r.projects,e.paths),f=u.target===`main`,p=f?c:e.agent??{seq:0},m=f&&d.isPublic?it(c.goal,r.goals):void 0;if(!Ze(p.last,{kind:u.kind,...u.cat?{cat:u.cat}:{},...m?{goal:m}:{}},i))return l;let h=dt(e.secret,c.saltDay),g=Qe({t:$e(i,r.timestampRoundingSec),seq:p.seq,sid:ft(h,a),...f||o===void 0?{}:{aid:ft(h,o)},role:f?t:mt(O(n,`agent_type`),r.publicAgentTypes),kind:u.kind,...u.cat===void 0?{}:{cat:u.cat},...d.name===void 0?{}:{project:d.name},...m===void 0?{}:{goal:m}}),_={seq:p.seq+1,last:gt(u,m,i)};return f?{event:g,session:{...c,..._},...u.kind===`end`?{remove:`session`}:{}}:{event:g,...l,agent:{v:1,..._},...u.kind===`done`?{remove:`agent`}:{}}}const H=[`SessionStart`,`UserPromptSubmit`,`PreToolUse`,`Stop`,`SubagentStart`,`SubagentStop`,`TaskCreated`,`TaskCompleted`,`SessionEnd`];function _t(e){return de(e,`"'`)}function vt(e){let t=e.trim();if(!t.endsWith(` hook`))return!1;let n=_t(t.slice(0,-5)).split(/[\\/]/),r=n.at(-1)?.toLowerCase();return n.length>1&&(r===`node`||r===`node.exe`)}function yt(e){let t=e.trim().split(/\s+/).map(_t);return vt(e)||t.some((e,n)=>e.toLowerCase().includes(`hivefloor`)&&t[n+1]===`hook`)}function U(e){return D(e)&&e.type===`command`&&typeof e.command==`string`&&yt(e.command)}function W(e,t){let n=e[t];return Array.isArray(n)?n:[]}function G(e){return D(e)&&Array.isArray(e.hooks)?e.hooks:[]}function bt(e){return{type:`command`,command:e,async:!0}}function xt(e,t){let n=D(e.hooks)?{...e.hooks}:{},r=[],i=bt(t);for(let e of H){let t=W(n,e),a=t.flatMap(G).filter(U);(a.length!==1||JSON.stringify(a[0])!==JSON.stringify(i))&&(n[e]=[...St(t),{hooks:[i]}],r.push(e))}return{settings:r.length===0?e:{...e,hooks:n},events:r}}function St(e){return e.flatMap(e=>{let t=G(e);if(!D(e)||!t.some(U))return[e];let n=t.filter(e=>!U(e));return n.length===0?[]:[{...e,hooks:n}]})}function Ct(e){let t=e.hooks;if(!D(t))return{settings:e,events:[]};let n={},r=[];for(let[e,i]of Object.entries(t)){let a=W(t,e);if(!a.flatMap(G).some(U)){n[e]=i;continue}let o=St(a);o.length>0&&(n[e]=o),r.push(e)}if(r.length===0)return{settings:e,events:r};let i=Object.keys(n).length>0;return{settings:Object.fromEntries(Object.entries(e).flatMap(([e,t])=>e===`hooks`?i?[[e,n]]:[]:[[e,t]])),events:r}}function wt(e){if(!D(e.hooks))return[];let t=e.hooks;return Object.keys(t).flatMap(e=>W(t,e).flatMap(G).filter(U).map(t=>{let n=t;return{event:e,command:String(n.command),async:n.async===!0}}))}const K=(e,t,n)=>n===void 0?{status:e,title:t}:{status:e,title:t,detail:n};function Tt(e,t){let n=t===null?NaN:Date.parse(t);if(Number.isNaN(n))return K(`warn`,`Clock`,`The relay sent no usable Date header.`);let r=Math.round((e-n)/1e3);return Math.abs(r)>30?K(`warn`,`Clock`,`Your clock is ${String(Math.abs(r))} s ${r>0?`ahead of`:`behind`} the relay. Beyond 60 s every event is rejected; sync your clock.`):K(`ok`,`Clock`,`Within ${String(Math.abs(r))} s of the relay.`)}function Et(e,t,n){return(D(e)?k(e,t):[]).flatMap(e=>{if(n===void 0)return typeof e==`string`?[e]:[];let t=D(e)?O(e,n):void 0;return t===void 0?[]:[t]})}function Dt(e,t){let n=new Set(Et(t,`publicProjects`,`name`)),r=new Set(Et(t,`agentTypes`)),i=e.projects.flatMap(e=>e.public&&e.name!==void 0&&!n.has(e.name)?[e.name]:[]),a=e.publicAgentTypes.filter(e=>!r.has(e));return[i.length===0?K(`ok`,`Public projects`,`Every public project is known to the relay.`):K(`fail`,`Public projects`,`Not in the relay's office.config.json: ${i.join(`, `)}. Their events are rejected; add them there and redeploy, or fix the names here.`),a.length===0?K(`ok`,`Agent types`,`Every public agent type is known to the relay.`):K(`warn`,`Agent types`,`Not in the relay's agentTypes: ${a.join(`, `)}. Those subagents are rejected; add them there or remove them from publicAgentTypes.`)]}function Ot(e){switch(e){case 204:case 200:return K(`ok`,`Signed test event`,`The relay accepted it (dry run: the office did not change).`);case 401:case 403:return K(`fail`,`Signed test event`,`The relay rejected the signature. The secret here and the relay secret differ: run init --rotate and update the relay secret.`);case 400:case 422:return K(`fail`,`Signed test event`,`The relay rejected the event. A project or agent name is probably missing from the relay config.`);case 404:return K(`fail`,`Signed test event`,`No relay at this address. Check the office URL, or deploy the relay.`);case 413:return K(`fail`,`Signed test event`,`The relay said the event is too large; this is a bug, please report it.`);case 429:return K(`warn`,`Signed test event`,`The relay is over Cloudflare's daily limit and pauses until the reset.`);case void 0:return K(`fail`,`Signed test event`,`Could not reach the relay (network error or 1.5 s timeout).`);default:return K(`fail`,`Signed test event`,`The relay answered ${String(e)}.`)}}function kt(e){let t=new Set(e.map(e=>e.event)),n=H.filter(e=>!t.has(e));return e.length===0?K(`fail`,`Claude Code hooks`,`Not registered. Run hivefloor init.`):n.length>0?K(`fail`,`Claude Code hooks`,`Missing for ${n.join(`, `)}. Run hivefloor init.`):e.some(e=>!e.async)?K(`warn`,`Claude Code hooks`,`Some hooks are not async, so Claude Code waits for them. Run hivefloor init.`):new Set(e.map(e=>e.command)).size>1?K(`warn`,`Claude Code hooks`,`Hooks run different commands. Run hivefloor init.`):K(`ok`,`Claude Code hooks`,`Registered for ${String(H.length)} events: ${e[0]?.command??``}`)}function At(e){let t={ok:`✓`,warn:`!`,fail:`✗`};return e.map(e=>`${t[e.status]} ${e.title}${e.detail===void 0?``:`: ${e.detail}`}`).join(`
|
|
10
|
+
`)}function q(e,t){return w(e.CLAUDE_CONFIG_DIR??w(t,`.claude`),`settings.json`)}async function J(e){let t;try{t=await y(e,`utf8`)}catch{return{kind:`missing`,settings:{}}}try{let e=JSON.parse(t);return D(e)?{kind:`ok`,settings:e}:{kind:`invalid`,reason:`it is not a JSON object`}}catch{return{kind:`invalid`,reason:`it is not valid JSON`}}}async function jt(e,t,n,r){let i;if(n){let t=`${e}.hivefloor-backup-${new Date(r).toISOString().replace(/[:.]/g,`-`)}`;for(let n=0;i===void 0;n++){let r=n===0?t:`${t}-${String(n)}`;try{await _(e,r,p.COPYFILE_EXCL),i=r}catch(e){if(e.code!==`EEXIST`||n>=99)throw e}}}return await N(e,`${JSON.stringify(t,null,2)}\n`,420),i}async function Mt(e){let t;try{t=await y(e.config,`utf8`)}catch{return{check:{status:`fail`,title:`Config`,detail:`No config at ${e.config}. Run hivefloor init.`}}}let{checkMachineConfig:n}=await import(`./validate-config-WKKxO7uI.mjs`),r=n(t);return r.ok?{check:{status:`ok`,title:`Config`,detail:e.config},config:r.config}:{check:{status:`fail`,title:`Config`,detail:`${e.config} is invalid: ${r.problems.join(`; `)}`}}}async function Nt(e,t){let n=await z(e);return n===void 0?{check:{status:`fail`,title:`Secret`,detail:`Missing ${e.secret}. Run hivefloor init.`}}:!t&&(await x(e.secret)).mode&63?{check:{status:`warn`,title:`Secret`,detail:`${e.secret} is readable by other users: chmod 600 it.`},secret:n}:{check:{status:`ok`,title:`Secret`,detail:`Present and private.`},secret:n}}async function Pt(e,t,n){let r=`${ge(e.endpoint)}/api/config`;try{let i=await n.fetch(r,{signal:AbortSignal.timeout(5e3),redirect:`error`});if(!i.ok)return[{status:`fail`,title:`Relay`,detail:`GET ${r} answered ${String(i.status)}.`}];let a=await i.json();return await N(Ee(t),JSON.stringify(a)),[{status:`ok`,title:`Relay`,detail:r},Tt(n.now(),i.headers.get(`date`)),...Dt(e,a)]}catch{return[{status:`fail`,title:`Relay`,detail:`Could not reach ${r}.`}]}}function Ft(e,t,n,r){let{event:i}=V({payload:{session_id:`hivefloor-doctor-${String(n.now())}`,cwd:n.cwd,...r},config:e,secret:t,now:Math.floor(n.now()/1e3),paths:{home:n.home,windows:n.windows}});return i===void 0?void 0:JSON.stringify(i)}async function It(e,t){let{values:n}=E({args:[...e],options:{settings:{type:`string`}},strict:!0}),r=P(t.env,t.home,t.windows),i=[],{check:a,config:o}=await Mt(r);i.push(a),o?.paused===!0&&i.push({status:`warn`,title:`Sending`,detail:`Paused. Run hivefloor resume.`});let{check:s,secret:c}=await Nt(r,t.windows);i.push(s);let l=n.settings??q(t.env,t.home),u=await J(l);if(i.push(u.kind===`invalid`?{status:`fail`,title:`Claude Code hooks`,detail:`${l} can't be read: ${u.reason}.`}:kt(wt(u.settings))),o!==void 0&&(i.push(...await Pt(o,r,t)),c!==void 0)){let e=Ft(o,c,t,{hook_event_name:`SessionStart`}),n=e===void 0?void 0:await ce(e,{endpoint:o.endpoint,secret:c,now:t.now,fetch:t.fetch,dryRun:!0});i.push(Ot(n))}if(L(t,At(i)),o!==void 0){let e=Ft(o,c??`example`,t,{hook_event_name:`PreToolUse`,tool_name:`Edit`});L(t,``,`When Claude edits a file in ${t.cwd}, exactly this leaves your machine:`,e??`(nothing)`)}return+!!i.some(e=>e.status===`fail`)}const Y=`0.1.1`,Lt={url:{type:`string`},"secret-stdin":{type:`boolean`},rotate:{type:`boolean`},public:{type:`string`},command:{type:`string`},settings:{type:`string`}};async function Rt(e,t,n){let r=typeof n==`string`?n:void 0,i=t;if(i===void 0&&e.interactive){let t=r===void 0?``:` [${r.replace(/\/ingest$/,``)}]`;i=(await e.ask(`Office URL${t}: `)).trim()||r}i??=r;let o=i===void 0?void 0:he(i);return o!==void 0&&a(o)?o:void 0}async function zt(e,t,n,r){if(n!==void 0&&!r)return{secret:n,created:!1};if(t){let t=(await e.readStdin()).trim();return t.length>=16?{secret:t,created:!1}:void 0}if(e.interactive&&!r){let t=(await e.ask(`Paste the office secret, or press Enter to create one: `)).trim();if(t.length>0)return t.length>=16?{secret:t,created:!1}:void 0}return{secret:e.randomSecret(),created:!0}}async function Bt(e,t,n){if(t!==void 0)return{path:e.cwd,public:!0,name:t};let r=n.some(t=>typeof t==`object`&&!!t&&t.path===e.cwd);if(!e.interactive||r)return;let i=(await e.ask(`Show ${e.cwd} in the office as a public project? [y/N] `)).trim().toLowerCase();if(i!==`y`&&i!==`yes`)return;let a=(await e.ask(`Its name in office.config.json [${S(e.cwd)}]: `)).trim()||S(e.cwd);return{path:e.cwd,public:!0,name:a}}async function Vt(e,t){let{values:n}=E({args:[...e],options:Lt,strict:!0}),r=P(t.env,t.home,t.windows),i=await F(r);if(i===null)return t.stderr(`hivefloor: ${r.config} is not a JSON object. Fix or delete it, then run init again.\n`),1;let a=i??{},o=await Rt(t,n.url,a.endpoint);if(o===void 0)return t.stderr(`hivefloor: give the office URL with --url, for example --url https://office.example.com (https, or http only for localhost).
|
|
11
|
+
`),1;let s=await zt(t,n[`secret-stdin`]===!0,await z(r),n.rotate===!0);if(s===void 0)return t.stderr(`hivefloor: the secret must be at least 16 characters.
|
|
12
|
+
`),1;let c=a.projects,l=Array.isArray(c)?c:[],u=await Bt(t,n.public,l),d={$schema:`https://unpkg.com/hivefloor/machine.schema.json`,v:1,...a,endpoint:o,...u===void 0?{}:{projects:[...l.filter(e=>e.path!==t.cwd),u]}},f=[];if(JSON.stringify(d)!==JSON.stringify(i)){let e=await I(r,d);if(!e.ok)return t.stderr(`hivefloor: the config would be invalid:\n ${e.problems.join(`
|
|
13
|
+
`)}\n`),1;f.push(`Wrote ${r.config}`)}(s.created||await z(r)!==s.secret)&&(await N(r.secret,`${s.secret}\n`,384),f.push(`Wrote ${r.secret} (mode 600)`));let p=n.settings??q(t.env,t.home),m=await J(p);if(m.kind===`invalid`)return t.stderr(`hivefloor: ${p} can't be updated because ${m.reason}. Fix it, then run init again.\n`),1;let h=n.command===void 0?me({execPath:t.execPath,script:t.script,version:Y,windows:t.windows}):{command:n.command},g=xt(m.settings,h.command);if(g.events.length>0){let e=await jt(p,g.settings,m.kind===`ok`,t.now());f.push(`Registered the hook for ${String(g.events.length)} events in ${p}${e===void 0?``:` (backup: ${e})`}`)}return f.length===0?L(t,`Nothing to change: Hivefloor is already set up.`):L(t,...f.map(e=>`✓ ${e}`)),h.warning!==void 0&&L(t,`! ${h.warning}`),s.created&&L(t,``,`New secret created. Set the same value on your relay (it is shown only now):`,` ${s.secret}`,` hivefloor deploy --push-secret (from your Hivefloor checkout)`),L(t,``,`Next: hivefloor doctor checks the connection and shows exactly what leaves this machine.`),0}async function Ht(e,t,n){E({args:[...t],options:{},strict:!0});let r=P(n.env,n.home,n.windows),i=await F(r);if(i==null)return n.stderr(`hivefloor: no valid config at ${r.config}. Run hivefloor init first.\n`),1;if(i.paused===!0!==e){let t=await I(r,{...i,paused:e});if(!t.ok)return n.stderr(`hivefloor: ${r.config} is invalid:\n ${t.problems.join(`
|
|
14
|
+
`)}\n`),1}return L(n,e?`Paused: nothing is sent until you run hivefloor resume.`:`Resumed: your office sees your sessions again.`),0}async function Ut(e,t){E({args:[...e],options:{},strict:!0});let n=P(t.env,t.home,t.windows),r=await R(n);if(r===void 0)return t.stderr(`hivefloor: no valid config at ${n.config}. Run hivefloor init first.\n`),1;let i=_e(await t.readStdin());if(i===void 0)return t.stderr(`hivefloor: pipe one hook payload (a JSON object) into hivefloor preview.
|
|
15
|
+
`),1;let{event:a}=V({payload:i,config:r,secret:await z(n)??`preview-without-a-secret`,now:Math.floor(t.now()/1e3),paths:{home:t.home,windows:t.windows}});if(a===void 0)return L(t,`Nothing would be sent for ${O(i,`hook_event_name`)??`this payload`}.`),0;L(t,`This would leave your machine:`,JSON.stringify(a,null,2)),r.paused&&L(t,`! Sending is paused (hivefloor resume).`);let o=await M(Ee(n));return a.project!==void 0&&D(o)&&(k(o,`publicProjects`).some(e=>D(e)&&e.name===a.project)||L(t,`! The relay did not know "${a.project}" at the last hivefloor doctor, so it would reject this event.`)),0}async function Wt(e,t){let{values:n}=E({args:[...e],options:{purge:{type:`boolean`},settings:{type:`string`}},strict:!0}),r=n.settings??q(t.env,t.home),i=await J(r);if(i.kind===`invalid`)return t.stderr(`hivefloor: ${r} can't be updated because ${i.reason}. Remove the hivefloor hooks by hand.\n`),1;let a=Ct(i.settings);if(a.events.length>0){let e=await jt(r,a.settings,i.kind===`ok`,t.now());L(t,`✓ Removed the Hivefloor hook from ${String(a.events.length)} events in ${r}${e===void 0?``:` (backup: ${e})`}`)}else L(t,`No Hivefloor hooks in ${r}.`);let o=P(t.env,t.home,t.windows);return n.purge===!0?(await b(o.dir,{recursive:!0,force:!0}),L(t,`✓ Deleted ${o.dir} (config, secret and state).`)):L(t,`Kept ${o.dir}. Run hivefloor uninstall --purge to delete it too.`),0}const Gt=/* @__PURE__ */ new Set([`hook_event_name`,`source`,`reason`,`permission_mode`,`status`,`level`]),Kt=/^[A-Za-z_][A-Za-z0-9_]{0,63}$/;function qt(e){return Je(e)===void 0?e:`mcp__<server>__<tool>`}function Jt(e,t){return t===`tool_name`?qt(e):t!==void 0&&Gt.has(t)&&Kt.test(e)?e:`<string:${String(e.length)}>`}function X(e,t,n=0){if(typeof e==`string`)return Jt(e,t);if(typeof e==`number`||typeof e==`boolean`||e===null)return e;if(n>=6)return`<nested>`;if(Array.isArray(e))return e.slice(0,20).map(e=>X(e,t,n+1));if(!D(e))return null;let r={},i=0;for(let[t,a]of Object.entries(e)){let e=Kt.test(t)?t:`<key:${String(i)}>`;r[e]=X(a,t,n+1),i++}return r}const Z=e=>Number.isInteger(e)&&e>=0,Q=e=>typeof e==`string`&&e.length>0,Yt=n,Xt=e;function Zt(e){if(!D(e)||!Z(e.at)||!Yt.includes(String(e.kind)))return;let t=e.cat,n=e.goal;return{kind:e.kind,at:e.at,...typeof t==`string`&&Xt.includes(t)?{cat:t}:{},...Q(n)?{goal:n}:{}}}function Qt(e){if(e.v!==1||!Z(e.seq))return;let t=Zt(e.last);return{seq:e.seq,...t===void 0?{}:{last:t}}}function $t(e){if(!D(e))return{tasks:[]};let t=Array.isArray(e.tasks)?e.tasks.flatMap(e=>D(e)&&Q(e.id)&&Q(e.subject)?[{id:e.id,subject:e.subject}]:[]):[],{title:n,activeTask:r,todo:i}=e;return{tasks:t,...Q(n)?{title:n}:{},...Q(r)?{activeTask:r}:{},...Q(i)?{todo:i}:{}}}function en(e){if(!D(e)||typeof e.saltDay!=`string`||!/^\d{4}-\d{2}-\d{2}$/.test(e.saltDay))return;let t=Qt(e);return t===void 0?void 0:{v:1,...t,saltDay:e.saltDay,goal:$t(e.goal)}}function tn(e){if(!D(e))return;let t=Qt(e);return t===void 0?void 0:{v:1,...t}}async function nn(e,t,n){if(!e.debug)return;let r=JSON.stringify({at:new Date(e.now()).toISOString(),hook:t,event:n.event??null});await g(e.files.debugLog,`${r}\n`,{mode:384})}async function rn(e,t){let n=`${(O(t,`hook_event_name`)??`unknown`).replace(/[^A-Za-z]/g,``)}-${String(e.now())}.json`;await N(w(e.files.recordings,n),`${JSON.stringify(X(t),null,2)}\n`)}async function an(e,t){let n=_e(e);if(n===void 0)return;t.record&&await rn(t,n);let r=await R(t.files);if(r===void 0||r.paused)return;let i=await z(t.files),a=O(n,`session_id`);if(i===void 0||a===void 0)return;let o=O(n,`agent_id`),s=pt(a),c=Te(t.files.stateDir,s),l=o===void 0?void 0:Te(t.files.stateDir,s,pt(o)),u=en(await M(c)),d=l===void 0?void 0:tn(await M(l)),f=V({payload:n,config:r,secret:i,now:Math.floor(t.now()/1e3),paths:t.paths,...u===void 0?{}:{session:u},...d===void 0?{}:{agent:d}});f.event!==void 0&&t.launchSender(JSON.stringify(f.event)),f.remove===`session`?await we(t.files.stateDir,`${s}.`):(f.session!==void 0&&await N(c,JSON.stringify(f.session)),l!==void 0&&f.remove===`agent`?await b(l,{force:!0}):l!==void 0&&f.agent!==void 0&&await N(l,JSON.stringify(f.agent))),await nn(t,O(n,`hook_event_name`),f)}const on=`hivefloor ${Y}: show your Claude Code sessions in a Hivefloor office
|
|
16
16
|
|
|
17
17
|
Usage:
|
|
18
18
|
hivefloor init [--url URL] [--public NAME] [--rotate] [--secret-stdin]
|
|
@@ -30,4 +30,4 @@ Usage:
|
|
|
30
30
|
hivefloor --version Print the version
|
|
31
31
|
|
|
32
32
|
Docs: https://github.com/valerymelou/hivefloor
|
|
33
|
-
`,
|
|
33
|
+
`,sn=/* @__PURE__ */ new Map([[`init`,Vt],[`add-project`,ze],[`doctor`,It],[`preview`,Ut],[`pause`,(e,t)=>Ht(!0,e,t)],[`resume`,(e,t)=>Ht(!1,e,t)],[`uninstall`,Wt],[`deploy`,je]]);async function cn(e,t){let n=P(t.env,t.home,t.windows),r=await R(n),i=await z(n);if(e===void 0||r===void 0||i===void 0||r.paused)return;let a=await ce(e,{endpoint:r.endpoint,secret:i,now:t.now,fetch:t.fetch});t.env.HIVEFLOOR_DEBUG===`1`&&await g(n.debugLog,`${JSON.stringify({at:new Date(t.now()).toISOString(),status:a??null})}\n`)}async function ln(e,t){try{await an(await t.readStdin(),{files:P(t.env,t.home,t.windows),paths:{home:t.home,windows:t.windows},now:t.now,launchSender:t.launchSender,record:e.includes(`--record`),debug:t.env.HIVEFLOOR_DEBUG===`1`})}catch{}return 0}async function un(e,t){let[n,...r]=e;if(n===`hook`)return ln(r,t);if(n===`__send`){try{await cn(r[0],t)}catch{}return 0}if(n===`--version`||n===`-v`)return t.stdout(`${Y}\n`),0;if(n===void 0||n===`help`||n===`--help`||n===`-h`)return t.stdout(on),0;let i=sn.get(n);if(i===void 0)return t.stderr(`hivefloor: unknown command "${n}"\n\n${on}`),2;try{return await i(r,t)}catch(e){let r=e instanceof Error?e.message:String(e);return t.stderr(`hivefloor ${n}: ${r}\n`),2}}const $=process.argv.slice(2),dn=le(process.argv[1]);if($[0]===`hook`||$[0]===`__send`){let e=()=>process.exit(0);process.on(`uncaughtException`,e),process.on(`unhandledRejection`,e),setTimeout(e,2500).unref()}async function fn(){if(process.stdin.isTTY)return``;let e=[],t=0;for await(let n of process.stdin){if(t+=n.length,t>8388608)return``;e.push(n)}return Buffer.concat(e).toString(`utf8`)}async function pn(e){let t=f({input:process.stdin,output:process.stdout});try{return await t.question(e)}finally{t.close()}}function mn(e){try{let t=ue(process.execPath,dn);s(t.file,[...t.args,`__send`,e],{detached:!0,stdio:`ignore`,windowsHide:!0}).unref()}catch{}}function hn(e,t,n){return new Promise(r=>{let i=s(e,[...t],{stdio:[n===void 0?`inherit`:`pipe`,`inherit`,`inherit`]});i.stdin?.end(n),i.on(`error`,()=>{r(1)}),i.on(`close`,e=>{r(e??1)})})}process.exitCode=await un($,{env:process.env,home:d(),cwd:process.cwd(),windows:process.platform===`win32`,execPath:process.execPath,script:dn,now:()=>Date.now(),readStdin:fn,stdout:e=>process.stdout.write(e),stderr:e=>process.stderr.write(e),interactive:process.stdin.isTTY&&process.stdout.isTTY,ask:pn,randomSecret:()=>u(32).toString(`base64url`),fetch,runProcess:hn,launchSender:mn});export{};
|