chamba 0.9.0 → 0.10.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/README.md +10 -4
- package/dist/commands/dev.js +11 -11
- package/dist/commands/menu.js +1 -1
- package/dist/commands/settings.js +9 -6
- package/dist/lib/awake-holder.js +3 -0
- package/dist/lib/awake-marker.js +4 -0
- package/dist/lib/awake.js +1 -0
- package/dist/lib/constants.js +1 -1
- package/dist/lib/global-config.js +3 -3
- package/dist/lib/skills.js +2 -2
- package/package.json +1 -1
- package/templates/pane-apps/client/assets/api-Cyoc3E6K.css +1 -0
- package/templates/pane-apps/client/assets/home-CLFnmg7u.css +1 -0
- package/templates/pane-apps/client/assets/home-CrhBkqDQ.js +1 -0
- package/templates/pane-apps/client/assets/reviews-CKk1bus6.js +153 -0
- package/templates/pane-apps/client/assets/reviews-DzHtA35Q.css +1 -0
- package/templates/pane-apps/client/assets/{files-BkmyervY.js → search-DgFnnu-J.js} +1 -1
- package/templates/pane-apps/client/assets/specs-JvdNFtXR.js +13 -0
- package/templates/pane-apps/client/assets/{useNow-BHFKFraS.js → useNow-Ww-Gffnk.js} +1 -1
- package/templates/pane-apps/client/home/index.html +5 -5
- package/templates/pane-apps/client/reviews/index.html +6 -6
- package/templates/pane-apps/client/specs/index.html +4 -4
- package/templates/pane-apps/server/home.mjs +11 -12
- package/templates/pane-apps/server/reviews.mjs +18 -18
- package/templates/pane-apps/server/specs.mjs +4 -4
- package/templates/skills/dx-spec/SKILL.md +4 -16
- package/templates/skills/dx-spec/references/review-guide.md +13 -7
- package/templates/skills/dx-spec/references/spec-guide.md +11 -4
- package/templates/skills/dx-spec/references/stages.md +38 -22
- package/templates/skills/dx-spec-execute/SKILL.md +5 -21
- package/templates/webterm/README.md +11 -8
- package/templates/webterm/awake.js +27 -0
- package/templates/webterm/config.js +10 -0
- package/templates/webterm/public/app/state.js +4 -0
- package/templates/webterm/public/app/tabs.js +37 -3
- package/templates/webterm/public/styles.css +13 -0
- package/templates/webterm/server.js +24 -1
- package/templates/webterm/tools/home.js +25 -3
- package/templates/pane-apps/client/assets/api-DNLbSBpK.css +0 -1
- package/templates/pane-apps/client/assets/home-3SeGzySM.css +0 -1
- package/templates/pane-apps/client/assets/home-Cu9xOd2i.js +0 -1
- package/templates/pane-apps/client/assets/reviews-DMrGB-kG.js +0 -153
- package/templates/pane-apps/client/assets/reviews-nK_yRav9.css +0 -1
- package/templates/pane-apps/client/assets/specs-Cabb15F0.js +0 -13
- package/templates/skills/dx-spec/references/principles-template.md +0 -2
- /package/templates/pane-apps/client/assets/{api-BBDf_rzz.js → api-CguEsvNp.js} +0 -0
package/README.md
CHANGED
|
@@ -39,6 +39,11 @@ The menu has two doors into that container.
|
|
|
39
39
|
**Web interface** brings it up, opens the interface in your browser, and hands your terminal straight back - the work happens in the tab.
|
|
40
40
|
**Container shell** drops you into a shell inside the container and opens nothing; the greeting there still prints the interface's URL, because it is running either way.
|
|
41
41
|
|
|
42
|
+
Both doors can hold your machine awake while the container is up, so an agent left running keeps working.
|
|
43
|
+
**Settings > Stay awake** is where you turn it on or off, and a machine that was never asked is asked once at its first session.
|
|
44
|
+
The display still sleeps, a closed lid still sends the machine to sleep, and the hold ends the moment the container stops.
|
|
45
|
+
It works on macOS and on Linux with systemd; elsewhere you are never asked, **Settings > Stay awake** says there is nothing to turn on, and your machine sleeps as it always did.
|
|
46
|
+
|
|
42
47
|
## The web pane
|
|
43
48
|
|
|
44
49
|
Beside the terminal is a pane, there from the first second of a session, and the pane holds tools.
|
|
@@ -59,7 +64,7 @@ They live under `~/.chamba/workspaces/<id>/agents/webpane/` on the host, and not
|
|
|
59
64
|
It renders the specs directory of your repository: the work, its artifacts, and where each piece stands.
|
|
60
65
|
Read an artifact as one continuous document, select any part of it to comment on or ask for its removal, and answer what the run asks - a gate on a screen, a round of questions, a decision that needs your judgment - as a form beside the thing it is about.
|
|
61
66
|
Everything is a file in your repository, so two windows agree, a session that ends loses nothing, and git sees the work.
|
|
62
|
-
The agent's half is `specs` on its path inside the container, and the `dx-spec` skills carry the craft: one builds a specification and one runs its plan, both honoring the
|
|
67
|
+
The agent's half is `specs` on its path inside the container, and the `dx-spec` skills carry the craft: one builds a specification and one runs its plan, both honoring the rules your repository states in its own `AGENTS.md` or `CLAUDE.md`.
|
|
63
68
|
Each agent spells the two commands its own way - `/dx-spec` and `/dx-spec-execute` on claude and opencode, `$dx-spec` and `$dx-spec-execute` on codex - and the buttons on the tab type the spelling of the session they are bound to.
|
|
64
69
|
|
|
65
70
|
**Code Reviews** is where a changeset is read hunk by hunk.
|
|
@@ -73,14 +78,14 @@ The agent's half is `reviews` on its path, and the `dx-review` skill carries the
|
|
|
73
78
|
## Where state lives
|
|
74
79
|
|
|
75
80
|
`chamba.yaml` lives in the workspace and can be committed.
|
|
76
|
-
Everything else is on your machine under `~/.chamba/`: one directory per workspace holding its lock file, agent config, and shadow overlays, plus a host-global `config` for settings that are yours rather than the project's.
|
|
81
|
+
Everything else is on your machine under `~/.chamba/`: one directory per workspace holding its lock file, agent config, and shadow overlays, plus a host-global `config` for settings that are yours rather than the project's - the web interface's port range, and whether chamba keeps this machine awake.
|
|
77
82
|
|
|
78
83
|
## Developing chamba
|
|
79
84
|
|
|
80
85
|
```bash
|
|
81
86
|
pnpm install
|
|
82
87
|
pnpm check # build, typecheck, lint, repo checks, tests
|
|
83
|
-
pnpm release #
|
|
88
|
+
pnpm release # docker tests, bump, commit through the hook, publish to npm
|
|
84
89
|
```
|
|
85
90
|
|
|
86
91
|
Running it is a step from the repo root, on the host, because Docker is not available in the dev container:
|
|
@@ -92,7 +97,8 @@ pnpm chamba # start a session with whatever is already built
|
|
|
92
97
|
|
|
93
98
|
From the root rather than from here: the workspace is the repo, and the directory the command runs in becomes the session's working directory inside the container.
|
|
94
99
|
|
|
95
|
-
`pnpm release` is the whole release process: it reads the live version off npm, offers a bump, runs
|
|
100
|
+
`pnpm release` is the whole release process: it reads the live version off npm, offers a bump, runs the docker tests, commits the bump through the pre-commit hook and publishes.
|
|
101
|
+
The hook builds, lints and tests chamba, so the release does not run `pnpm check` on its own.
|
|
96
102
|
It runs from here or from the repo root, where `pnpm release` is the same command.
|
|
97
103
|
`AGENTS.md` carries the conventions this repo is written to.
|
|
98
104
|
|
package/dist/commands/dev.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import{spawnSync as
|
|
2
|
-
Agent memory, settings, and workspace data are preserved.`);const oe=await
|
|
3
|
-
(for example the workspace directory was renamed).`);const
|
|
4
|
-
Run \`webterm ${
|
|
5
|
-
Widen the range in Settings > Ports.`):
|
|
6
|
-
Check that the workspace cache dir is writable.`);const c=
|
|
7
|
-
Please rebuild to update - this will not affect agent memory, settings, or your data.`);const e=await
|
|
8
|
-
${
|
|
9
|
-
${
|
|
10
|
-
Pick "Container shell" from the menu to work in the terminal instead.`),
|
|
11
|
-
`),process.exit(
|
|
1
|
+
import{spawnSync as k}from"node:child_process";import{createHash as $e}from"node:crypto";import{existsSync as ve}from"node:fs";import{join as j,relative as Le}from"node:path";import{cancel as G,confirm as T,isCancel as y,log as i,outro as C,select as ye}from"@clack/prompts";import{buildAgentContextDocs as Ce,buildAgentMountArgs as Ee,injectAgentContext as Pe}from"../lib/agent-context.js";import{ensureAwakeHolder as Re,isAwakeSupported as xe}from"../lib/awake.js";import{openInBrowser as Me}from"../lib/browser.js";import{readChambaYaml as We}from"../lib/chamba-yaml.js";import{CONTAINER_KEEP_ALIVE as Te,CONTAINER_STARTUP as _e,CONTAINER_WORKSPACE as X,DEFAULT_PROFILE as ie,GIT_MODE as Ie,LABEL_ENV as se,LABEL_GIT_MODE as re,LABEL_MANAGED as Ne,LABEL_PORTS as ae,LABEL_PROFILE as ce,LABEL_RUNTIME_ENV as le,LABEL_SHADOWS as de,LABEL_TIMEZONE as ue,RUNTIME_ENV as fe,WEB_CONTAINER_PORT as pe}from"../lib/constants.js";import{buildDockerfile as me,buildImageWithTempfile as Oe,computeBuildHash as De,isImageStale as Be}from"../lib/dockerfile-builder.js";import{envLabel as He,envRunArgs as Ve,envWarnings as ze,validateEnvConfig as Fe}from"../lib/env.js";import{readStayAwake as Ue,readWebRange as je,writeStayAwake as Ge}from"../lib/global-config.js";import{buildPnpmStoreMountArgs as Ze}from"../lib/pnpm-store.js";import{assertHostPortsAvailable as Ke,formatPortNotice as Ye,formatWebRange as qe,portEnvArgs as Je,portPublishArgs as Qe,portsLabel as he,validatePortsConfig as Xe}from"../lib/ports.js";import{containerSessionCount as et,loginShellExecArgs as tt}from"../lib/sessions.js";import{buildShadowMountArgs as nt,ensureShadowsInSync as ot,expandShadowPatterns as it}from"../lib/shadows.js";import{buildSkillsMountArgs as st}from"../lib/skills.js";import{buildWebpaneMountArgs as rt,buildWebtermStateMountArgs as at,isWebKey as ct,readWebAgent as lt,readWebKey as ee,resolveWebPort as dt,setWebDefaultCwd as ut,startWebtermAndVerify as ft,webInterfaceAnswers as pt,webInterfaceUrl as we,webPortUsable as ge,webSessionInfo as mt}from"../lib/webterm.js";import{readActiveProfile as ht,readGitMode as wt,writeActiveProfile as gt}from"../lib/workspace-identity.js";function bt(t,n){return n===t?X:`${X}/${Le(t,n)}`}async function kt(t,n){const r=Object.keys(n);if(r.length<=1)return r[0]??ie;const o=ht(t.workspaceId)??ie,A=await ye({message:"Profile:",options:r.map(s=>{const f=n[s]?.description,w=s===o,m=f&&w?`${f} \xB7 current`:f??(w?"current":void 0),d={value:s,label:s};return m&&(d.hint=m),d}),initialValue:o});y(A)&&(G("Cancelled."),process.exit(0));const l=A;return l!==o&>(t.workspaceId,l),l}function At(t){const n=`{{.State.Status}}|{{index .Config.Labels "${de}"}}|{{index .Config.Labels "${ce}"}}|{{index .Config.Labels "${le}"}}|{{index .Config.Labels "${re}"}}|{{index .Config.Labels "${ue}"}}|{{index .Config.Labels "${ae}"}}|{{index .Config.Labels "${se}"}}`,r=k("docker",["inspect","--format",n,t],{encoding:"utf8",stdio:"pipe"});if(r.status!==0)return null;const o=P=>P==="<no value>"?"":P,[A="",l="",s="",f="",w="",m="",d="",E=""]=r.stdout.trim().split("|");return{status:A,shadowLabel:o(l),profileLabel:o(s),runtimeEnvLabel:o(f),gitModeLabel:o(w),timezoneLabel:o(m),portsLabel:o(d),envLabel:o(E)}}function be(t){return t.length===0?"":[...t].sort().join(",")}const St=/^[A-Za-z][A-Za-z0-9_+-]*(\/[A-Za-z0-9_+-]+){1,2}$/;function $t(){let t;try{t=Intl.DateTimeFormat().resolvedOptions().timeZone}catch{return null}return typeof t!="string"||!St.test(t)||t==="UTC"||t==="Etc/UTC"?null:t}function ke(){const t=Object.entries(fe);if(t.length===0)return"";const n=t.map(([r,o])=>`${r}=${o}`).sort().join(",");return $e("sha256").update(n).digest("hex").slice(0,12)}function te(t){k("docker",["stop",t],{stdio:"pipe"}),k("docker",["rm",t],{stdio:"pipe"})}function vt(t,n){return k("docker",["exec","-u","root",...n?[]:["-i","-t"],t,"node",_e,"--summary"],{stdio:n?"pipe":"inherit"}).status===0}async function Ae(t){const{containerName:n,workspaceRoot:r,cacheDir:o,templatesDir:A,activeProfile:l,profileHook:s,expandedShadows:f,envConfig:w,hasGit:m,gitMode:d,shadowPatterns:E,workspaceName:P,portMappings:_,webPort:h,noCache:a,quiet:c=!1}=t,D=c?"pipe":["ignore","ignore","inherit"],B=he(_),Z=He(w),H=nt(o,f),V=Ce(m,E,d),I=Ve(w),z=Ee(o),N=st(o),K=Ze(o),Y=at(o),F=rt(o),R=["-v",`${r}:${X}`,...H,...z,...N,...K,...Y,...F],L=$t(),q=["--label",`${Ne}=true`,"--label",`${de}=${be(f)}`,"--label",`${ce}=${l}`,"--label",`${le}=${ke()}`,"--label",`${re}=${d}`,"--label",`${ue}=${L??""}`],x=[...Object.entries(fe).flatMap(([p,g])=>["-e",`${p}=${g}`]),...L===null?[]:["-e",`TZ=${L}`],"-e",`CHAMBA_WORKSPACE=${P}`,"-e",`CHAMBA_GIT_MODE=${d}`],u=At(n);let O=u?.status??null;if(u!==null){const p=be(f),g=u.shadowLabel!==p,b=u.profileLabel!==l,J=u.runtimeEnvLabel!==ke(),U=u.gitModeLabel!==d,Q=u.timezoneLabel!==(L??""),W=u.portsLabel!==B,v=u.envLabel!==Z;if(g||b||J||U||Q||W||v){let $;b?$=`Profile changed (${u.profileLabel} -> ${l})`:g?$="Shadow paths changed":U?$=`Git mode changed (${u.gitModeLabel||"<unset>"} -> ${d})`:Q?$=`Timezone changed (${u.timezoneLabel||"<unset>"} -> ${L??"<unset>"})`:W?$="Ports changed":v?$="Environment variables changed":$="Runtime environment updated";const ne=!c&&u.status==="running";if(ne){i.warn(`${$} - applying this needs to recreate the running container, which stops any open sessions.
|
|
2
|
+
Agent memory, settings, and workspace data are preserved.`);const oe=await T({message:"Recreate the container now?",initialValue:!0});(y(oe)||!oe)&&(G("Session cancelled - container left running."),process.exit(0))}te(n),O=null,b&&k("docker",["rmi",n],{stdio:"pipe"}),!c&&!ne&&i.info(`${$} - ${b?"rebuilding":"recreating container"}...`)}}ot(o,f,r),Pe(o,V);let e=h;const S=async()=>{const p=me(j(A,"Dockerfile"),s),g=await Oe(p,A,n,a,c);g.status!==0&&(c||C("Failed to build container image."),process.exit(g.status));let b=_;h!==void 0&&!await ge(h,n)&&(c||i.warn(`Web interface: host port ${h} was taken before the container could start - continuing without it.`),b=_.filter(v=>v.host!==h),e=void 0);try{await Ke(b,e)}catch(v){c||C(v instanceof Error?v.message:String(v)),process.exit(1)}c||i.info("Starting dev container...");const J=e!==void 0?["-e",`CHAMBA_WEB_URL=${we(e,null)}`]:[],U=["run","-d","--name",n,...R,...I,...x,...J,...Je(b),...Qe(b),"--security-opt","no-new-privileges:true",...q,"--label",`${ae}=${he(b)}`,"--label",`${se}=${Z}`,n,...Te],W=k("docker",U,{stdio:c?"pipe":["ignore","ignore","pipe"]});W.status!==0&&(c||(process.stderr.write(W.stderr?.toString()??""),C("Failed to start dev container.")),process.exit(W.status??1))},M=p=>({status:p,webPort:e??null});if(O===null)return await S(),M("created");if(O==="exited"){c||i.info("Resuming dev container...");const p=k("docker",["start",n],{stdio:D});if(p.status!==0){c&&process.exit(p.status??1),i.warn(`This container could not start - a host path it was created against has likely moved or been removed
|
|
3
|
+
(for example the workspace directory was renamed).`);const g=await T({message:"Recreate it now? Your agent memory, settings, and workspace data are preserved.",initialValue:!0});return(y(g)||!g)&&(C("Failed to start dev container."),process.exit(p.status??1)),te(n),await S(),M("created")}return M("resumed")}else return M("connected")}async function Se(t,n,r,o){await ft(t,n,r,o)||i.warn(`Web interface: the server did not come up on port ${r}, so the URL in the greeting will not answer.
|
|
4
|
+
Run \`webterm ${n}\` in the container to see why, or just run \`${n}\` in the terminal.`)}async function Lt(){if(Ue()!==null||!xe())return;const t=await T({message:"Keep this machine awake while a chamba container is up?",initialValue:!0});y(t)||(Ge(t?"on":"off"),i.info(t?"Stay awake is on. Change it under Settings > Stay awake.":"Stay awake is off. Turn it on under Settings > Stay awake."))}async function yt(t,n){const r=await Re({cacheDir:t,container:n});r==="unsupported"?i.info("Stay awake: not available on this platform. The session goes on, and the machine sleeps as it always did."):r==="failed"&&i.warn("Stay awake: the hold did not start, so this machine may sleep while the container is up.")}async function Gt(t,n,r){const o=r?.mode??"web",A=process.cwd(),l=n.workspaceRoot,s=n.containerName,f=n.workspaceDir,w=j(t,"templates"),m=We(l);m||(i.error("chamba.yaml not found or invalid."),process.exit(1));let d;try{d=Xe(m.ports??[])}catch(e){i.error(e instanceof Error?e.message:String(e)),process.exit(1)}const E=je(),P=new Set(d.map(e=>e.host)),_=async e=>!P.has(e)&&await ge(e,s),h=await dt(n.workspaceId,E,_);let a=null;h.ok?(h.movedFrom!==void 0&&i.info(`Web interface: port ${h.movedFrom} was not available - moved to ${h.port} and kept there.`),a=h.port,d.push({host:a,container:pe})):h.reason==="exhausted"?i.warn(`Web interface: no free port left in ${qe(E)} - web interface skipped this session.
|
|
5
|
+
Widen the range in Settings > Ports.`):i.warn(`Web interface: the port assignment could not be recorded for this workspace - web interface skipped this session.
|
|
6
|
+
Check that the workspace cache dir is writable.`);const c=bt(l,A),D=m.profiles??{},B=await kt(n,D),H=D[B]?.dockerfile_hook,V=m.shadow_paths??[],{paths:I,skippedTracked:z}=it(V,l);I.length>0&&i.info(`Shadow paths active: ${I.join(", ")} (Settings > Shadow paths)`),z.length>0&&i.warn(`Skipped ${z.length} shadow path(s) tracked by git`);let N;try{N=Fe(m.env,l)}catch(e){i.error(e instanceof Error?e.message:String(e)),process.exit(1)}for(const e of ze(N))i.warn(e);const K=ve(j(l,".git")),Y=wt(n.workspaceId)??Ie.local,F={containerName:s,workspaceRoot:l,cacheDir:f,templatesDir:w,activeProfile:B,profileHook:H,expandedShadows:I,envConfig:N,hasGit:K,gitMode:Y,shadowPatterns:V,workspaceName:n.workspaceId,portMappings:d,...a!==null&&{webPort:a},...r?.noCache!==void 0&&{noCache:r.noCache}};let R=await Ae(F);a=R.webPort;const L=me(j(w,"Dockerfile"),H),q=De(L,w);let x=Be(s,q);if(x){i.warn(`This container's image is out of date.
|
|
7
|
+
Please rebuild to update - this will not affect agent memory, settings, or your data.`);const e=await T({message:"Rebuild now? (Recommended)",initialValue:!0});y(e)&&(G("Session cancelled."),process.exit(0)),e&&(te(s),k("docker",["rmi",s],{stdio:"pipe"}),R=await Ae(F),a=R.webPort,x=!1)}for(const e of d)e.container!==pe&&i.info(Ye(e));if(!vt(s,x))if(x){const e=await T({message:"Startup checks failed (likely due to outdated image). Connect anyway?",initialValue:!0});(!e||y(e))&&(G("Session cancelled."),process.exit(0))}else C("Startup checks failed."),process.exit(1);await Lt(),await yt(f,s);const u=lt(f);if(R.status!=="connected"?a!==null&&await Se(s,u,a,c):a!==null&&(await pt(a)?await ut(a,ee(s),c):await Se(s,u,a,c)),o==="web"){const e=a===null?null:ee(s);if(a!==null&&ct(e)){const S=we(a,e);Me(S)?i.info(`Web interface: opened in your browser
|
|
8
|
+
${S}`):i.info(`Web interface: open this in your browser
|
|
9
|
+
${S}`),C("The container and the interface keep running. Run chamba again for the menu.")}else i.warn(`Web interface: there is nothing to open (see above).
|
|
10
|
+
Pick "Container shell" from the menu to work in the terminal instead.`),C("The container is running.");return}const O=k("docker",tt(c,s),{stdio:"inherit"});if(et(s)===0){const e=(a===null?null:await mt(a,ee(s)))?.sessions??0;if(e>0){const M=e===1?"1 agent session is":`${e} agent sessions are`,p=e===1?"it":"them";i.warn(`Web interface: ${M} open in the browser - stopping the container ends ${p}.`)}const S=await T({message:"Last session to this container closed. Stop it? (resumes fast)",initialValue:e===0});!y(S)&&S&&(i.info("Stopping container..."),k("docker",["stop",s],{stdio:"pipe"}),i.info("Container stopped."))}process.stdout.write(`
|
|
11
|
+
`),process.exit(O.status??0)}export{$t as hostTimezone,bt as resolveWorkdir,Gt as run,Ae as startContainer};
|
package/dist/commands/menu.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync as y}from"node:fs";import{join as
|
|
1
|
+
import{existsSync as y}from"node:fs";import{join as S}from"node:path";import{styleText as e}from"node:util";import{cancel as $,isCancel as A,log as P,select as j}from"@clack/prompts";import{isAwakeSupported as x}from"../lib/awake.js";import{readChambaYaml as C}from"../lib/chamba-yaml.js";import{DEFAULT_PROFILE as r}from"../lib/constants.js";import{readStayAwake as I}from"../lib/global-config.js";import{readActiveProfile as R}from"../lib/workspace-identity.js";async function N(u){const{ctx:o,activeCount:l,workspaceRunning:s,version:m}=u,d=y(S(o.workspaceRoot,".git"));let t=[];try{t=Object.keys(C(o.workspaceRoot)?.profiles??{})}catch{}const i=R(o.workspaceId),f=t.includes(r)?r:t[0]??r,b=i&&t.includes(i)?i:f,w=e(["bold","gray"]," \xB7 "),g=s?`${e("bold",`${o.workspaceId} container`)} ${e(["bold","green"],"up")}`:e("bold",o.workspaceId),c=[e("bold",`chamba v${m}`),g];t.length>1&&c.push(e("bold",`profile: ${b}`));const k=c.join(w),n=[],a=l-(s?1:0);a>0&&n.push(`${a} other container${a===1?"":"s"} up`),d||n.push("no git");const p=n.length>0?[e("gray",n.join(" \xB7 "))]:[];I()==="on"&&x()&&l>0&&p.push(e("gray","Stay awake is on: with the lid open, this computer does not sleep while a container is running, so agents keep working.")),P.message([k,...p]);const v=[{value:"web",label:"Web interface",hint:"open this workspace in your browser"},{value:"shell",label:"Container shell",hint:"a shell inside the container, no browser"},...s?[{value:"stop",label:"Stop container",hint:"stops this workspace's container"}]:[],{value:"settings",label:"Settings",hint:"git mode, shadow paths, web, rebuild"},{value:"advanced",label:"Advanced",hint:"stop, clear, remove, uninstall"},{value:"quit",label:"Quit"}],h=await j({message:"Menu:",options:v});return A(h)?($(),"quit"):h}export{N as run};
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
import{spawnSync as l}from"node:child_process";import{relative as I}from"node:path";import{cancel as v,confirm as
|
|
1
|
+
import{spawnSync as l}from"node:child_process";import{relative as I}from"node:path";import{cancel as v,confirm as f,isCancel as i,log as n,multiselect as O,note as m,outro as W,path as D,select as w,text as S}from"@clack/prompts";import{endAwakeHolder as U,ensureAwakeHolder as E,isAwakeSupported as R,otherHeldWorkspaces as L}from"../lib/awake.js";import{buildDefaultChambaYaml as Y,readChambaYaml as b,writeChambaYaml as y}from"../lib/chamba-yaml.js";import{GIT_MODE as d}from"../lib/constants.js";import{readStayAwake as $,readWebRange as P,writeStayAwake as H,writeWebRange as V}from"../lib/global-config.js";import{formatWebRange as p,PORT_MAX as j,PORT_MIN as B,parseWebRange as _}from"../lib/ports.js";import{countPatternHits as A}from"../lib/shadows.js";import{readWebKey as K,reassignOutOfRangeWebPorts as q,webInterfaceUrl as T}from"../lib/webterm.js";import{readGitMode as C,readWebPort as z,writeGitMode as X}from"../lib/workspace-identity.js";async function F(e){const a=b(e.workspaceRoot);if(!a){n.error("chamba.yaml not found or invalid.");return}const t=a.shadow_paths??[];if(t.length>0){const c=t.map(r=>{const h=A(r,e.workspaceRoot);return` ${r} (${h} ${h===1?"match":"matches"})`});m(c.join(`
|
|
2
2
|
`),"Shadow patterns")}else n.info("No shadow patterns configured.");n.message(`Shadow patterns block the agent from seeing matching host paths -
|
|
3
3
|
the container gets an empty, isolated copy instead.
|
|
4
4
|
Supports gitignore-style patterns (e.g. node_modules, .env*).
|
|
5
|
-
Git-tracked paths are skipped to avoid worktree diversions.`);const o=[{value:"add",label:"Add pattern or path"}];t.length>0&&o.push({value:"remove",label:"Remove patterns"}),o.push({value:"back",label:"\u2190 Back"});const s=await
|
|
5
|
+
Git-tracked paths are skipped to avoid worktree diversions.`);const o=[{value:"add",label:"Add pattern or path"}];t.length>0&&o.push({value:"remove",label:"Remove patterns"}),o.push({value:"back",label:"\u2190 Back"});const s=await w({message:"Shadow paths:",options:o});i(s)||s==="back"||(s==="add"?await J(e):s==="remove"&&await N(e))}async function J(e){const a=b(e.workspaceRoot);if(!a)return;const t=[...a.shadow_paths??[]],o=await w({message:"Add:",options:[{value:"pattern",label:"Pattern",hint:"gitignore-style (e.g. .env*, *.log)"},{value:"path",label:"Specific path",hint:"pick a file or directory"}]});if(!i(o)){if(o==="pattern"){const s=await S({message:"Pattern:",placeholder:"e.g. .env* or node_modules",validate:h=>{const u=(h??"").trim();if(u.length===0)return"Pattern cannot be empty";if(t.includes(u))return"Pattern already exists"}});if(i(s))return;const c=s.trim(),r=A(c,e.workspaceRoot);t.push(c),n.info(`Added: ${c} (${r} ${r===1?"match":"matches"})`)}else{const s=await D({message:"Path to shadow:",root:e.workspaceRoot,directory:!0});if(i(s))return;const c=s.trim(),r=I(e.workspaceRoot,c);if(!r||r.startsWith("..")){n.warn("Path must be inside the workspace directory. Skipped.");return}if(t.includes(r)){n.warn(`"${r}" is already in shadow patterns. Skipped.`);return}t.push(r),n.info(`Added: ${r}`)}a.shadow_paths=t,y(e.workspaceRoot,a),await g(e)}}async function N(e){const a=b(e.workspaceRoot);if(!a?.shadow_paths?.length)return;const t=await O({message:"Select patterns to remove: (space to toggle, enter to confirm)",options:a.shadow_paths.map(s=>({value:s,label:s}))});if(i(t))return;const o=new Set(t);a.shadow_paths=a.shadow_paths.filter(s=>!o.has(s)),y(e.workspaceRoot,a),n.success(`Removed ${o.size} pattern(s).`),await g(e)}async function Q(e){const a=C(e.workspaceId)??d.local;m(`Local - local mutations allowed; remote blocked
|
|
6
6
|
Strict - read-only; mutations and remote blocked
|
|
7
|
-
Unrestricted - no chamba-enforced restrictions`,"Git mode");const t=await
|
|
7
|
+
Unrestricted - no chamba-enforced restrictions`,"Git mode");const t=await w({message:"Git mode:",options:[{value:d.local,label:"Local",hint:a===d.local?"current \xB7 default":"default"},{value:d.strict,label:"Strict",...a===d.strict?{hint:"current"}:{}},{value:d.unrestricted,label:"Unrestricted",...a===d.unrestricted?{hint:"current"}:{}}],initialValue:a});if(!i(t)&&t!==a){if(t===d.unrestricted){const o=await f({message:"Unrestricted mode disables chamba's built-in git restrictions (allows remote push/pull/fetch). Continue?",initialValue:!1});if(i(o)||!o){n.info("Git mode unchanged.");return}}X(e.workspaceId,t),n.success(`Git mode set to ${t}.`),await g(e)}}async function Z(e){if(!R()){m("chamba holds a machine awake with `caffeinate` on macOS and `systemd-inhibit` on Linux.\nNeither is available here, so there is nothing to turn on.","Stay awake");return}const a=$();m(`On - while a chamba container is up, this computer does not sleep, so agents keep working
|
|
8
|
+
Off - the computer sleeps as it always did
|
|
9
|
+
|
|
10
|
+
The display sleeps either way, and a closed lid still sends the computer to sleep.`,"Stay awake");const t=await w({message:"Stay awake:",options:[{value:"on",label:"On",...a==="on"?{hint:"current"}:{}},{value:"off",label:"Off",...a==="off"?{hint:"current"}:{}}],initialValue:a??"on"});if(i(t))return;if(H(t),t==="off"){await U({cacheDir:e.workspaceDir,container:e.containerName}),n.success("Stay awake is off. This computer sleeps as it always did.");const s=L(e.workspaceId);s.length>0&&n.info(`Still held for ${s.join(", ")}. Each of those ends with its own container.`);return}const o=await E({cacheDir:e.workspaceDir,container:e.containerName});o==="failed"?n.warn("Stay awake is on, and the hold did not start. This machine may sleep while the container is up."):o==="no-container"?n.success("Stay awake is on. The hold starts with this workspace's container."):n.success("Stay awake is on. This computer does not sleep while a container is up.")}async function x(e){const a=P(),t=z(e.workspaceId),o=t===null?null:K(e.containerName),s=t===null?"no port assigned yet":o!==null?T(t,o):`${T(t,null)} (the key comes with the interface when it starts)`;m(`web interface range: ${p(a)} (all workspaces)
|
|
8
11
|
this workspace: ${s}`,"Ports"),n.message(`The host port range the web interface draws from.
|
|
9
12
|
Each workspace keeps one sticky port from it, so its URL never changes.
|
|
10
13
|
Loopback-only, never reachable off this machine, and the URL carries a key
|
|
11
14
|
that is minted fresh every time the interface starts.
|
|
12
|
-
Ports your own project publishes are set in chamba.yaml, not here.`);const
|
|
15
|
+
Ports your own project publishes are set in chamba.yaml, not here.`);const c=await S({message:"Port range (START-END):",placeholder:p(a),initialValue:p(a),validate:u=>{const k=(u??"").trim();if(!/^\d+-\d+$/.test(k))return"Use START-END, e.g. 3900-3999";if(!_(k)){const[M=0,G=0]=k.split("-").map(Number);return M>=G?"Start must be below end":`Ports must be between ${B} and ${j}`}}});if(i(c))return;const r=_(c.trim());if(!r||p(r)===p(a))return;V(r);const h=q(r);for(const u of h)n.info(`${u.workspaceId}: port ${u.from} -> ${u.to}`);n.success(`Port range set to ${p(r)}.`),await g(e)}async function g(e){const a=e.containerName,t=l("docker",["inspect","--format","{{.State.Status}}",a],{encoding:"utf8",stdio:"pipe"});if((t.status===0?t.stdout.trim():null)!=="running"){n.info("Changes will apply on next session.");return}const s=await f({message:"Stop the running container so changes apply on next session?"});if(i(s)||!s){n.warn("Container still running with old config - it will be recreated on next session.");return}n.info("Stopping container..."),l("docker",["stop",a],{stdio:"pipe"}),l("docker",["rm",a],{stdio:"pipe"}),n.info("Container removed. Open a new session to apply changes.")}async function ee(e){const a=b(e.workspaceRoot);if(!a){n.error("chamba.yaml not found or invalid.");return}m(`This will reset chamba.yaml to the minimal default (workspace_id + shadow_paths).
|
|
13
16
|
Your workspace_id is preserved; shadow_paths reset to the defaults (node_modules, .env*).
|
|
14
|
-
Any env, profiles, or ports settings will be removed - re-add them with your editor, which reads the schema the file points at.`,"Reset chamba.yaml");const t=await
|
|
15
|
-
Agent memory, settings, and workspace data are preserved.`);const
|
|
17
|
+
Any env, profiles, or ports settings will be removed - re-add them with your editor, which reads the schema the file points at.`,"Reset chamba.yaml");const t=await f({message:"Reset chamba.yaml to defaults?"});if(i(t)||!t)return;const o=Y(a.workspace_id);y(e.workspaceRoot,o),n.success("chamba.yaml reset to defaults."),await g(e)}function te(){if(!R())return"not available on this platform";const e=$();return e===null?"not set":`current: ${e}`}async function me(e){for(;;){const t=[{value:"git-mode",label:"Git mode",hint:`current: ${C(e.workspaceId)??d.local}`},{value:"shadow-paths",label:"Shadow paths",hint:"manage shadow patterns"},{value:"ports",label:"Ports",hint:`web interface range: ${p(P())}`},{value:"stay-awake",label:"Stay awake",hint:te()},{value:"rebuild",label:"Rebuild container",hint:"force a fresh image build"},{value:"clean-rebuild",label:"Clean rebuild",hint:"fresh build, no cache"},{value:"reset",label:"Reset config",hint:"restore chamba.yaml to defaults"},{value:"back",label:"\u2190 Back"}],o=await w({message:"Settings:",options:t});if(i(o)||o==="back")return"back";switch(o){case"git-mode":await Q(e);break;case"shadow-paths":await F(e);break;case"ports":await x(e);break;case"stay-awake":await Z(e);break;case"rebuild":return"rebuild";case"clean-rebuild":return"clean-rebuild";case"reset":await ee(e);break}}}async function fe(e){if(l("docker",["inspect","--type","container",e],{encoding:"utf8"}).status!==0){n.info(`Container ${e} is not running.`);return}const t=await f({message:`Stop ${e}?`});if(i(t)||!t){v();return}n.info(`Stopping ${e}...`),l("docker",["stop",e],{stdio:"pipe"}),W(`${e} stopped.`)}async function we(e){const a=l("docker",["inspect","--type","container","--format","{{.State.Status}}",e],{encoding:"utf8",stdio:"pipe"}),t=a.status===0;if(t&&a.stdout.trim()==="running"){n.warn(`Rebuilding stops and removes the running container.
|
|
18
|
+
Agent memory, settings, and workspace data are preserved.`);const c=await f({message:"Rebuild now?",initialValue:!0});if(i(c)||!c)return v("Rebuild cancelled - container left running."),!1}return t&&(n.info(`Stopping container ${e}...`),l("docker",["stop",e],{stdio:"pipe"}),l("docker",["rm",e],{stdio:"pipe"})),(l("docker",["images","-q",e],{encoding:"utf8",stdio:"pipe"}).stdout??"").trim().length>0&&(n.info(`Removing image ${e}...`),l("docker",["rmi",e],{stdio:"pipe"})),n.info("Image removed - starting fresh build\u2026"),!0}export{we as resetImage,me as run,fe as stop};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{spawn as m}from"node:child_process";import{utimesSync as w}from"node:fs";import{awakeMarkerPath as d,claimAwakeMarker as g,dockerWaitArgv as M,isAwakeMarkerLive as I,readAwakeMarker as p,removeAwakeMarker as u,writeAwakeMarker as x}from"./awake-marker.js";const[r="",n="",o="",S="",...l]=process.argv.slice(2),s=Number(S),v={cacheDir:r,container:n};(!r||!n||!o||!Number.isFinite(s)||s<=0||l.length===0)&&(process.stderr.write(`awake-holder: needs a cache dir, a container name, a container id, a touch interval and an inhibitor command
|
|
2
|
+
`),process.exit(1));let t=null,a=null,f=!1;for(const e of["SIGTERM","SIGINT","SIGHUP"])process.on(e,()=>i(!0));process.on("uncaughtException",()=>i(!0)),process.on("unhandledRejection",()=>i(!0));const c=p(r);c!==null&&I(v,c,o)&&process.exit(0),c!==null&&u(r);const h=new Date().toISOString();try{g(r,{pid:process.pid,container:n,id:o,started:h})||process.exit(0)}catch(e){process.stderr.write(`awake-holder: cannot write ${d(r)} - ${e instanceof Error?e.message:String(e)}
|
|
3
|
+
`),process.exit(1)}const[b="",...A]=l;if(t=m(b,[...A,...M(n)],{detached:!0,stdio:"ignore"}),t.on("exit",()=>i(!0)),t.on("error",()=>i(!0)),t.pid!==void 0)try{x(r,{pid:process.pid,container:n,id:o,started:h,inhibitor:t.pid})}catch{}a=setInterval(()=>{if(!k())return i(!1);try{const e=new Date;w(d(r),e,e)}catch{i(!0)}},s),a.unref();function k(){return p(r)?.pid===process.pid}function i(e){if(!f){if(f=!0,a!==null&&clearInterval(a),t?.pid!==void 0)try{process.kill(-t.pid,"SIGTERM")}catch{}e&&k()&&u(r),process.exit(0)}}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{spawnSync as x}from"node:child_process";import{readFileSync as w,renameSync as b,writeFileSync as l}from"node:fs";import{join as m}from"node:path";import{WEBTERM_AWAKE_FILE as g,WEBTERM_STATE_DIR as A}from"./constants.js";import{safeRmSync as E}from"./safe-rm.js";function M(t){return["docker","wait",t]}const k="awake-holder";function o(t){return m(t,A,g)}function y(t){let n;try{n=w(o(t),"utf8")}catch{return null}const e=new Map;for(const u of n.split(`
|
|
2
|
+
`)){const s=u.indexOf("=");s!==-1&&e.set(u.slice(0,s).trim(),u.slice(s+1).trim())}const r=Number(e.get("pid")),i=e.get("container"),f=e.get("id"),a=e.get("started"),c=Number(e.get("inhibitor"));return!Number.isInteger(r)||r<=0||!i||!f||!a?null:{pid:r,container:i,id:f,started:a,...Number.isInteger(c)&&c>0?{inhibitor:c}:{}}}function d(t){const n=[`pid=${t.pid}`,`container=${t.container}`,`id=${t.id}`,`started=${t.started}`];return t.inhibitor!==void 0&&n.push(`inhibitor=${t.inhibitor}`),`${n.join(`
|
|
3
|
+
`)}
|
|
4
|
+
`}function W(t,n){try{return l(o(t),d(n),{flag:"wx"}),!0}catch(e){if(e.code==="EEXIST")return!1;throw e}}function F(t,n){const e=o(t),r=`${e}.${n.pid}`;l(r,d(n)),b(r,e)}function S(t){try{E(o(t),{force:!0})}catch{}}function p(t){const n=x("ps",["-ww","-o","args=","-p",String(t)],{encoding:"utf8"});return n.error!==void 0||n.status!==0?null:n.stdout.trim()||null}function h(t,...n){return n.every(e=>$(t,e))}function $(t,n){if(n==="")return!1;for(let e=t.indexOf(n);e!==-1;e=t.indexOf(n,e+1)){const r=e===0?" ":t[e-1],i=e+n.length>=t.length?" ":t[e+n.length];if(/\s/.test(r)&&/\s/.test(i))return!0}return!1}function I(t,n,e,r){return n.id===e&&R(t,n,r)}function R(t,n,e=p){if(n.container!==t.container)return!1;const r=e(n.pid);return r===null?!1:r.includes(k)&&h(r,t.cacheDir,t.container)}function j(t,n,e){const r=y(t.cacheDir);return r===null?null:I(t,r,n,e)?r:(T(t,r,e),S(t.cacheDir),null)}function T(t,n,e=p){if(n.inhibitor===void 0)return;const r=e(n.inhibitor);r===null||!h(r,...M(t.container))||v(-n.inhibitor,"SIGTERM")}function v(t,n){try{return process.kill(t,n),!0}catch{return!1}}export{k as HOLDER_NAME,o as awakeMarkerPath,W as claimAwakeMarker,M as dockerWaitArgv,T as endInhibitor,I as isAwakeMarkerLive,R as isHolderRunning,y as readAwakeMarker,S as removeAwakeMarker,v as signal,j as takeLiveMarker,F as writeAwakeMarker};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{spawn as k,spawnSync as A}from"node:child_process";import{accessSync as h,constants as D}from"node:fs";import{delimiter as x,dirname as g,extname as S,join as s}from"node:path";import{setTimeout as u}from"node:timers/promises";import{fileURLToPath as y}from"node:url";import{endInhibitor as H,HOLDER_NAME as _,isHolderRunning as f,readAwakeMarker as i,removeAwakeMarker as l,signal as o,takeLiveMarker as E}from"./awake-marker.js";import{AWAKE_END_GRACE_MS as M,AWAKE_START_WAIT_MS as I,AWAKE_TOUCH_MS as T}from"./constants.js";import{readStayAwake as b}from"./global-config.js";import{listWorkspaces as v}from"./workspace-identity.js";function p(r,n=process.platform){return n==="darwin"?["caffeinate","-is"]:n==="linux"?["systemd-inhibit","--what=idle:sleep","--who=chamba",`--why=${r} is up`,"--mode=block"]:null}function m(r=process.platform){const n=p("chamba",r);if(n===null)return!1;const[e=""]=n;return R(e)}function R(r){return r.includes("/")?d(r):(process.env.PATH??"").split(x).filter(Boolean).some(e=>d(s(e,r)))}function d(r){try{return h(r,D.X_OK),!0}catch{return!1}}function W(){const r=y(import.meta.url);return s(g(r),`${_}${S(r)}`)}async function K(r,n,e=process.platform){const t=p(r.container,e);if(t===null||!m(e))return!1;const c=k(process.execPath,P(r,n,t),{detached:!0,stdio:"ignore"});c.on("error",()=>{}),c.unref();const w=Date.now()+I;for(;Date.now()<w;){if(i(r.cacheDir)!==null)return!0;await u(50)}return!1}async function z(r,n=process.platform,e=L){if(b()!=="on")return"off";if(!m(n))return"unsupported";const t=e(r.container);return t===null?"no-container":E(r,t)!==null?"already":await K(r,t,n)?"held":"failed"}function L(r){const n=A("docker",["inspect","--format","{{.Id}}|{{.State.Running}}",r],{encoding:"utf8",stdio:"pipe"});if(n.status!==0)return null;const[e="",t=""]=n.stdout.trim().split("|");return e&&t==="true"?e:null}function P(r,n,e,t=T){return[...process.execArgv,W(),r.cacheDir,r.container,n,String(t),...e]}function C(r,n){return r.filter(e=>{const t=i(e.cacheDir);return t!==null&&f(e,t,n)}).map(e=>e.container)}function F(r){const n=v().filter(e=>e.workspaceId!==r).map(e=>({cacheDir:e.workspaceDir,container:e.containerName}));return C(n)}async function J(r,n){const e=i(r.cacheDir);if(e===null)return l(r.cacheDir);if(!f(r,e,n)||!o(e.pid,"SIGTERM"))return a(r,e,n);const t=Date.now()+M;for(;Date.now()<t;){if(!o(e.pid,0))return a(r,e,n);await u(50)}o(e.pid,"SIGKILL"),a(r,e,n)}function a(r,n,e){H(r,i(r.cacheDir)??n,e),l(r.cacheDir)}export{p as awakeArgv,P as awakeHolderArgv,J as endAwakeHolder,z as ensureAwakeHolder,C as heldWorkspaces,m as isAwakeSupported,F as otherHeldWorkspaces,K as startAwakeHolder};
|
package/dist/lib/constants.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{dirname as E}from"node:path";import{fileURLToPath as
|
|
1
|
+
import{dirname as E}from"node:path";import{fileURLToPath as A}from"node:url";const I=E(E(E(A(import.meta.url)))),R=".chamba",a="workspaces",O="global",x="agents",N="shadows",D="pnpm-store",S="webterm",C="chamba.yaml",m="schema",B="chamba.schema.json",M=".lock",P="config",h="1",W=2,U=48,b=["node_modules",".env*"],e="devuser",o=`/home/${e}`,F="/workspace",l=`${o}/startup.mjs`,t=`${o}/.local/share/pnpm/store`,K=["bash","-c",'trap "exit 0" TERM INT; while :; do sleep 86400 & wait $!; done'],i="/usr/local/share/chamba/claude-statusline.sh",d="chamba-",G="chamba.managed",H="chamba.shadows",u="chamba.profile",w="chamba.runtime-env",f="chamba.git-mode",g="chamba.timezone",$="chamba.build-hash",V="chamba.ports",k="chamba.env",v="default";import{GIT_MODE as _,GIT_WRAPPER_PATH as c,GIT_WRAPPER_SOURCE as r}from"../../templates/runtime-constants.mjs";const j=Object.values(_),y={CLAUDE_AFK_TIMEOUT_MS:"2147483647",CLAUDE_CODE_DISABLE_FEEDBACK_SURVEY:"1",CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC:"1",CLAUDE_CODE_DISABLE_OFFICIAL_MARKETPLACE_AUTOINSTALL:"1",CLAUDE_CODE_NO_FLICKER:"1",DISABLE_AUTOUPDATER:"1",DISABLE_ERROR_REPORTING:"1",DISABLE_INSTALLATION_CHECKS:"1",DISABLE_TELEMETRY:"1",DISABLE_UPGRADE_COMMAND:"1",DO_NOT_TRACK:"1",OPENCODE_DISABLE_CLAUDE_CODE_SKILLS:"1",npm_config_store_dir:t,pnpm_config_store_dir:t},X=["claude","opencode","codex"],z="claude",Z=3899,q="3900-3999",J="/tmp/webterm.key",s=`${o}/.chamba-webterm`,n="agent",Q=`${s}/${n}`,oo="awake",p=3e4,Eo=p*3,to=2e3,_o=2e3,Ao="webpane",eo=`${o}/.webpane`;export{x as AGENTS_DIR,to as AWAKE_END_GRACE_MS,Eo as AWAKE_STALE_MS,_o as AWAKE_START_WAIT_MS,p as AWAKE_TOUCH_MS,R as CHAMBA_DIR,m as CHAMBA_SCHEMA_DIR,B as CHAMBA_SCHEMA_FILE,C as CHAMBA_YAML,i as CLAUDE_STATUSLINE_PATH,o as CONTAINER_HOME,K as CONTAINER_KEEP_ALIVE,d as CONTAINER_NAME_PREFIX,t as CONTAINER_PNPM_STORE,l as CONTAINER_STARTUP,e as CONTAINER_USER,eo as CONTAINER_WEBPANE_DIR,s as CONTAINER_WEBTERM_STATE_DIR,F as CONTAINER_WORKSPACE,v as DEFAULT_PROFILE,b as DEFAULT_SHADOW_PATHS,z as DEFAULT_WEB_AGENT,_ as GIT_MODE,j as GIT_MODES,c as GIT_WRAPPER_PATH,r as GIT_WRAPPER_SOURCE,P as GLOBAL_CONFIG_FILE,O as GLOBAL_DIR,$ as LABEL_BUILD_HASH,k as LABEL_ENV,f as LABEL_GIT_MODE,G as LABEL_MANAGED,V as LABEL_PORTS,u as LABEL_PROFILE,w as LABEL_RUNTIME_ENV,H as LABEL_SHADOWS,g as LABEL_TIMEZONE,M as LOCK_FILE,h as LOCK_VERSION,I as PACKAGE_ROOT,D as PNPM_STORE_DIR,y as RUNTIME_ENV,N as SHADOWS_DIR,Ao as WEBPANE_DIR,n as WEBTERM_AGENT_FILE,Q as WEBTERM_AGENT_FILE_PATH,oo as WEBTERM_AWAKE_FILE,S as WEBTERM_STATE_DIR,X as WEB_AGENTS,Z as WEB_CONTAINER_PORT,J as WEB_KEY_FILE_PATH,q as WEB_RANGE_DEFAULT,a as WORKSPACES_DIR,U as WORKSPACE_ID_MAX,W as WORKSPACE_ID_MIN};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{mkdirSync as
|
|
2
|
-
`).map(
|
|
1
|
+
import{mkdirSync as g,readFileSync as m,writeFileSync as A}from"node:fs";import{homedir as a}from"node:os";import{join as c}from"node:path";import{CHAMBA_DIR as f,GLOBAL_CONFIG_FILE as w,GLOBAL_DIR as s,WEB_RANGE_DEFAULT as d}from"./constants.js";import{formatWebRange as _,parseWebRange as l}from"./ports.js";const r={webRange:"web_range",stayAwake:"stay_awake"},b=["on","off"];function p(){return c(a(),f,s,w)}function i(){const e=new Map;try{const n=m(p(),"utf8").trimEnd().split(`
|
|
2
|
+
`).map(t=>t.trim()).filter(Boolean);for(const t of n){const o=t.indexOf("=");o!==-1&&e.set(t.slice(0,o),t.slice(o+1))}}catch{}return e}function u(e){g(c(a(),f,s),{recursive:!0});const n=`${[...e].map(([t,o])=>`${t}=${o}`).join(`
|
|
3
3
|
`)}
|
|
4
|
-
`;
|
|
4
|
+
`;A(p(),n)}function G(){const e=i().get(r.webRange);return(e!==void 0?l(e):null)??l(d)}function S(e){const n=i();n.set(r.webRange,_(e)),u(n)}function k(){const e=i().get(r.stayAwake);return b.find(n=>n===e)??null}function B(e){const n=i();n.set(r.stayAwake,e),u(n)}export{r as GLOBAL_CONFIG_KEYS,b as STAY_AWAKE_VALUES,p as globalConfigPath,k as readStayAwake,G as readWebRange,B as writeStayAwake,S as writeWebRange};
|
package/dist/lib/skills.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{copyFileSync as
|
|
2
|
-
`),
|
|
1
|
+
import{copyFileSync as T,existsSync as p,mkdirSync as f,readdirSync as g,readFileSync as S,renameSync as E,statSync as I,writeFileSync as M}from"node:fs";import{dirname as h,join as o}from"node:path";import{load as N}from"js-yaml";import{AGENTS_DIR as d,CONTAINER_HOME as b,PACKAGE_ROOT as O,WEB_AGENTS as $}from"./constants.js";import{safeRmSync as y}from"./safe-rm.js";import{renderTemplate as L,writeFileEnsuringDir as _}from"./templates.js";const k=[{audience:["claude"],hostSubpath:o("claude","skills"),container:`${b}/.claude/skills`,insideAgentMount:!0},{audience:["codex","opencode"],hostSubpath:o("shared","skills"),container:`${b}/.agents/skills`,insideAgentMount:!1}],F="skills-manifest.json",R=".skill-staging",j=/^---\r?\n([\s\S]*?)\r?\n---/;function A(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function x(e){const n=j.exec(S(e,"utf8"));if(!n)return null;const t=N(n[1]??""),i=A(t)?t.metadata:void 0,r=A(i)?i.audience:void 0;if(r==null)return null;const c=typeof r=="string"?r.split(","):r;if(!Array.isArray(c)||c.some(u=>typeof u!="string"))throw new Error(`${e}: metadata.audience is neither a name nor a list of names`);const a=c.map(u=>String(u).trim()).filter(u=>u.length>0),s=a.filter(u=>!$.includes(u));if(s.length>0)throw new Error(`${e}: metadata.audience names ${s.join(", ")}, which chamba does not run`);return a.length>0?a:null}function D(e,n){return e===null||n.audience.some(t=>e.includes(t))}function q(e){return k.flatMap(n=>{const t=o(e,d,n.hostSubpath);return f(t,{recursive:!0}),["-v",`${t}:${n.container}:ro`]})}function P(e,n){const t=o(O,"templates","skills");if(!p(t))return;const i=g(t,{withFileTypes:!0}).filter(s=>s.isDirectory()&&p(o(t,s.name,"SKILL.md"))).map(s=>({name:s.name,audience:x(o(t,s.name,"SKILL.md"))})),r=o(e,d,F),c=o(e,d,R),a=H(r);for(const s of k){const u=o(e,d,s.hostSubpath),m=i.filter(l=>D(l.audience,s)).map(l=>l.name);G(u,a[s.hostSubpath]??[],m);for(const l of m)v(o(t,l),o(u,l),c,n);a[s.hostSubpath]=[...m].sort()}C(r,a)}function v(e,n,t,i){y(t,{recursive:!0,force:!0}),w(e,t,i),f(h(n),{recursive:!0}),y(n,{recursive:!0,force:!0}),E(t,n)}function w(e,n,t){for(const i of g(e,{withFileTypes:!0})){const r=o(e,i.name),c=o(n,i.name),a=I(r);a.isDirectory()?w(r,c,t):a.isFile()&&(i.name.endsWith(".md")?_(c,L(S(r,"utf8"),t)):(f(h(c),{recursive:!0}),T(r,c)))}}function G(e,n,t){for(const i of n){if(t.includes(i))continue;const r=o(e,i);p(r)&&y(r,{recursive:!0,force:!0})}}const K=/^[A-Za-z0-9._-]+$/;function H(e){try{const n=JSON.parse(S(e,"utf8"));if(A(n))return Object.fromEntries(Object.entries(n).map(([t,i])=>[t,(Array.isArray(i)?i:[]).filter(r=>typeof r=="string"&&K.test(r))]))}catch{}return{}}function C(e,n){f(h(e),{recursive:!0});const t=`${e}.writing`;M(t,`${JSON.stringify(n,null,2)}
|
|
2
|
+
`),E(t,e)}export{k as SKILL_HOMES,q as buildSkillsMountArgs,P as injectSkills,x as readSkillAudience};
|
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--bg:#0d1117;--panel:#161b22;--fg:#e6edf3;--muted:#8b949e;--border:#30363d;--accent:#58a6ff;--ok:#3fb950;--warn:#d29922;--sunken:#0b0e13;--sel:#1f6feb33;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}[data-theme=light]{--bg:#fff;--panel:#f6f8fa;--fg:#1f2328;--muted:#656d76;--border:#d0d7de;--accent:#0969da;--ok:#1a7f37;--warn:#9a6700;--sunken:#f6f8fa;--sel:#ddf4ff;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}*{box-sizing:border-box}html,body,#root{height:100%}body{background:var(--bg);color:var(--fg);margin:0;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;font-size:14px;line-height:1.6}@media (prefers-reduced-motion:no-preference){html{scroll-behavior:smooth}}.workspace{grid-template-columns:minmax(180px,220px) minmax(0,1fr) minmax(220px,280px);height:100%;display:grid}.workspace.is-alone{grid-template-columns:minmax(180px,220px) minmax(0,1fr)}.workspace.has-foot{grid-template-rows:minmax(0,1fr) auto}.workspace-foot{grid-column:1/-1}.nav,.rail{background:var(--panel);font-size:12.5px;overflow:auto}.stage{background:var(--bg);min-width:0;color:var(--fg);flex-direction:column;display:flex;position:relative;overflow:hidden}.stage>*{flex:auto;min-height:0}.nav{border-right:1px solid var(--border);padding:10px 0 24px}.rail{border-left:1px solid var(--border);flex-direction:column;gap:18px;padding:12px 14px 24px;display:flex}.nav-new{border:1px solid var(--border);width:calc(100% - 28px);height:30px;color:var(--accent);font:inherit;cursor:pointer;background:0 0;border-radius:7px;justify-content:center;align-items:center;gap:7px;margin:2px 14px 4px;font-size:12.5px;display:flex}.nav-new:hover{border-color:var(--accent)}.nav-new[aria-pressed=true]{background:var(--sel);border-color:var(--accent)}.nav-new:disabled{color:var(--muted);border-color:var(--border);cursor:default}.nav-note{color:var(--muted);margin:0 14px 4px;font-size:12px;line-height:1.5}.nav-empty{color:var(--muted);margin:0;padding:0 14px}.nav-back{width:100%;color:var(--muted);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;align-items:center;gap:6px;padding:2px 14px 8px;font-size:12px;display:flex}.nav-back:hover{color:var(--accent)}.nav-title{border-bottom:1px solid var(--border);margin-bottom:6px;padding:0 14px 8px}.nav-title-name{overflow-wrap:anywhere;font-weight:600}.nav-title-status{color:var(--muted);letter-spacing:.04em;text-transform:uppercase;font-size:10px}.nav-head,.rail-head{letter-spacing:.06em;text-transform:uppercase;color:var(--muted);margin:12px 0 5px;padding:0 14px;font-size:10.5px;font-weight:700}.rail-head{padding:0}.nav-head{justify-content:space-between;align-items:baseline;gap:8px;display:flex}.nav-head-count{letter-spacing:0;text-transform:none;font-size:10px;font-weight:400}.nav-head button{all:unset;cursor:pointer;width:100%;color:inherit;font:inherit;letter-spacing:inherit;text-transform:inherit;justify-content:space-between;align-items:baseline;gap:8px;display:flex}.nav-head button:hover{color:var(--fg)}.nav-search{margin:6px 14px 4px}.nav-search input{background:var(--sunken);border:1px solid var(--border);width:100%;color:var(--fg);font:inherit;border-radius:5px;padding:3px 7px;font-size:12px}.nav-title-note{color:var(--muted);font-size:11.5px}.nav.has-foot{flex-direction:column;padding-bottom:0;display:flex}.nav.has-foot>*{flex:none}.nav-foot{border-top:1px solid var(--border);background:var(--panel);color:var(--muted);margin:auto 0 0;padding:8px 14px;font-size:11.5px;position:sticky;bottom:0}.nav-list{--nav-line:1.35;margin:0;padding:0;list-style:none}.nav-list button{text-align:left;width:100%;color:inherit;font:inherit;cursor:pointer;background:0 0;border:none;border-left:2px solid #0000;padding:3px 14px;display:block}.nav-list button:hover{color:var(--accent)}.nav-list button[aria-current]{background:var(--sel);border-left-color:var(--accent)}.nav-list button.nav-artifact{padding-left:22px}.nav-list button.nav-row{padding:6px 14px 7px}.nav-list button.nav-row:hover{color:inherit;background:var(--sunken)}.nav-row-sub{color:var(--muted);margin-top:2px;font-size:11.5px}.nav-list button.nav-entry{align-items:baseline;gap:6px;display:flex}.nav-entry-name{overflow-wrap:anywhere;line-height:var(--nav-line);flex:1}.nav-archived .nav-entry-name{color:var(--muted);display:block}.nav-entry-status{color:var(--muted);letter-spacing:.04em;text-transform:uppercase;flex:none;font-size:10px}.nav-entry-awaiting{background:var(--accent);min-width:15px;color:var(--bg);text-align:center;border-radius:7px;flex:none;padding:0 4px;font-size:10px;font-weight:700}.nav-dir{color:var(--muted);letter-spacing:.04em;margin:8px 0 2px;padding:0 14px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10.5px}.nav-sections{margin:0 0 4px;padding:0;font-size:12px;list-style:none}.nav-sections button{color:var(--muted);padding-left:32px}.nav-sections button[aria-current]{color:var(--fg);font-weight:600}.nav-sections button.is-read{opacity:.55}.nav-changed{color:var(--warn);vertical-align:middle;margin-left:6px;font-size:9px}.doc{padding:20px 40px 96px;position:relative;overflow:auto}.doc-facts{color:var(--muted);flex-wrap:wrap;align-items:center;gap:6px;margin-bottom:14px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;display:flex}.doc-changed{color:var(--warn)}.doc-facts-acts{align-items:center;gap:4px;margin-left:auto;display:inline-flex}.doc-section{scroll-margin-top:12px;position:relative}.doc-section.is-read{opacity:.62}.doc-section h2{margin:22px 0 8px;font-size:1.15em}.sec-mark{position:absolute;top:24px;left:-26px}.mark{border:1px solid var(--border);background:var(--bg);color:#0000;cursor:pointer;border-radius:5px;width:20px;height:20px;padding:0;font-size:11px;line-height:1}.doc-section:hover .mark,.mark:focus-visible{color:var(--muted)}.mark[aria-pressed=true]{color:var(--ok);border-color:var(--ok)}.sec-changed{color:var(--warn);margin-left:10px;font-size:11px;font-weight:400}.art-frame{border:1px solid var(--border);background:var(--bg);border-radius:8px;width:100%;height:calc(100vh - 90px)}.art-image img{max-width:100%}.rail-fact{margin:0 0 2px}.theme-toggle{z-index:2;background:var(--bg);color:var(--muted);cursor:pointer;border:none;border-radius:5px;justify-content:center;align-items:center;padding:3px;display:inline-flex;position:absolute;top:20px;right:12px}.theme-toggle svg{display:block}.theme-toggle:hover:enabled{color:var(--accent);background:var(--sel)}.theme-toggle:disabled{opacity:.45;cursor:default}.notice{color:var(--muted);padding:20px 24px}.notice-failure{border-left:3px solid var(--warn);color:var(--fg)}.muted{color:var(--muted)}.visually-hidden{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.tip{z-index:100;border:1px solid var(--border);background:var(--panel);max-width:min(320px,100vw - 12px);color:var(--fg);text-align:left;white-space:normal;pointer-events:none;border-radius:6px;padding:6px 9px;font-size:12px;font-style:normal;font-weight:400;line-height:1.45;position:fixed;top:0;left:0;box-shadow:0 6px 18px #00000059}.plain{white-space:pre-wrap;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12.5px;overflow-x:auto}.prose{overflow-wrap:anywhere;font-size:13.5px}.prose h1{margin:18px 0 8px;font-size:1.4em}.prose h2{margin:18px 0 8px;font-size:1.2em}.prose h3{margin:16px 0 6px;font-size:1.08em}.prose h4,.prose h5,.prose h6{color:var(--muted);margin:14px 0 6px;font-size:1em}.prose p{margin:0 0 10px}.prose ul,.prose ol{margin:0 0 10px;padding-left:22px}.prose li{margin:2px 0}.prose li.task{margin-left:-20px;list-style:none}.task-box{border:1px solid var(--muted);vertical-align:baseline;border-radius:3px;width:11px;height:11px;margin-right:8px;display:inline-block}.task-box.is-done{border-color:var(--ok);background:var(--ok)}.prose a{color:var(--accent)}.prose code{background:var(--sunken);border:1px solid var(--border);border-radius:5px;padding:1px 5px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.88em}.prose blockquote{border-left:3px solid var(--border);color:var(--muted);margin:0 0 12px;padding:2px 14px}.prose blockquote>:last-child{margin-bottom:0}.prose hr{border:0;border-top:1px solid var(--border);margin:16px 0}.prose img{max-width:100%}.prose table{border-collapse:collapse;margin:0 0 12px;font-size:.95em;display:block;overflow-x:auto}.prose th,.prose td{border:1px solid var(--border);text-align:left;padding:4px 10px}.prose th{background:var(--sunken)}.prose .cell-left{text-align:left}.prose .cell-center{text-align:center}.prose .cell-right{text-align:right}.prose pre{background:var(--sunken);border:1px solid var(--border);border-radius:8px;margin:0 0 12px;padding:12px;overflow-x:auto}.prose pre code{background:0 0;border:0;padding:0}.annotate{z-index:2;border:1px solid var(--border);background:var(--panel);border-radius:8px;align-items:center;gap:2px;height:30px;padding:0 5px;display:flex;position:absolute;box-shadow:0 4px 14px #00000059}.annotate button{width:24px;height:24px;color:var(--muted);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:0;display:inline-flex}.annotate button:hover{background:var(--sel);color:var(--accent)}.annotate .annotate-drop:hover,.annotate button:nth-child(2):hover{color:var(--accent)}.annotate .annotate-close:hover{color:var(--fg)}.annotate-composer{z-index:2;border:1px solid var(--border);background:var(--panel);border-radius:8px;width:240px;padding:8px;position:absolute;box-shadow:0 4px 14px #00000059}.composer-target{color:var(--muted);margin:0 0 6px;font-size:11px;font-style:italic}.annotate-composer textarea{background:var(--bg);width:100%;height:54px;color:var(--fg);border:1px solid var(--border);font:inherit;resize:vertical;border-radius:6px;padding:5px 7px;font-size:12.5px}.composer-acts{justify-content:flex-end;gap:6px;margin-top:6px;display:flex}.composer-add{border:1px solid var(--accent);color:var(--accent);font:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:2px 10px;font-size:11.5px}.composer-add:disabled{border-color:var(--border);color:var(--muted);cursor:default}.composer-cancel{color:var(--muted);font:inherit;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:6px;padding:2px 8px;font-size:11.5px}.composer-cancel:hover{border-color:var(--border);color:var(--fg)}.annotate-whole{color:var(--muted);font:inherit;cursor:pointer;background:0 0;border:none;border-radius:5px;align-items:center;padding:3px;display:inline-flex}.annotate-whole svg{display:block}.annotate-whole:hover,.annotate-whole:focus-visible{color:var(--accent);background:var(--sel)}.queue{margin:0 0 8px;padding:0;list-style:none}.filed{margin:0;padding:0;list-style:none}.rail-awaiting{gap:6px;margin:10px 0 0;padding:0;list-style:none;display:grid}.rail-annotations .filed{margin-top:10px}.filed li{border-bottom:1px solid var(--border);align-items:baseline;gap:6px;padding:3px 0;font-size:11.5px;display:flex}.filed li:last-child{border-bottom:none}.filed-round{flex:none;font-weight:600}.filed-count{color:var(--muted);flex:1}.filed-when{color:var(--muted);flex:none;font-size:10.5px}.queued{border:1px solid var(--border);border-left:3px solid var(--accent);background:var(--bg);border-radius:7px;margin-bottom:7px;padding:7px 9px}.queued.is-remove{border-left-color:var(--warn)}.queued-target{color:var(--muted);margin:0;font-size:11px;font-style:italic}.queued-kind{color:var(--warn);margin:3px 0 0;font-size:11.5px}.queued-text{margin:3px 0 0;font-size:12.5px}.queued-empty{color:var(--muted);margin:3px 0 0;font-size:12.5px;font-style:italic}.queued textarea{background:var(--panel);width:100%;min-height:42px;color:inherit;border:1px solid var(--border);font:inherit;resize:vertical;border-radius:6px;margin-top:4px;padding:5px 7px;font-size:12px}.queued-acts{gap:10px;margin-top:4px;display:flex}.queued-acts button{color:var(--accent);font:inherit;cursor:pointer;background:0 0;border:none;padding:0;font-size:11px}.queued-acts button:disabled{color:var(--muted);cursor:default}.send{background:var(--accent);width:100%;color:var(--bg);font:inherit;cursor:pointer;border:none;border-radius:7px;padding:6px 0;font-size:12px}.send:disabled{background:var(--border);color:var(--muted);cursor:default}.rail-acts{grid-template-columns:1fr 1fr;gap:6px;display:grid}.rail-act{border:1px solid var(--border);color:inherit;font:inherit;cursor:pointer;background:0 0;border-radius:8px;flex-direction:column;justify-content:center;align-items:center;gap:5px;padding:9px 4px 7px;font-size:12px;display:flex}.rail-act:hover{background:var(--sel)}.archive-target{color:var(--fg);word-break:break-all;margin:2px 0 10px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.archive-open{color:var(--muted);margin:4px 0 10px;padding-left:18px;font-size:12.5px}.dialog-shade{z-index:10;background:#00000080;justify-content:center;align-items:center;padding:24px;display:flex;position:fixed;inset:0}.dialog{border:1px solid var(--border);background:var(--panel);border-radius:10px;flex-direction:column;max-width:340px;max-height:100%;padding:0;display:flex;overflow:hidden}.dialog>*{flex-shrink:0}.dialog>.rail-head{border-bottom:1px solid var(--border);margin:0;padding:14px 18px}.dialog-body{flex-shrink:1;min-height:0;padding:14px 18px;overflow-y:auto}.dialog p{margin:0 0 12px}.dialog>.dialog-body>:last-child{margin-bottom:0}.dialog>.notice{margin:0;padding:12px 18px}.dialog-acts{border-top:1px solid var(--border);justify-content:flex-end;gap:10px;padding:14px 18px;display:flex}.dialog-acts button{border:1px solid var(--border);color:inherit;font:inherit;cursor:pointer;background:0 0;border-radius:7px;padding:4px 12px;font-size:12px}.dialog-acts .send{border-color:var(--accent);width:auto}.board-list{margin:0;padding:0;list-style:none}.board-stage{padding:2px 0;font-size:12px}.board-stage-name{color:var(--muted);margin:0}.board-stage.is-running .board-stage-name,.board-stage.is-done .board-stage-name{color:var(--fg)}.board-mark{width:14px;color:var(--muted);display:inline-block}.board-stage.is-running .board-mark{color:var(--accent)}.board-stage.is-done .board-mark{color:var(--ok)}.board-stage-name button{color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;padding:0}.board-stage-name button:hover{color:var(--accent);text-decoration:underline}.board-chevron{color:var(--muted);margin-left:4px;font-size:9px}.board-artifacts{margin:2px 0 4px 20px;padding:0;list-style:none}.board-artifacts button{color:var(--accent);font:inherit;cursor:pointer;text-align:left;background:0 0;border:none;padding:1px 0;font-size:11.5px}.board-now{color:var(--accent);align-items:center;gap:6px;margin:0;font-size:11.5px;display:flex}.board-now .pulse{background:var(--accent);border-radius:50%;flex:none;width:6px;height:6px;animation:1.6s ease-in-out infinite board-pulse}@keyframes board-pulse{50%{opacity:.25}}@media (prefers-reduced-motion:reduce){.board-now .pulse{animation:none}}.form{padding-bottom:40px}.form .lede{color:var(--muted)}.choices{gap:12px;margin:0;padding:0;list-style:none;display:grid}.choices li{border:1px solid var(--border);border-radius:8px;padding:10px 12px}.choices li.is-recommended{border-color:var(--accent)}.choices label{cursor:pointer;align-items:center;gap:8px;display:flex}.choice-title{font-weight:600}.choice-flag{color:var(--accent);text-transform:uppercase;letter-spacing:.06em;margin-left:8px;font-size:10.5px;font-weight:400}.choice-about{color:var(--muted);margin:4px 0 0 22px;font-size:12.5px}.choice-why{margin:4px 0 0 22px;font-size:12.5px}.choice-mode{cursor:pointer;align-items:flex-start;gap:8px;display:flex}.field{margin-bottom:12px;display:block}.field>span{color:var(--muted);margin-bottom:4px;font-size:11.5px;display:block}.field input,.field-dump,.run-with select,.run-with input,.extra select,.extra input{background:var(--bg);color:var(--fg);border:1px solid var(--border);font:inherit;border-radius:6px;padding:5px 8px;font-size:12.5px}.field input,.field-dump{box-sizing:border-box;resize:vertical;border-radius:7px;width:100%;padding:7px 9px;font-size:13px}.field-dump{min-height:140px}.attached{gap:4px;margin:0 0 12px;padding:0;font-size:12px;list-style:none;display:grid}.attached li{justify-content:space-between;gap:8px;display:flex}.attached button{color:var(--muted);font:inherit;cursor:pointer;background:0 0;border:none;font-size:11px}.form-acts{justify-content:flex-end;gap:10px;margin-top:20px;display:flex}.form-acts button{border:1px solid var(--border);color:inherit;font:inherit;cursor:pointer;background:0 0;border-radius:7px;padding:5px 14px;font-size:12.5px}.form-acts .send{border-color:var(--accent);width:auto;color:var(--accent)}.dialog-wide{width:90%;max-width:560px}.doc-and-ask{flex-direction:column;min-width:0;display:flex;overflow-y:auto}.doc-and-ask .doc{flex:1 0 auto;overflow-y:visible}.ask{border:1px solid var(--accent);background:var(--panel);border-radius:10px;width:calc(100% - 80px);max-width:780px;margin:0 auto 40px;padding:16px 20px}.doc>.ask{width:100%;max-width:none;margin:14px 0 28px;scroll-margin-top:12px}.ask-head h2{margin:0;font-size:15px}.ask-about{color:var(--muted);margin:2px 0 10px;font-size:11.5px}.ask-about b{color:var(--fg);font-weight:500}.ask .prose{font-size:inherit}.ask .prose>:last-child{margin-bottom:0}.ask-asks{margin:0 0 12px}.ask-asked{color:var(--muted);margin:12px 0 0;font-size:12px}.form-acts .ask-question{margin-right:auto}.form-acts button:disabled{color:var(--muted);border-color:var(--border);cursor:default}.questions{gap:18px;margin:0 0 14px;padding-left:18px;display:grid}.question-ask{margin:0 0 8px}.question-ask>p:first-child{font-weight:600}.question-said{box-sizing:border-box;background:var(--bg);border:1px solid var(--border);width:100%;min-height:48px;color:inherit;font:inherit;resize:vertical;border-radius:7px;margin-top:8px;padding:6px 8px;font-size:12.5px}.board-review{padding:3px 0;font-size:12px}.board-marks{vertical-align:-1px;gap:6px;margin-left:8px;display:inline-flex}.board-flag{color:var(--muted);cursor:default;display:inline-flex;position:relative}.board-tip{white-space:nowrap;max-width:none;padding:4px 8px}.board-flag.is-waiting{opacity:.45}.board-flag.is-ran{color:var(--fg);opacity:1}.board-flag:hover{color:var(--fg)}.board-log{border-top:1px solid var(--border);margin-top:16px;padding-top:6px}.board-log>.rail-head:first-child{margin-top:6px}.board-under-name{color:var(--muted);margin:4px 0 2px;font-size:12px}.board-nested>.board-under{list-style:none}.board-nested .board-list{border-left:1px solid var(--border);margin-left:10px;padding-left:8px}.run-field{grid-template-columns:92px 1fr;align-items:center;gap:10px;margin:0 0 10px;display:grid}.run-field>span,.run-head{letter-spacing:.08em;text-transform:uppercase;color:var(--muted);font-size:11px}.run-with{align-items:center;gap:8px;display:flex}.run-field .run-with select{min-width:150px;font-size:13px}.run-with input{flex:1;min-width:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.run-phases{flex-direction:column;gap:2px;margin:-4px 0 10px 102px;display:flex}.run-phases label{align-items:center;gap:7px;font-size:12.5px;display:flex}.run-head{margin:16px 0 6px;font-weight:400}.run-banner{border:1px solid var(--border);background:var(--sunken);border-radius:8px;margin:0 0 14px;padding:8px 12px;font-size:12.5px}.run-checkpoint{border:1px solid var(--border);border-radius:8px;margin:6px 0;padding:9px 12px}.run-checkpoint-head{align-items:baseline;gap:8px;font-size:13px;display:flex}.run-why{color:var(--muted);margin:0;font-size:12px}.run-phases label+.run-why,.run-phases .run-stale+.run-why{margin-top:4px}.run-why b{color:var(--fg);font-weight:400}.run-checkpoint .run-why{margin:2px 0 0 24px}.run-panel{flex-wrap:wrap;gap:5px;margin:7px 0 0 24px;display:flex}.run-reviewer{background:var(--sunken);border:1px solid var(--border);border-radius:12px;align-items:flex-start;gap:6px;max-width:100%;padding:2px 9px;font-size:12px;display:inline-flex}.run-focus{color:inherit;font:inherit;text-align:left;cursor:pointer;overflow-wrap:anywhere;background:0 0;border:none;padding:0}.run-focus:hover{color:var(--accent)}.run-new{border:1px dashed var(--border);border-radius:12px;flex:220px;align-items:center;gap:6px;max-width:100%;padding:2px 9px;font-size:12px;display:inline-flex}.run-new input{min-width:10ch;color:inherit;font:inherit;background:0 0;border:none;flex:1;padding:0}.run-new input:focus{color:var(--accent);outline:none}.run-drop,.run-new button{color:var(--muted);cursor:pointer;font:inherit;background:0 0;border:none;align-items:center;gap:4px;padding:0;font-size:12px;display:inline-flex}.run-drop{padding-top:3px}.run-drop:hover,.run-new button:hover{color:var(--fg)}.run-stale{color:var(--warn);margin:6px 0 0;font-size:12px}.field-slug{color:var(--muted);font-size:12px}.field-slug code{background:var(--bg);border:1px solid var(--border);border-radius:4px;padding:0 4px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11.5px}.flavour{align-items:baseline;gap:8px;margin:4px 0;display:flex}.flavour-what{font-size:13px}.flavour-hint{color:var(--muted);margin-top:1px;font-size:12px;display:block}.extras{border-left:2px solid var(--border);flex-direction:column;gap:6px;margin:6px 0 2px 24px;padding-left:10px;display:flex}.extra{grid-template-columns:78px 1fr;align-items:center;gap:8px;display:grid}.extra>span{color:var(--muted);font-size:12px}.extra select{max-width:260px}.extra select,.extra input{padding:4px 8px}.choice-locked{color:var(--muted)}.board-head{justify-content:space-between;align-items:center;gap:8px;display:flex}.board-amend{color:var(--muted);cursor:pointer;background:0 0;border:none;align-items:center;padding:0;display:inline-flex}.board-amend:hover{color:var(--accent)}.ask-offer{align-items:baseline;gap:8px;margin:10px 0 0;font-size:13px;display:flex}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.hm-page{height:100%;padding:14px 16px;font-size:13.5px;position:relative;overflow:hidden auto}.hm-column{min-width:0;max-width:1100px;margin:0 auto}.hm-head{color:var(--muted);flex-wrap:wrap;align-items:center;gap:6px 16px;margin-bottom:14px;font-size:12.5px;display:flex}.hm-repo{color:var(--fg);font-size:16px;font-weight:600}.hm-dot{background:var(--ok);vertical-align:middle;border-radius:50%;width:8px;height:8px;margin-right:5px;display:inline-block}.hm-dot.hm-dirty{background:var(--warn)}.hm-read{align-items:center;gap:8px;margin-left:auto;display:flex}.hm-control{all:unset;box-sizing:border-box;height:24px;font:inherit;color:var(--muted);background:var(--panel);cursor:pointer;border-radius:6px;align-items:center;gap:7px;padding:0 9px;font-size:12.5px;transition:background .12s,color .12s;display:inline-flex}.hm-control:hover,.hm-control:focus-visible{color:var(--fg);background:#1e242d}.hm-control:focus-visible{outline:2px solid var(--accent);outline-offset:1px}.hm-refresh{padding:0 5px}.hm-plain{color:var(--muted);margin:0;padding:20px 0}.hm-failed{color:var(--fg);border-left:3px solid var(--warn);flex-wrap:wrap;align-items:center;gap:6px;margin:0 0 14px;padding:8px 12px;font-size:12.5px;display:flex}.hm-bar{background:var(--panel);border-radius:5px;width:90px;height:10px;display:inline-block}.hm-bar-name{width:120px;height:14px}@media (prefers-reduced-motion:no-preference){.hm-bar{animation:1.6s ease-in-out infinite hmBreathe}@keyframes hmBreathe{0%,to{opacity:1}50%{opacity:.55}}}.hm-card{background:var(--panel);border:1px solid var(--border);border-radius:8px;min-width:0;margin-bottom:12px;padding:12px 14px}.hm-card h3{text-transform:uppercase;letter-spacing:.06em;color:var(--muted);align-items:baseline;gap:8px;margin:0 0 8px;font-size:11.5px;font-weight:600;display:flex}.hm-card h3 small{text-transform:none;letter-spacing:0;font-weight:400}.hm-grid{grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr));gap:12px;display:grid}.hm-grid .hm-card{margin-bottom:12px}.hm-tiles{grid-template-columns:repeat(auto-fit,minmax(min(100%,180px),1fr));gap:12px;display:grid}.hm-big{font-variant-numeric:tabular-nums;font-size:24px;font-weight:600;line-height:1.15}.hm-lines{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:20px}.hm-lines .hm-added{color:#7bb992;white-space:nowrap}.hm-lines .hm-deleted{color:#c78b8b;white-space:nowrap}.hm-lines .hm-slash{color:var(--muted)}.hm-span{color:var(--muted);font-size:14px;font-weight:400}.hm-sub{color:var(--muted);font-size:12px}.hm-up{color:var(--ok)}.hm-muted{color:var(--muted)}.hm-cut{color:var(--muted);margin:10px 0 0;font-size:12px}.hm-loader{background:linear-gradient(90deg,#1b2230 25%,#232b38 37%,#1b2230 63%) 0 0/400% 100%;border-radius:6px}@media (prefers-reduced-motion:no-preference){.hm-loader{animation:1.4s infinite hmShimmer}@keyframes hmShimmer{0%{background-position:100% 0}to{background-position:0 0}}}.hm-notice{color:var(--fg);margin:0;font-size:12.5px}.hm-tip{opacity:0;white-space:nowrap;background:#1b2230;max-width:none;padding:4px 8px;transition:opacity .12s}.hm-tip.hm-tip-on{opacity:1}.hm-scroll{scrollbar-width:thin;padding-bottom:4px;overflow:auto hidden}.hm-garden-wrap{position:relative}.hm-garden-wrap.hm-more:before{content:"";background:linear-gradient(90deg, var(--panel), transparent);z-index:2;pointer-events:none;width:64px;position:absolute;top:0;bottom:22px;left:0}.hm-earlier{z-index:3;color:var(--muted);background:var(--panel);border-radius:6px;align-items:center;gap:6px;padding:2px 6px;font-size:11.5px;display:flex;position:absolute;top:8px;left:8px}@media (prefers-reduced-motion:no-preference){.hm-earlier i{animation:1.6s ease-in-out infinite hmNudge;display:inline-block}@keyframes hmNudge{50%{transform:translate(-4px)}}}.hm-garden{background:linear-gradient(#0000 78%,#12281a 100%);border-radius:6px 6px 0 0;min-width:max-content;display:block}.hm-stem{stroke:#2f7a3e;stroke-width:2px;fill:none}.hm-leaf{fill:#26a641}.hm-bud{fill:#39d353}.hm-flower{fill:#a371f7}.hm-flower.hm-shade-1{fill:#b168e2}.hm-flower.hm-shade-2{fill:#c060c9}.hm-flower.hm-shade-3{fill:#c95aa5}.hm-flower.hm-shade-4{fill:#d55181}@media (prefers-reduced-motion:no-preference){.hm-plant.hm-sway{animation:3.2s ease-in-out infinite alternate hmSway}@keyframes hmSway{0%{transform:rotate(-2deg)}to{transform:rotate(2deg)}}}.hm-axis{border-top:1px solid var(--border);min-width:max-content;height:22px;color:var(--muted);font-size:11px;position:relative}.hm-axis span{white-space:nowrap;position:absolute;top:3px}.hm-axis span:before{content:"";border-left:1px solid var(--border);height:5px;position:absolute;top:-4px;left:0}.hm-axis span.hm-year{color:var(--fg);font-weight:600;top:11px}.hm-legend{color:var(--muted);flex-wrap:wrap;align-items:center;gap:16px;margin-top:8px;font-size:12px;display:flex}.hm-legend b{color:var(--fg)}.hm-info{all:unset;box-sizing:border-box;width:14px;height:14px;color:var(--muted);vertical-align:-2px;cursor:default;justify-content:center;align-items:center;margin-left:5px;display:inline-flex}.hm-info:hover,.hm-info:focus-visible{color:var(--fg)}.hm-infotip{width:280px}.hm-key{vertical-align:middle;border-radius:50%;width:8px;height:8px;margin-right:5px;display:inline-block}.hm-bud-key{background:#39d353}.hm-flower-key{background:#a371f7}.hm-big-key{background:#d55181}.hm-lines-key{background:var(--ok)}.hm-files-key{background:var(--accent)}.hm-counting{align-items:center;display:inline-flex}.hm-switch-track{background:var(--border);border-radius:999px;width:26px;height:14px;transition:background .12s;display:inline-block;position:relative}.hm-switch-track i{background:var(--muted);border-radius:50%;width:10px;height:10px;transition:left .12s,background .12s;position:absolute;top:2px;left:2px}.hm-switch:hover .hm-switch-track i,.hm-switch:focus-visible .hm-switch-track i{background:var(--fg)}.hm-switch[aria-checked=true] .hm-switch-track{background:var(--ok)}.hm-switch[aria-checked=true] .hm-switch-track i{background:var(--panel);left:14px}.hm-counting-tip{width:340px}.hm-counting-tip p{color:var(--muted);margin:6px 0 0}.hm-read-tip{width:max-content;max-width:220px}.hm-read-tip p{color:var(--muted);margin:5px 0 0}.hm-left-out{opacity:.85;margin-top:4px}.hm-bars{align-items:flex-end;gap:3px;height:64px;display:flex}.hm-bars.hm-bars-wide{gap:8px}.hm-bars i{background:#006d32;border-radius:3px 3px 0 0;flex:1;min-width:3px}.hm-bars i.hm-tall{background:#39d353}.hm-bars i:hover{background:var(--accent)}.hm-axis-x{color:var(--muted);justify-content:space-between;margin-top:4px;font-size:11px;display:flex}.hm-growth-card{flex-direction:column;display:flex}.hm-growth-card .hm-growth{flex-direction:column;flex:1;display:flex}.hm-growth-plot{flex:auto;width:100%;height:0;min-height:260px;display:block;overflow:visible}.hm-growth-lines,.hm-growth-files{fill:none;stroke-width:2px;stroke-linecap:round;stroke-linejoin:round}.hm-growth-lines{stroke:var(--ok)}.hm-growth-files{stroke:var(--accent)}.hm-growth-band{fill:#0000}.hm-growth-band:hover{fill:#ffffff0a}.hm-growth-axis{border-top:1px solid var(--border);color:var(--muted);justify-content:space-between;padding-top:3px;font-size:11px;display:flex}.hm-growth-keys{flex-wrap:wrap;align-items:center;gap:14px;margin-top:8px;display:flex}.hm-hbar{grid-template-columns:78px 1fr 44px;align-items:center;gap:8px;margin:5px 0;font-size:12px;display:grid}.hm-key-name{color:var(--muted);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.hm-track{background:var(--sunken);border-radius:4px;height:8px;overflow:hidden}.hm-track i{border-radius:0 4px 4px 0;height:100%;display:block}.hm-value{text-align:right;color:var(--muted);font-variant-numeric:tabular-nums}.hm-areas .hm-hbar{grid-template-columns:minmax(64px,120px) 1fr auto 44px}.hm-shift{text-align:right;color:var(--muted);font-variant-numeric:tabular-nums}.hm-list{max-height:260px;font-size:12.5px;overflow-y:auto}.hm-branches-card{flex-direction:column;display:flex}.hm-branches-card .hm-list{flex:auto;height:0;min-height:260px;max-height:none}.hm-list>div{border-bottom:1px dashed #21262d;grid-template-columns:1fr auto auto auto;align-items:center;gap:10px;padding:5px 0;display:grid}.hm-list>div:last-child{border-bottom:0}.hm-name{text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;overflow:hidden}.hm-flag{color:var(--muted);white-space:nowrap;background:#1f2937;border-radius:9px;padding:1px 7px;font-size:11px}.hm-flag.hm-merged,.hm-flag.hm-squash{color:var(--ok);background:#3fb95026}.hm-flag.hm-stale{color:var(--warn);background:#d2992226}.hm-flag.hm-current{color:var(--accent);background:#58a6ff26}.hm-pop{position:relative}.hm-del{color:var(--muted);cursor:pointer;background:0 0;border:0;padding:2px 4px;line-height:0}.hm-del:hover{color:var(--fg)}.hm-popover{z-index:5;background:var(--panel);border:1px solid var(--border);white-space:normal;border-radius:8px;width:min(420px,88vw);padding:10px 12px;font-size:12.5px;position:absolute;top:26px;right:0;box-shadow:0 8px 28px #00000080}.hm-popover p{color:var(--muted);margin:0 0 6px}.hm-warn-text{color:var(--warn)}.hm-cmd{align-items:center;gap:8px;display:flex}.hm-cmd input{background:var(--sunken);color:var(--fg);border:1px solid var(--border);border-radius:6px;flex:1;min-width:0;padding:6px 8px;font:12px ui-monospace,SFMono-Regular,Menlo,monospace}.hm-hint{color:var(--muted);white-space:nowrap;font-size:11px}.hm-bee{z-index:8;appearance:none;aspect-ratio:110/88;cursor:pointer;will-change:transform;visibility:hidden;background:0 0;border:0;width:110px;padding:0;position:fixed;top:0;left:0}.hm-bee.hm-here{visibility:visible}.hm-bee.hm-small{width:37px}.hm-bee img{object-fit:contain;pointer-events:none;width:100%;height:100%;display:block}.hm-page.hm-still .hm-head{padding-right:76px}.hm-bee.hm-parked{width:64px;height:52px;position:absolute;top:4px;left:auto;right:12px;transform:none}.hm-bubble{z-index:9;background:var(--fg);color:#0d1117;opacity:0;pointer-events:none;border-radius:10px;max-width:280px;padding:10px 12px;font-size:12.5px;line-height:1.4;transition:opacity 1s linear,transform 1s;position:fixed;transform:translateY(6px);box-shadow:0 8px 28px #00000080}.hm-page.hm-still .hm-bubble{top:64px;left:auto;right:12px}.hm-who{color:#4b5563;margin-top:4px;display:block}.hm-bubble.hm-said{opacity:1;pointer-events:auto;transition:opacity .2s,transform .2s;transform:translateY(0)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{A as e,C as t,D as n,E as r,O as i,c as a,i as o,k as s,n as c,r as l,s as u,t as d,y as f}from"./api-CguEsvNp.js";import{t as p}from"./useNow-Ww-Gffnk.js";var m=e(),h=i(),g=/^[A-Za-z0-9._/-]+$/;function _(e){return g.test(e)?e:`'${e.replace(/'/g,`'\\''`)}'`}function v(e){return e===`merged`||e===`squash`||e===`stale`}function y(e,t){return`git branch ${t===`merged`?`-d`:`-D`} -- ${_(e)}`}var b=[`Jan`,`Feb`,`Mar`,`Apr`,`May`,`Jun`,`Jul`,`Aug`,`Sep`,`Oct`,`Nov`,`Dec`];function x(e){return e.toLocaleString(`en-GB`)}function S(e,t){return`${x(e)} ${t}${e===1?``:`s`}`}function C(e){let t=/^(\d{4})-(\d{2})-(\d{2})$/.exec(e);if(t===null)return null;let n=Number(t[2])-1;return n<0||n>11?null:{year:t[1]??``,month:n,date:Number(t[3])}}function w(e){if(e===null)return``;let t=C(e.slice(0,10));return t===null?``:`${t.date} ${b[t.month]} ${t.year}`}function T(e){let t=C(e.slice(0,10));return t===null?``:`${t.date} ${b[t.month]}`}function ee(e,t){let n=C(e.slice(0,10)),r=C(t.slice(0,10));return n===null||r===null?``:n.year===r.year&&n.month===r.month?`${n.date}-${r.date} ${b[n.month]}`:`${T(e)} - ${T(t)}`}function te(e){return e===0?`working tree clean`:`${S(e,`uncommitted change`)}`}function ne(e,t){return`+${x(e)} / -${x(t)}`}var E=n();function re(e,t){switch(e){case`current`:return`current`;case`default`:return`default`;case`merged`:return`merged`;case`squash`:return`merged (squash)`;case`stale`:return`stale`;default:return`ahead of ${t}`}}function ie(e){let t=e.filter(e=>e.state===`merged`||e.state===`squash`).length,n=e.filter(e=>e.state===`stale`).length;return`${x(e.length)} local · ${x(t)} merged, ${x(n)} stale`}function ae(e,t){return e===`stale`?{said:`This branch holds work that is not on ${t}. The command deletes it anyway.`,warn:!0}:e===`squash`?{said:`Squash-merged into ${t}. git cannot see a squash merge, so the force flag is needed. Home checked that the whole change is on ${t}.`,warn:!1}:{said:`Merged into ${t}, so the safe delete works.`,warn:!1}}function oe(e){let t=e.default??`the default branch`,[n,i]=(0,m.useState)(null),a=(0,m.useRef)(null);return(0,m.useEffect)(()=>{if(n===null)return;let e=e=>{a.current?.contains(e.target)!==!0&&i(null)};return document.addEventListener(`click`,e),()=>document.removeEventListener(`click`,e)},[n]),(0,E.jsx)(`div`,{className:`hm-list`,children:e.branches.map(o=>{let s=o.ahead>0?` · ${S(o.ahead,`commit`)} ahead of ${t}`:``;return(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`span`,{className:`hm-name`,title:`${o.name}${s}`,children:o.name}),(0,E.jsx)(`span`,{className:`hm-muted`,children:u(o.lastCommit,e.now)}),(0,E.jsx)(`span`,{className:`hm-flag hm-${o.state}`,children:re(o.state,t)}),(0,E.jsx)(`span`,{className:`hm-pop`,children:v(o.state)&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(`button`,{type:`button`,className:`hm-del`,title:`Delete this branch`,onClick:e=>{e.stopPropagation(),i(n===o.name?null:o.name)},children:(0,E.jsx)(r,{size:14})}),n===o.name&&(0,E.jsx)(se,{branch:o,into:t,held:a})]})})]},o.name)})})}function se(e){let t=ae(e.branch.state,e.into),n=y(e.branch.name,e.branch.state);return(0,E.jsxs)(`div`,{className:`hm-popover`,ref:e.held,children:[(0,E.jsxs)(`p`,{children:[(0,E.jsx)(`span`,{className:t.warn?`hm-warn-text`:void 0,children:t.said}),` Deletes the local branch alone: a remote branch of the same name is not touched.`]}),(0,E.jsxs)(`div`,{className:`hm-cmd`,children:[(0,E.jsx)(`input`,{readOnly:!0,value:n,"aria-label":`The command that deletes this branch`,onClick:e=>e.currentTarget.select()}),(0,E.jsx)(`span`,{className:`hm-hint`,children:`click selects · copy with the keyboard`})]})]})}function D(e){let{title:t,note:n,state:r,said:i,loaderHeight:a=120}=e;return(0,E.jsxs)(`section`,{className:e.className===void 0?`hm-card`:`hm-card ${e.className}`,children:[t!==void 0&&(0,E.jsxs)(`h3`,{children:[t,r===`read`&&n!==void 0&&(0,E.jsx)(`small`,{children:n})]}),r===`loading`?(0,E.jsx)(`div`,{className:`hm-loader`,style:{height:`${a}px`}}):r===`failed`?(0,E.jsxs)(`p`,{className:`hm-notice`,children:[(0,E.jsx)(`span`,{children:i}),` `,(0,E.jsx)(`span`,{className:`hm-muted`,children:`Read the repository again to try.`})]}):e.children]})}var ce=``+new URL(`bee-B7t97l5B.webp`,import.meta.url).href,le=``+new URL(`buzz-CUUsbnXH.mp3`,import.meta.url).href,ue=``+new URL(`pop-D5ZANBC3.mp3`,import.meta.url).href,O=[{said:`Simplicity is prerequisite for reliability.`,who:`Edsger W. Dijkstra, EWD498, 1975`},{said:`Any organization that designs a system will produce a design whose structure is a copy of the organization's communication structure.`,who:`Melvin Conway, How Do Committees Invent?, 1967`},{said:`Perfection is attained not when there is nothing more to add, but when there is nothing left to take away.`,who:`Antoine de Saint-Exupéry, Terre des Hommes, 1939`},{said:`Have nothing in your houses that you do not know to be useful, or believe to be beautiful.`,who:`William Morris, The Beauty of Life, 1880`}],de=640,fe=[270,330],pe=[30,60],me=[.15,.75],he=[60,120],ge=[95,125],_e=16,ve=[14,32],ye=[2.2,3.4],be=.6,xe=.25,Se=.05;function k(e,t){return e+Math.random()*(t-e)}function A(){return{width:window.innerWidth,height:window.innerHeight}}var Ce={scale:1,quick:1,gap:fe,talks:!0},j={scale:1/3,quick:3,gap:he,talks:!1};function M(e,t){return Math.round(110*Math.min(1,t.width/de)*e.scale)}function we(e,t){let n=t.height*me[0]+e,r=t.height*me[1]-e;if(r>n)return[n,r];let i=(n+r)/2;return[i,i]}function Te(){return window.matchMedia?.(`(prefers-reduced-motion: reduce)`).matches===!0}function Ee(e,t){return{x:0,y:0,base:0,amplitude:0,period:3,t:0,direction:1,speed:110,tilt:0,away:t,flying:!1,clicks:0,dart:null,drawn:0,kind:e}}function De(e,t){let n=M(e.kind,t),r=Math.random()*Math.PI-Math.PI/2,[i,a]=we(e.amplitude,t),o=Math.max(0,Math.min(t.width-n,e.x-e.direction*Math.cos(r)*n));o=e.direction>0?Math.min(o,e.x):Math.max(o,e.x);let s=Math.max(i,Math.min(a,e.base+Math.sin(r)*n));e.dart={fromX:e.x,fromY:e.y,toX:o,toY:s,t:0}}function N(e){let t=(0,m.useRef)(null),n=(0,m.useRef)(null),r=(0,m.useRef)(null),[i]=(0,m.useState)(Te),[a,o]=(0,m.useState)(null),s=(0,m.useRef)(e.sound);s.current=e.sound;let c=(0,m.useRef)(0),[l]=(0,m.useState)(()=>Math.floor(Math.random()*O.length)),u=(0,m.useRef)(null),[d]=(0,m.useState)(()=>Ee(Ce,k(pe[0],pe[1]))),[f]=(0,m.useState)(()=>Ee(j,k(j.gap[0],j.gap[1]))),p=(0,m.useRef)(()=>{}),h=(0,m.useCallback)(()=>{o({quote:(l+c.current)%O.length,shown:!0}),c.current+=1,u.current={left:6,hovered:!1,fading:0},p.current()},[l]),g=(0,m.useCallback)(e=>{if(s.current)try{let t=new Audio(e);t.volume=.7,t.play().catch(e=>{console.warn(`[home] the bee could not play its clip:`,e)})}catch(e){console.warn(`[home] the bee could not play its clip:`,e)}},[]),_=(0,m.useCallback)(e=>{if(!(e.kind.talks&&u.current!==null)){if(i){g(ue),h();return}if(e.flying){if(e.kind.talks&&(e.clicks+=1,e.clicks>=3)){g(ue),h();return}g(le),De(e,A())}}},[g,h,i]),v=(0,m.useCallback)(()=>{let e=u.current;e!==null&&(e.hovered=!0)},[]),y=(0,m.useCallback)(()=>{let e=u.current;e!==null&&(e.hovered=!1,e.left=Math.max(e.left,1))},[]);(0,m.useEffect)(()=>{let e=t.current;if(e===null)return;i&&(e.style.width=`${M(Ce,A())}px`,e.classList.add(`hm-parked`,`hm-here`));let a=0,s=0,c=(e,t,n)=>{let r=M(e.kind,n.view);if(r!==e.drawn&&(e.drawn=r,t.style.width=`${r}px`),e.flying){let i=e.kind.talks&&u.current!==null;if(e.dart!==null){let t=e.dart;t.t+=n.flown;let r=Math.min(1,t.t/xe),i=1-(1-r)**3;e.x=t.fromX+(t.toX-t.fromX)*i,e.y=t.fromY+(t.toY-t.fromY)*i,r>=1&&(e.base=t.toY,e.dart=null,e.t=0)}else if(!(i&&u.current?.hovered===!0)){let t=i?_e:e.speed;e.t+=n.flown,e.x+=e.direction*t*n.flown;let r=e.t/e.period*2*Math.PI;e.y=e.base+Math.sin(r)*e.amplitude;let a=Math.cos(r)*e.amplitude*2*Math.PI/e.period;e.tilt=Math.atan2(a,t)*180/Math.PI*be}(e.x<-r*1.5||e.x>n.view.width+r*.5)&&!i&&(e.flying=!1,e.away=k(e.kind.gap[0],e.kind.gap[1]),t.classList.remove(`hm-here`))}else{if(e.away-=n.waited,e.away>0)return;e.direction=Math.random()<.5?1:-1,e.x=e.direction>0?-r:n.view.width,e.amplitude=k(ve[0],ve[1]);let[i,a]=we(e.amplitude,n.view);e.base=k(i,a),e.y=e.base,e.tilt=0,e.period=k(ye[0],ye[1]),e.speed=k(ge[0],ge[1])*e.kind.quick,e.t=0,e.clicks=0,e.dart=null,e.flying=!0,t.classList.add(`hm-here`)}t.style.transform=`translate(${e.x}px, ${e.y}px) scaleX(${e.direction}) rotate(${e.direction*e.tilt}deg)`},l=e=>{let t=u.current;if(t!==null){if(t.fading>0){t.fading-=e,t.fading<=0&&(u.current=null,d.clicks=0,o(null));return}t.hovered||(t.left-=e),t.left<=0&&(t.fading=1,o(e=>e===null?null:{...e,shown:!1}))}},m=t=>{let o=(t-s)/1e3;s=t;let p={waited:o,flown:Math.min(Se,o),view:A()};if(!i){c(d,e,p),n.current!==null&&c(f,n.current,p);let t=r.current;t!==null&&u.current!==null&&(t.style.left=`${Math.min(Math.max(8,d.x-110),p.view.width-300)}px`,t.style.top=`${Math.max(8,d.y-92)}px`)}if(l(p.flown),i&&u.current===null){a=0;return}a=requestAnimationFrame(m)},h=()=>{a===0&&(s=performance.now(),a=requestAnimationFrame(m))};return p.current=h,i||h(),()=>{cancelAnimationFrame(a),a=0,p.current=()=>{}}},[i,d,f]);let b=a===null?null:O[a.quote];return(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(`button`,{type:`button`,className:`hm-bee`,ref:t,"aria-label":`The bee`,title:`A quote`,onClick:()=>_(d),children:(0,E.jsx)(`img`,{src:ce,alt:``})}),!i&&(0,E.jsx)(`button`,{type:`button`,className:`hm-bee hm-small`,ref:n,"aria-label":`A small bee`,onClick:()=>_(f),children:(0,E.jsx)(`img`,{src:``+new URL(`bee-B7t97l5B.webp`,import.meta.url).href,alt:``})}),(0,E.jsx)(`div`,{className:a?.shown===!0?`hm-bubble hm-said`:`hm-bubble`,ref:r,onMouseEnter:v,onMouseLeave:y,children:b!=null&&(0,E.jsxs)(E.Fragment,{children:[b.said,(0,E.jsxs)(`span`,{className:`hm-who`,children:[`- `,b.who]})]})})]})}var Oe=`counting-exceptions`;function ke(e){return e.length===0?``:e.join(` and `)}function Ae(e){let t=o({className:`hm-infotip hm-counting-tip`,side:`bottom`});if(e.toolPaths.length===0)return null;let n=e.counting===`all`,r=ke(e.toolPaths),i=(0,E.jsxs)(E.Fragment,{children:[(0,E.jsxs)(`b`,{children:[`Off, every count of lines and of files on this page leaves out `,r,`.`]}),(0,E.jsx)(`p`,{children:`That is the height of each plant, the lines since Monday, the tree and the growth card.`}),(0,E.jsx)(`p`,{children:`It never changes a count of commits - the total above, the active days, both rhythm cards, the longest streak and the biggest day - nor the uncommitted changes, which are what git status says, nor the branches card, nor the ignored size.`})]});return(0,E.jsxs)(`span`,{className:`hm-counting`,children:[(0,E.jsxs)(`button`,{type:`button`,className:`hm-control hm-switch`,role:`switch`,"aria-checked":n,"aria-describedby":Oe,onClick:()=>e.onChange(n?`work`:`all`),...t.anchor,children:[(0,E.jsx)(`span`,{className:`hm-switch-track`,"aria-hidden":`true`,children:(0,E.jsx)(`i`,{})}),`count chamba files`,t.says(i)]}),(0,E.jsxs)(`span`,{className:`visually-hidden`,id:Oe,children:[`Off, every count of lines and of files on this page leaves out `,r,`. It never changes a count of commits, the uncommitted changes, the branches card or the ignored size.`]})]})}function P(e,t){return t===`all`?e.all:e.work}var je=1e4,F=10,I=170,Me=10,Ne=128,L=12,Pe=60,R=500,z=2e3,B=`Its height follows the lines changed that day, added plus deleted, on a square-root scale so a huge day does not flatten the rest.`,V=`plant-height`,Fe=5,Ie=.7;function Le(e,t){return P(e.added,t)+P(e.deleted,t)}function Re(e){let t=2166136261;for(let n=0;n<e.length;n++)t^=e.charCodeAt(n),t=Math.imul(t,16777619);return(t>>>0)%1e4/1e4}function ze(e,t){let n=Math.min(Math.max((t-R)/(z-R),0),1),r=Math.min(Math.max(n+(Re(e)-.5)*Ie,0),1);return Math.round(r*(Fe-1))}function H(e){let[t=0,n=1,r=1]=e.split(`-`).map(Number);return Date.UTC(t,n-1,r)}function U(e,t){return Math.round((H(t)-H(e))/864e5)}function Be(e,t,n){if(n<=0)return[0,0];let r=t-Pe,i=t+n+Pe,a=0;for(;a<e.length&&(e[a]??0)<r;)a+=1;let o=a;for(;o<e.length&&(e[o]??0)<=i;)o+=1;return[a,o]}function Ve(e,t){let n=[],r=``,i=``;for(let a=0;a<t;a+=1){let t=new Date(H(e)+a*864e5).toISOString().slice(0,10),o=L+a*F;t.slice(0,4)!==i&&(i=t.slice(0,4),n.push({x:o,said:i,year:!0})),t.slice(0,7)!==r&&(r=t.slice(0,7),n.push({x:o,said:T(t).split(` `)[1]??``,year:!1}))}return n}function He(e){let{at:t,lines:n}=e,r=Me+Math.sqrt(n)/e.tallest*Ne,i=I-r,a=e.index%2==0?-3:3,o=I-r*.55;return(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(`path`,{className:`hm-stem`,d:`M${t},${I} q${a},${-r/2} 0,${-r}`}),(0,E.jsx)(`ellipse`,{className:`hm-leaf`,cx:t-4,cy:o,rx:4,ry:2,transform:`rotate(-25 ${t-4} ${o})`}),n>=R?(0,E.jsx)(`circle`,{className:`hm-flower hm-shade-${ze(e.date,n)}`,cx:t,cy:i,r:n>=z?5.5:3.5}):(0,E.jsx)(`circle`,{className:`hm-bud`,cx:t,cy:i,r:2})]})}function Ue(e){let{days:t,today:n,counting:r}=e,i=o({className:`hm-infotip`,side:`top`}),a=(0,m.useRef)(null),s=(0,m.useRef)(null),c=(0,m.useRef)([]),l=(0,m.useRef)([0,0]),[u,d]=(0,m.useState)(!1),p=t[0]?.date??n,h=t[t.length-1]?.date??n,g=Math.max(1,U(p,h>n?h:n)+1),_=g*F+L*2,v=Math.sqrt(Math.max(1,...t.map(e=>Le(e,r)))),y=(0,m.useMemo)(()=>t.filter(e=>e.commits>0).map(e=>({day:e,x:L+U(p,e.date)*F})),[t,p]),b=(0,m.useCallback)(()=>{let e=a.current,t=s.current;if(e===null||t===null)return;let n=t.querySelectorAll(`g.hm-plant`),[r,i]=Be(c.current,e.scrollLeft,e.clientWidth),[o,u]=l.current;for(let e=o;e<u;e+=1)(e<r||e>=i)&&n[e]?.classList.remove(`hm-sway`);for(let e=r;e<i;e+=1)n[e]?.classList.add(`hm-sway`);l.current=[r,i],d(e.scrollLeft>4)},[]);return(0,m.useEffect)(()=>{let e=a.current;if(e===null)return;c.current=y.map(e=>e.x),l.current=[0,0],e.scrollLeft=e.scrollWidth,b();let t=new ResizeObserver(b);return t.observe(e),()=>t.disconnect()},[b,y]),(0,E.jsxs)(E.Fragment,{children:[(0,E.jsxs)(`div`,{className:u?`hm-garden-wrap hm-more`:`hm-garden-wrap`,children:[u&&(0,E.jsxs)(`div`,{className:`hm-earlier`,children:[(0,E.jsx)(`i`,{children:`‹`}),` earlier`]}),(0,E.jsxs)(`div`,{className:`hm-scroll`,ref:a,onScroll:b,"data-testid":`garden-scroll`,children:[(0,E.jsx)(`svg`,{className:`hm-garden`,ref:s,width:_,height:I,role:`img`,"aria-label":`One plant for each day worked on since ${w(p)}`,children:y.map(({day:t,x:n},i)=>(0,E.jsx)(`g`,{className:`hm-plant`,"data-day":t.date,style:{transformOrigin:`${n}px ${I}px`,animationDelay:`${i%7*-.4}s`},...e.hover(`${w(t.date)} · ${ne(P(t.added,r),P(t.deleted,r))} · ${S(t.commits,`commit`)}`),children:(0,E.jsx)(He,{at:n,index:i,date:t.date,lines:Le(t,r),tallest:v})},t.date))}),(0,E.jsx)(`div`,{className:`hm-axis`,style:{width:`${_}px`},children:Ve(p,g).map(e=>(0,E.jsx)(`span`,{className:e.year?`hm-year`:void 0,style:{left:`${e.x}px`},children:e.said},`${e.said}-${e.x}`))})]})]}),(0,E.jsxs)(`div`,{className:`hm-legend`,children:[(0,E.jsxs)(`span`,{children:[(0,E.jsx)(`b`,{children:`Each plant is one day`}),(0,E.jsxs)(`button`,{type:`button`,className:`hm-info`,"aria-label":`What a plant's height means`,"aria-describedby":V,...i.anchor,children:[(0,E.jsx)(f,{size:13}),(0,E.jsx)(`span`,{className:`visually-hidden`,id:V,children:B}),i.says(B)]})]}),(0,E.jsxs)(`span`,{children:[(0,E.jsx)(`i`,{className:`hm-key hm-bud-key`}),`a bud: a day with a change`]}),(0,E.jsxs)(`span`,{children:[(0,E.jsx)(`i`,{className:`hm-key hm-flower-key`}),`a flower: a day of 500 lines or more`]}),(0,E.jsxs)(`span`,{children:[(0,E.jsx)(`i`,{className:`hm-key hm-big-key`}),`a big flower: a day of 2,000 or more`]})]})]})}var W=100,G=100,We=.92;function Ge(e){let t=e[e.length-1];if(t===void 0)return null;let n=Math.max(1,...e),r=e.length===1?0:W/(e.length-1);return{line:e.map((t,i)=>{let a=e.length===1?W/2:i*r,o=G-t/n*G*We;return`${K(a)},${K(o)}`}).join(` `),last:t}}function K(e){return Math.round(e*100)/100}function Ke(e){let{points:t}=e.growth,n=Ge(t.map(t=>P(t.files,e.counting))),r=Ge(t.map(t=>P(t.lines,e.counting)));if(n===null||r===null)return(0,E.jsx)(`p`,{className:`hm-sub`,children:`Counting the history. The line fills in as the points land.`});let i=t[0],a=t[t.length-1],o=t.length===1?W:W/(t.length-1);return(0,E.jsxs)(`div`,{className:`hm-growth`,children:[(0,E.jsxs)(`svg`,{className:`hm-growth-plot`,viewBox:`0 0 ${W} ${G}`,preserveAspectRatio:`none`,role:`img`,"aria-label":`${S(n.last,`tracked file`)} and ${x(r.last)} tracked lines, from ${w(i?.date??null)} to ${w(a?.date??null)}`,children:[(0,E.jsx)(`polyline`,{className:`hm-growth-lines`,points:r.line,vectorEffect:`non-scaling-stroke`}),(0,E.jsx)(`polyline`,{className:`hm-growth-files`,points:n.line,vectorEffect:`non-scaling-stroke`}),t.map((n,r)=>(0,E.jsx)(`rect`,{className:`hm-growth-band`,x:K(Math.max(0,r*o-o/2)),y:0,width:K(r===0||r===t.length-1?o/2:o),height:G,...e.hover(`${w(n.date)} · ${S(P(n.files,e.counting),`file`)} · ${x(P(n.lines,e.counting))} lines`)},n.date))]}),(0,E.jsxs)(`div`,{className:`hm-growth-axis`,children:[(0,E.jsx)(`span`,{children:w(i?.date??null)}),(0,E.jsx)(`span`,{children:w(a?.date??null)})]}),(0,E.jsxs)(`div`,{className:`hm-sub hm-growth-keys`,children:[(0,E.jsxs)(`span`,{children:[(0,E.jsx)(`i`,{className:`hm-key hm-lines-key`}),x(r.last),` lines`]}),(0,E.jsxs)(`span`,{children:[(0,E.jsx)(`i`,{className:`hm-key hm-files-key`}),S(n.last,`file`)]}),e.growth.counted<e.growth.of&&(0,E.jsxs)(`span`,{className:`hm-muted`,children:[`counted at `,e.growth.counted,` of `,e.growth.of,` points so far`]})]})]})}function qe(e){let{repository:t,onTop:n,readAt:r,now:i}=e,a=(0,E.jsx)(Je,{readAt:r,now:i,onRefresh:e.onRefresh,toolPaths:e.toolPaths,counting:e.counting,onCounting:e.onCounting});return t===null?(0,E.jsxs)(`div`,{className:`hm-head`,children:[(0,E.jsx)(`span`,{className:`hm-bar hm-bar-name`}),(0,E.jsx)(`span`,{className:`hm-bar`}),(0,E.jsx)(`span`,{className:`hm-bar`}),a]}):(0,E.jsxs)(`div`,{className:`hm-head`,children:[(0,E.jsx)(`span`,{className:`hm-repo`,children:t.name}),(0,E.jsxs)(`span`,{children:[(0,E.jsx)(`span`,{className:t.changedFiles>0?`hm-dot hm-dirty`:`hm-dot`}),t.detached?`${t.branch}, detached`:t.branch,` ·`,` `,te(t.changedFiles)]}),t.commits>0&&(0,E.jsxs)(E.Fragment,{children:[n===null?(0,E.jsx)(`span`,{children:S(t.commits,`commit`)}):(0,E.jsxs)(`span`,{children:[S(n.count,`commit`),` on top of `,n.base,` · `,x(t.commits),` `,`in total`]}),t.firstCommit!==null&&(0,E.jsxs)(`span`,{children:[`since `,w(t.firstCommit),t.shallow&&(0,E.jsx)(`span`,{className:`hm-muted`,children:` (shallow)`})]}),t.lastCommit!==null&&(0,E.jsxs)(`span`,{children:[`last commit `,u(t.lastCommit,i)]})]}),a]})}function Je(e){return(0,E.jsxs)(`span`,{className:`hm-read`,children:[(0,E.jsx)(Ae,{toolPaths:e.toolPaths,counting:e.counting,onChange:e.onCounting}),(0,E.jsx)(Ye,{readAt:e.readAt,now:e.now,onRefresh:e.onRefresh})]})}function Ye(e){let n=o({className:`hm-infotip hm-read-tip`,side:`bottom`}),r=e.readAt===null?null:u(e.readAt.toISOString(),e.now);return(0,E.jsxs)(`button`,{type:`button`,className:`hm-control hm-refresh`,"aria-label":r===null?`Refresh`:`Refresh, read ${r}`,onClick:e.onRefresh,...n.anchor,children:[(0,E.jsx)(t,{size:14}),n.says((0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(`b`,{children:`Read the repository again`}),r!==null&&(0,E.jsxs)(`p`,{children:[`Read `,r,`.`]})]}))]})}var Xe=s();function Ze(){let e=(0,m.useRef)(null),t=(0,m.useRef)(``);return{hover:(0,m.useCallback)(n=>({onMouseMove(r){t.current=n;let i=e.current;if(i===null)return;i.textContent=n;let a=l({left:r.clientX,top:r.clientY,width:0,height:0},{width:i.offsetWidth,height:i.offsetHeight},{width:window.innerWidth,height:window.innerHeight},`top`);i.style.left=`${a.left}px`,i.style.top=`${a.top}px`,i.classList.add(`hm-tip-on`)},onMouseLeave(){t.current===n&&(t.current=``,e.current?.classList.remove(`hm-tip-on`))}}),[]),node:(0,Xe.createPortal)((0,E.jsx)(`div`,{className:`tip hm-tip`,"aria-hidden":`true`,ref:e}),document.body)}}var q=`none`,J=`-`;function Qe(e){let{facts:t,now:n}=e,r=t.longestStreak;return(0,E.jsx)(`div`,{className:`hm-list`,children:[[`First commit`,t.firstCommit===null?q:e.shallow?`${w(t.firstCommit)} (shallow)`:w(t.firstCommit),t.firstCommit===null?J:u(t.firstCommit,n)],[`Commits`,x(e.commits),`${t.commitsPerDay} a day`],[`Longest streak`,r===null?q:S(r.days,`day`),r===null?J:ee(r.from,r.to)],[`Biggest day`,t.biggestDay===null?q:w(t.biggestDay.date),t.biggestDay===null?J:S(t.biggestDay.commits,`commit`)],[`Last tag`,t.lastTag===null?q:t.lastTag.name,t.lastTag===null?J:u(t.lastTag.date,n)],[`Stashes`,x(t.stashes),J]].map(([e,t,n])=>(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`span`,{children:e}),(0,E.jsx)(`span`,{className:`hm-muted`,children:t}),(0,E.jsx)(`span`,{className:`hm-muted`,children:n})]},e))})}var $e=[`Mon`,`Tue`,`Wed`,`Thu`,`Fri`,`Sat`,`Sun`],et=[`0`,`6`,`12`,`18`,`23`];function tt(e){let t=Math.max(...e.counts);return(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(`div`,{className:e.wide===!0?`hm-bars hm-bars-wide`:`hm-bars`,children:e.counts.map((n,r)=>(0,E.jsx)(`i`,{className:n===t&&t>0?`hm-tall`:void 0,style:{height:t>0?`${n/t*100}%`:`0%`},...e.hover(e.said(r,n))},r))}),(0,E.jsx)(`div`,{className:`hm-axis-x`,children:e.marks.map(e=>(0,E.jsx)(`span`,{children:e},e))})]})}function nt(e){return(0,E.jsx)(tt,{counts:e.counts,marks:et,hover:e.hover,said:(e,t)=>`${String(e).padStart(2,`0`)}:00 - ${S(t,`commit`)}`})}function rt(e){return(0,E.jsx)(tt,{counts:e.counts,marks:$e,wide:!0,hover:e.hover,said:(e,t)=>`${$e[e]} - ${S(t,`commit`)}`})}var Y=c(`home`);Y.receive;var it=Y.credentialsReady,at=Y.onSession;Y.openOutside;var ot=Y.sayWaiting,st=Y.listen;function ct(e){return(0,E.jsxs)(`div`,{className:`hm-hbar`,children:[(0,E.jsx)(`span`,{className:`hm-key-name`,title:e.name,children:e.name}),(0,E.jsx)(`div`,{className:`hm-track`,children:(0,E.jsx)(`i`,{style:{width:`${e.width}%`,background:e.colour}})}),(0,E.jsx)(`span`,{className:`hm-value`,children:e.value}),e.note!==void 0&&(0,E.jsx)(`span`,{className:e.note.className,title:e.note.title,children:e.note.said})]})}var lt=[`#3987e5`,`#8b949e`,`#c98500`,`#199e70`,`#d95926`,`#d55181`,`#4f74d6`];function ut(e,t){if(e===null)return{size:`ignored files not counted yet`,when:``};let n=a(e.bytes),r=e.atLeast?`the count hit its ${je/1e3} s limit · `:``;return{size:`${e.atLeast?`at least ${n}`:n} ignored`,when:`${r}counted ${u(e.countedAt,t)}`}}function dt(e,t,n){if(n===`all`||t.length===0)return``;let r=e.files.all-e.files.work,i=e.lines.all-e.lines.work;return r===0?``:`${t.join(` and `)} left out · ${S(r,`file`)} and ${x(i)} lines`}function ft(e){let t=ut(e.ignored,e.now),n=dt(e.tracked,e.toolPaths,e.counting);return(0,E.jsxs)(`div`,{children:[e.kinds.map((e,t)=>(0,E.jsx)(ct,{name:e.kind,width:e.share,colour:lt[t%lt.length]??``,value:`${e.share}%`},e.kind)),(0,E.jsxs)(`div`,{className:`hm-sub`,children:[S(P(e.tracked.files,e.counting),`tracked file`),` ·`,` `,x(P(e.tracked.lines,e.counting)),` lines ·`,` `,a(P(e.tracked.bytes,e.counting)),` tracked · `,(0,E.jsx)(`b`,{children:t.size}),t.when!==``&&` · ${t.when}`]}),n!==``&&(0,E.jsx)(`div`,{className:`hm-sub hm-left-out`,children:n})]})}var X=d({prefix:`home`,label:`Home`,credentialsReady:it});function pt(){return X.ask(`history`)}function mt(){return X.ask(`branches`)}function ht(){return X.ask(`tree`)}var Z={status:`waiting`},gt=1500,_t=90,vt=5;function yt(e){let t=e instanceof Error?e.message:String(e);return t===``?`the Home tool could not read the repository`:t}function bt(){let[e,t]=(0,m.useState)(Z),[n,r]=(0,m.useState)(Z),[i,a]=(0,m.useState)(Z),[o,s]=(0,m.useState)(null),c=(0,m.useRef)(0),l=(0,m.useRef)(!0);(0,m.useEffect)(()=>(l.current=!0,()=>{l.current=!1}),[]);let u=(0,m.useRef)({reads:0,counted:-1,stalls:0}),d=(0,m.useCallback)(()=>{c.current+=1;let e=c.current,n=()=>l.current&&c.current===e;u.current={reads:0,counted:-1,stalls:0},s(new Date);let i=(e,t)=>{t(Z),e().then(e=>{n()&&t({status:`read`,answer:e})},e=>{n()&&t({status:`failed`,said:yt(e)})})};i(pt,t),i(mt,r),i(ht,a)},[]),f=(0,m.useCallback)(()=>{let e=c.current;ht().then(t=>{l.current&&c.current===e&&a({status:`read`,answer:t})},()=>{})},[]);return(0,m.useEffect)(()=>{if(i.status!==`read`)return;let e=i.answer;if(e.repository===null||!e.growth.filling)return;let t=u.current;if(e.growth.counted>t.counted?(t.counted=e.growth.counted,t.stalls=0):t.stalls+=1,t.reads+=1,t.stalls>vt||t.reads>_t)return;let n=setTimeout(f,gt);return()=>clearTimeout(n)},[i,f]),{history:e,branches:n,tree:i,readAt:o,read:d}}function xt(e){let t=(0,m.useRef)(e);t.current=e,(0,m.useEffect)(()=>{let e=!1,n=new ResizeObserver(n=>{let r=(n[n.length-1]?.contentRect.width??0)>0;r&&!e&&t.current(),e=r});return n.observe(document.documentElement),()=>n.disconnect()},[])}function St(e){return e===1?`active day`:`active days`}var Ct=[`January`,`February`,`March`,`April`,`May`,`June`,`July`,`August`,`September`,`October`,`November`,`December`];function wt(e){return{year:e.getFullYear(),month:e.getMonth(),date:e.getDate()}}function Tt(e,t,n){let r=new Date(e,t,n),i=String(r.getMonth()+1).padStart(2,`0`),a=String(r.getDate()).padStart(2,`0`);return`${r.getFullYear()}-${i}-${a}`}function Q(e,t,n,r){let i=[];for(let a=0;a<r;a++)i.push(Tt(e,t,n+a));return i}function Et(e){return(e.getDay()+6)%7+1}function Dt(e,t){return new Date(e,t+1,0).getDate()}function $(e,t){return t.filter(t=>(e.get(t)?.commits??0)>0).length}function Ot(e,t,n){let r=0,i=0;for(let a of t){let t=e.get(a);t!==void 0&&(r+=P(t.added,n),i+=P(t.deleted,n))}return{added:r,deleted:i}}function kt(e,t,n){if(t===0)return e===0?{said:`none on ${n} either`,up:!1}:{said:`none on ${n}`,up:!0};let r=Math.round((e-t)/t*100);return{said:`${r>=0?`+`:``}${r}% on ${n}`,up:r>0}}function At(e,t,n=`work`){let r=new Map(e.map(e=>[e.date,e])),i=wt(t),a=Q(i.year,i.month,1,i.date),o=i.month===0?{year:i.year-1,month:11}:{year:i.year,month:i.month-1},s=Q(o.year,o.month,1,Math.min(i.date,Dt(o.year,o.month))),c=Et(t),l=Q(i.year,i.month,i.date-c+1,c),u=Q(i.year,i.month,i.date-c-6,c),d=Ot(r,l,n);return{month:{planted:$(r,a),name:Ct[i.month]??``,against:kt($(r,a),$(r,s),`the same days of ${Ct[o.month]??``}`)},week:{planted:$(r,l),against:kt($(r,l),$(r,u),`the same days last week`)},lines:{added:d.added,deleted:d.deleted,perDay:Math.round((d.added+d.deleted)/c)}}}function jt(e){let t=At(e.days,e.now,e.counting);return(0,E.jsxs)(`div`,{className:`hm-tiles`,children:[(0,E.jsxs)(`div`,{className:`hm-card hm-tile`,children:[(0,E.jsxs)(`div`,{className:`hm-big`,children:[x(t.month.planted),` `,(0,E.jsxs)(`span`,{className:`hm-span`,children:[St(t.month.planted),` in `,t.month.name]})]}),(0,E.jsx)(`div`,{className:`hm-sub`,children:(0,E.jsx)(Mt,{...t.month.against})})]}),(0,E.jsxs)(`div`,{className:`hm-card hm-tile`,children:[(0,E.jsxs)(`div`,{className:`hm-big`,children:[x(t.week.planted),` `,(0,E.jsxs)(`span`,{className:`hm-span`,children:[St(t.week.planted),` since Monday`]})]}),(0,E.jsx)(`div`,{className:`hm-sub`,children:(0,E.jsx)(Mt,{...t.week.against})})]}),(0,E.jsxs)(`div`,{className:`hm-card hm-tile`,children:[(0,E.jsxs)(`div`,{className:`hm-big hm-lines`,children:[(0,E.jsxs)(`span`,{className:`hm-added`,children:[`+`,x(t.lines.added)]}),(0,E.jsx)(`span`,{className:`hm-slash`,children:` / `}),(0,E.jsxs)(`span`,{className:`hm-deleted`,children:[`-`,x(t.lines.deleted)]})]}),(0,E.jsxs)(`div`,{className:`hm-sub`,children:[`lines since Monday · `,x(t.lines.perDay),` a day on average`]})]})]})}function Mt(e){return(0,E.jsx)(`span`,{className:e.up?`hm-up`:void 0,children:e.said})}function Nt(e){if(e===null||e.default===null)return null;let t=e.branches.find(e=>e.current);return t===void 0||t.name===e.default?null:{count:t.ahead,base:e.default}}function Pt(){let e=bt(),t=p(!0),n=Ze(),[r,i]=(0,m.useState)(!0);(0,m.useEffect)(()=>at(e=>i(e.sound)),[]);let[a,o]=(0,m.useState)(`work`),s=Te();xt(e.read),(0,m.useEffect)(()=>{ot(0,!0)},[]);let c=e.history,l=c.status===`read`?c.answer:null,u=l===null?null:l.repository;if(l!==null&&l.repository===null)return(0,E.jsx)(`div`,{className:`hm-page`,children:(0,E.jsx)(`div`,{className:`hm-column`,children:(0,E.jsx)(`p`,{className:`hm-plain`,children:`This workspace holds no git repository, so there is no pulse to show.`})})});let d=u===null?`loading`:`read`,f=e.branches,h=e.tree,g=e=>e.status===`read`?`read`:e.status===`failed`?`failed`:`loading`,_=e=>e.status===`failed`?e.said:void 0,v=f.status===`read`&&f.answer.repository!==null?f.answer:null,y=h.status===`read`&&h.answer.repository!==null?h.answer:null,b=l!==null&&l.repository!==null?l:null,x=u!==null&&u.commits===0,S=[u,y?.repository,v?.repository].find(e=>(e?.toolPaths.length??0)>0)?.toolPaths??[],C=(0,E.jsx)(D,{title:`Branches`,note:v===null?void 0:ie(v.branches),state:g(f),said:_(f),loaderHeight:130,className:`hm-branches-card`,children:v!==null&&(0,E.jsx)(oe,{branches:v.branches,default:v.default,now:t})}),w=(0,E.jsx)(D,{title:`The tree`,note:`what the workspace is made of`,state:g(h),said:_(h),loaderHeight:130,children:y!==null&&(0,E.jsx)(ft,{kinds:a===`all`?y.kinds:y.kindsWork,tracked:y.tracked,ignored:y.ignored,toolPaths:y.repository.toolPaths,counting:a,now:t})}),T=(0,E.jsx)(D,{title:`Growth`,note:`tracked files and lines, since the first commit`,state:g(h),said:_(h),loaderHeight:130,className:`hm-growth-card`,children:y!==null&&(0,E.jsx)(Ke,{growth:y.growth,counting:a,hover:n.hover})});return c.status===`failed`?(0,E.jsxs)(`div`,{className:s?`hm-page hm-still`:`hm-page`,children:[(0,E.jsxs)(`div`,{className:`hm-column`,children:[(0,E.jsxs)(`div`,{className:`hm-failed`,children:[(0,E.jsx)(`span`,{children:c.said}),` `,(0,E.jsx)(`span`,{className:`hm-muted`,children:`Read the repository again to try.`}),(0,E.jsxs)(`span`,{className:`hm-read`,children:[(0,E.jsx)(Ae,{toolPaths:S,counting:a,onChange:o}),(0,E.jsx)(Ye,{readAt:e.readAt,now:t,onRefresh:e.read})]})]}),(0,E.jsxs)(`div`,{className:`hm-grid`,children:[C,T]}),(0,E.jsx)(`div`,{className:`hm-grid`,children:w})]}),n.node,(0,E.jsx)(N,{sound:r})]}):(0,E.jsxs)(`div`,{className:s?`hm-page hm-still`:`hm-page`,children:[(0,E.jsxs)(`div`,{className:`hm-column`,children:[(0,E.jsx)(qe,{repository:u,onTop:Nt(v),readAt:e.readAt,now:t,onRefresh:e.read,toolPaths:S,counting:a,onCounting:o}),x?(0,E.jsx)(`p`,{className:`hm-plain`,children:`This repository has no commit yet. The page fills in as the work starts.`}):(0,E.jsxs)(E.Fragment,{children:[(0,E.jsxs)(D,{state:d,loaderHeight:192,className:`hm-garden-card`,children:[b!==null&&(0,E.jsx)(Ue,{days:b.days,today:b.readAt.slice(0,10),counting:a,hover:n.hover}),b?.repository.cut===!0&&(0,E.jsx)(`p`,{className:`hm-cut`,children:`The full history was too large to walk, so this garden is the last two years alone.`})]}),b===null?(0,E.jsxs)(`div`,{className:`hm-tiles`,children:[(0,E.jsx)(`div`,{className:`hm-card hm-tile`,children:(0,E.jsx)(`div`,{className:`hm-loader`,style:{height:`46px`}})}),(0,E.jsx)(`div`,{className:`hm-card hm-tile`,children:(0,E.jsx)(`div`,{className:`hm-loader`,style:{height:`46px`}})}),(0,E.jsx)(`div`,{className:`hm-card hm-tile`,children:(0,E.jsx)(`div`,{className:`hm-loader`,style:{height:`46px`}})})]}):(0,E.jsx)(jt,{days:b.days,now:t,counting:a}),(0,E.jsxs)(`div`,{className:`hm-grid`,children:[(0,E.jsx)(D,{title:`Rhythm`,note:`commits by hour, author time`,state:d,loaderHeight:84,children:b!==null&&(0,E.jsx)(nt,{counts:b.hours,hover:n.hover})}),(0,E.jsx)(D,{title:`Rhythm`,note:`commits by weekday`,state:d,loaderHeight:84,children:b!==null&&(0,E.jsx)(rt,{counts:b.weekdays,hover:n.hover})})]}),(0,E.jsxs)(`div`,{className:`hm-grid`,children:[C,T]}),(0,E.jsxs)(`div`,{className:`hm-grid`,children:[w,(0,E.jsx)(D,{title:`Milestones`,state:d,loaderHeight:130,children:b!==null&&(0,E.jsx)(Qe,{facts:b.milestones,commits:b.repository.commits,now:t,shallow:b.repository.shallow})})]})]})]}),n.node,(0,E.jsx)(N,{sound:r})]})}st();var Ft=document.getElementById(`root`);Ft&&(0,h.createRoot)(Ft).render((0,E.jsx)(m.StrictMode,{children:(0,E.jsx)(Pt,{})}));
|