chamba 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +7 -1
  2. package/dist/lib/chamba-yaml.js +4 -4
  3. package/package.json +1 -1
  4. package/templates/Dockerfile +3 -3
  5. package/templates/context/baseline.md +2 -2
  6. package/templates/context/web-pane-craft.md +1 -1
  7. package/templates/pane-apps/client/assets/api-BBDf_rzz.js +12 -0
  8. package/templates/pane-apps/client/assets/api-DNLbSBpK.css +1 -0
  9. package/templates/pane-apps/client/assets/bee-B7t97l5B.webp +0 -0
  10. package/templates/pane-apps/client/assets/buzz-CUUsbnXH.mp3 +0 -0
  11. package/templates/pane-apps/client/assets/files-BkmyervY.js +1 -0
  12. package/templates/pane-apps/client/assets/home-3SeGzySM.css +1 -0
  13. package/templates/pane-apps/client/assets/home-Cu9xOd2i.js +1 -0
  14. package/templates/pane-apps/client/assets/pop-D5ZANBC3.mp3 +0 -0
  15. package/templates/pane-apps/client/assets/reviews-DMrGB-kG.js +153 -0
  16. package/templates/pane-apps/client/assets/reviews-nK_yRav9.css +1 -0
  17. package/templates/pane-apps/client/assets/specs-Cabb15F0.js +13 -0
  18. package/templates/pane-apps/client/assets/useNow-BHFKFraS.js +1 -0
  19. package/templates/pane-apps/client/home/index.html +16 -0
  20. package/templates/pane-apps/client/reviews/index.html +6 -4
  21. package/templates/pane-apps/client/specs/index.html +4 -3
  22. package/templates/pane-apps/server/home.mjs +12 -0
  23. package/templates/pane-apps/server/reviews.mjs +19 -18
  24. package/templates/pane-apps/server/specs.mjs +4 -4
  25. package/templates/skills/dx-review/SKILL.md +16 -3
  26. package/templates/skills/dx-review/references/acts.md +86 -15
  27. package/templates/skills/dx-spec/SKILL.md +7 -3
  28. package/templates/skills/dx-spec/references/review-guide.md +2 -2
  29. package/templates/skills/dx-spec/references/spec-guide.md +1 -1
  30. package/templates/skills/dx-spec/references/stages.md +6 -2
  31. package/templates/skills/dx-spec-execute/SKILL.md +73 -7
  32. package/templates/startup.mjs +13 -13
  33. package/templates/tool-helper.sh +4 -2
  34. package/templates/webterm/README.md +34 -13
  35. package/templates/webterm/config.js +20 -0
  36. package/templates/webterm/public/app/alerts.js +92 -11
  37. package/templates/webterm/public/app/composer.js +37 -3
  38. package/templates/webterm/public/app/connection.js +14 -0
  39. package/templates/webterm/public/app/dom.js +1 -0
  40. package/templates/webterm/public/app/frames.js +1 -1
  41. package/templates/webterm/public/app/home-host.js +16 -0
  42. package/templates/webterm/public/app/main.js +4 -2
  43. package/templates/webterm/public/app/pane-shape.js +5 -3
  44. package/templates/webterm/public/app/pane-shell.js +45 -5
  45. package/templates/webterm/public/app/pane.js +8 -2
  46. package/templates/webterm/public/app/reviews-host.js +5 -1
  47. package/templates/webterm/public/app/tool-host.js +19 -3
  48. package/templates/webterm/public/app/workspace-color.js +1 -1
  49. package/templates/webterm/public/index.html +5 -1
  50. package/templates/webterm/public/styles.css +52 -0
  51. package/templates/webterm/tool-document.js +3 -2
  52. package/templates/webterm/tools/home.js +58 -0
  53. package/templates/webterm/tools/index.js +5 -4
  54. package/templates/webterm/tools/reviews.js +7 -3
  55. package/templates/pane-apps/client/assets/files-D0nJgFAA.js +0 -12
  56. package/templates/pane-apps/client/assets/files-h0K1vZyQ.css +0 -1
  57. package/templates/pane-apps/client/assets/reviews-BsoGZ35r.css +0 -1
  58. package/templates/pane-apps/client/assets/reviews-iW0Mbn4e.js +0 -153
  59. package/templates/pane-apps/client/assets/specs-D9z3neR-.js +0 -13
package/README.md CHANGED
@@ -33,7 +33,7 @@ The optional fields - `shadow_paths`, `env`, `ports`, `profiles` - are all descr
33
33
  - **The current CLIs.** claude, opencode and codex are kept on their latest versions, each with its config directory bind-mounted to the workspace cache so conversations and memory survive rebuilds.
34
34
  - **Your own clock.** The container runs on the timezone your machine is on, so everything a session dates - a log line, a commit, an archived piece of work - is dated the way you read it. Work somewhere else for a week and the next session picks the new zone up, rebuilding the container to do it.
35
35
  - **A web interface.** The browser front-end relays the real agent TUI over a websocket - every session on one page, several agents at once, images and dictation. It starts with the container. Claude sessions also get a status strip above the composer: model, context used, quota left.
36
- - **A pane of tools beside the terminal.** Pages, where an agent publishes a page for you to read or a form for you to answer; Specs, where a piece of work is read, annotated and steered; and Code Reviews, where a changeset is reviewed hunk by hunk with the agent on the other side of it. An agent reaches each one with a helper on its path - `specs` and `reviews` - and the `dx-spec` and `dx-review` skills teach it the craft.
36
+ - **A pane of tools beside the terminal.** Home, the pulse of the repository you are working in; Pages, where an agent publishes a page for you to read or a form for you to answer; Specs, where a piece of work is read, annotated and steered; and Code Reviews, where a changeset is reviewed hunk by hunk with the agent on the other side of it. An agent reaches Specs and Code Reviews with a helper on its path - `specs` and `reviews` - and the `dx-spec` and `dx-review` skills teach it the craft. The agent cannot reach Home at all.
37
37
 
38
38
  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.
@@ -44,6 +44,11 @@ The menu has two doors into that container.
44
44
  Beside the terminal is a pane, there from the first second of a session, and the pane holds tools.
45
45
  One tab each, and the width controls beside them: drag the divider, take the whole window, go back to half of it, or fold the pane into the spine at its edge.
46
46
 
47
+ **Home** is the tab a session opens on, and it is the repository you are in, read from git.
48
+ The header row says the branch, what is uncommitted and when the last commit landed, and under it the work of the repository is drawn: the days you committed on, the shape of your week, the branches, the tree and the milestones.
49
+ It reads when you open the tab and when you press Refresh, and never on its own, so nothing here is watching you type.
50
+ Nothing it draws touches the repository, and its numbers are cached outside the workspace, so `git status` never shows it.
51
+
47
52
  **Pages** is where an agent publishes.
48
53
  `webpane report.html --title "Port rework"` puts a standalone HTML file in the pane as a chip: a plan, a comparison table, a long answer, anything worth reading at your own pace instead of scrolling back for.
49
54
  A page can also ask - a form marked `data-feedback` is wired up by the interface, and what you submit is written as JSON next to the page, with one line typed into the agent's terminal saying where to read it.
@@ -59,6 +64,7 @@ Each agent spells the two commands its own way - `/dx-spec` and `/dx-spec-execut
59
64
 
60
65
  **Code Reviews** is where a changeset is read hunk by hunk.
61
66
  Pick what to review - the branch against its base, the last commit, a commit, a range, another branch - and the tool computes the hunks itself and asks the agent to group them and to say what each group does.
67
+ The main line has no base of its own, so on `main` or `master` the form opens on the last commit and says why.
62
68
  Mark a hunk seen, comment on one or on a group, and send the lot to the agent in one act; the agent's replies arrive live in the threads they belong to.
63
69
  Sync the review after new commits and every hunk nobody touched stays as it was read; follow a squash merge and the review moves to the commit it became; sign the approval and the review is filed away as it looked at the end.
64
70
  The tool reads the repository and writes nothing to it: the commit and the checkout are the agent's, in the terminal beside the tab.
@@ -1,10 +1,10 @@
1
- import{existsSync as w,readFileSync as h,writeFileSync as v}from"node:fs";import{basename as $,join as p}from"node:path";import y from"ajv";import{dump as C,load as _}from"js-yaml";import{CHAMBA_SCHEMA_DIR as S,CHAMBA_SCHEMA_FILE as g,CHAMBA_YAML as o,DEFAULT_SHADOW_PATHS as j,PACKAGE_ROOT as b,WORKSPACE_ID_MAX as m,WORKSPACE_ID_MIN as k}from"./constants.js";const M=/^[a-z0-9][a-z0-9-]*[a-z0-9]$/;function B(e){if(e.length<k)return`Workspace ID must be at least ${k} characters`;if(e.length>m)return`Workspace ID must be at most ${m} characters`;if(!M.test(e))return"Workspace ID must be lowercase alphanumeric with hyphens, not starting or ending with a hyphen"}function Y(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,m)||"my-workspace"}const I=p(b,S,g),O=y.default??y;let u=null;function A(){if(!u){const e=JSON.parse(h(I,"utf8"));u=new O({allErrors:!0,allowUnionTypes:!0}).compile(e)}return u}function E(e){return(e??[]).map(t=>{if(t.keyword==="additionalProperties"&&t.params?.additionalProperty)return`unknown property "${t.params.additionalProperty}"`;const a=t.instancePath?`"${t.instancePath.slice(1).replace(/\//g,".")}"`:"";return a?`${a} ${t.message}`:t.message??"validation error"}).join("; ")}function V(e){const t=p(e,o);if(!w(t))return null;const a=_(h(t,"utf8"));if(typeof a!="object"||a===null)throw new Error(`${o} is empty or not a valid YAML object`);const r=A();if(!r(a))throw new Error(`Invalid ${o}: ${E(r.errors)}`);return a}const{version:P}=JSON.parse(h(p(b,"package.json"),"utf8")),D=`https://unpkg.com/chamba@${P}/schema/${g}`,W=`# yaml-language-server: $schema=${D}`,x={workspace_id:`# chamba workspace config - run 'npx chamba' from anywhere under this directory tree to start your dev container.
1
+ import{existsSync as w,readFileSync as h,writeFileSync as A}from"node:fs";import{basename as $,join as p}from"node:path";import y from"ajv";import{dump as C,load as _}from"js-yaml";import{CHAMBA_SCHEMA_DIR as S,CHAMBA_SCHEMA_FILE as g,CHAMBA_YAML as o,DEFAULT_SHADOW_PATHS as j,PACKAGE_ROOT as b,WORKSPACE_ID_MAX as m,WORKSPACE_ID_MIN as k}from"./constants.js";const M=/^[a-z0-9][a-z0-9-]*[a-z0-9]$/;function B(e){if(e.length<k)return`Workspace ID must be at least ${k} characters`;if(e.length>m)return`Workspace ID must be at most ${m} characters`;if(!M.test(e))return"Workspace ID must be lowercase alphanumeric with hyphens, not starting or ending with a hyphen"}function Y(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,m)||"my-workspace"}const O=p(b,S,g),P=y.default??y;let u=null;function E(){if(!u){const e=JSON.parse(h(O,"utf8"));u=new P({allErrors:!0,allowUnionTypes:!0}).compile(e)}return u}function v(e){return(e??[]).map(t=>{if(t.keyword==="additionalProperties"&&t.params?.additionalProperty)return`unknown property "${t.params.additionalProperty}"`;const a=t.instancePath?`"${t.instancePath.slice(1).replace(/\//g,".")}"`:"";return a?`${a} ${t.message}`:t.message??"validation error"}).join("; ")}function V(e){const t=p(e,o);if(!w(t))return null;const a=_(h(t,"utf8"));if(typeof a!="object"||a===null)throw new Error(`${o} is empty or not a valid YAML object`);const r=E();if(!r(a))throw new Error(`Invalid ${o}: ${v(r.errors)}`);return a}const{version:I}=JSON.parse(h(p(b,"package.json"),"utf8")),D=`https://unpkg.com/chamba@${I}/schema/${g}`,W=`# yaml-language-server: $schema=${D}`,x={workspace_id:`# chamba workspace config - run 'npx chamba' from anywhere under this directory tree to start your dev container.
2
2
  # Every field is documented in the schema above, which your editor reads for completion and validation.
3
3
  # This file may be rewritten by chamba (repair, reset, settings changes). Custom comments will not be preserved.`,env:`# Environment injected into the container - a single value or a list.
4
- # Each entry is an env-file path relative to this directory (e.g. '.env') or an inline 'KEY=VALUE' variable.`,shadow_paths:"# .gitignore-style patterns - agents see an empty, isolated copy instead of the real host data.",profiles:`# Dockerfile profiles - each adds on top of the chamba base image (Debian + Node.js + git + AI CLIs).
4
+ # Each entry is an env-file path relative to this directory (e.g. '.env') or an inline 'KEY=VALUE' variable.`,shadow_paths:"# .gitignore-style patterns - agents see an empty, isolated copy instead of the real host data.",profiles:`# Dockerfile profiles - each adds on top of the chamba base image (Debian + Node.js + git + agent CLIs).
5
5
  # Useful for teams: each person can have a lean profile for their stack instead of one large shared image.
6
6
  # When multiple profiles exist, chamba prompts you to pick one on session start.`};function R(e,t){const a=p(e,o),n=C(t,{lineWidth:-1,quotingType:'"',forceQuotes:!1}).split(`
7
7
  `),s=[];for(const c of n){const i=c.match(/^(\w[\w_]*):/)?.[1],f=i&&x[i];f&&(s.push(""),s.push(f)),s.push(c)}const l=s.join(`
8
8
  `).trimEnd(),d=t.profiles&&Object.keys(t.profiles).length>0?`
9
- ${T}`:"";v(a,`${W}${l}${d}
10
- `)}const T=" # Add more profiles here - or ask the agent inside the container to set one up for you.";function H(e){return{workspace_id:e,shadow_paths:[...j]}}const L=new Set(["workspace_id","env","shadow_paths","profiles","ports"]);function J(e){const t=p(e,o);if(!w(t))return{repairedYaml:null};try{const a=_(h(t,"utf8"));if(typeof a!="object"||a===null)return{repairedYaml:null};const r=a,n=[];for(const i of Object.keys(r))L.has(i)||(delete r[i],n.push(`removed unknown field "${i}"`));const s=Y($(e)),l=H(r.workspace_id||s);if("workspace_id"in r||(r.workspace_id=l.workspace_id,n.push(`added missing workspace_id ("${l.workspace_id}")`)),"shadow_paths"in r||(r.shadow_paths=l.shadow_paths,n.push("added default shadow_paths")),n.length===0)return{repairedYaml:null};const d=A();if(!d(r))return{repairedYaml:null,error:`${o} could not be repaired: ${E(d.errors)}`};const c=r;return R(e,c),{repairedYaml:c,message:`Repaired ${o}: ${n.join(", ")}`}}catch(a){return{repairedYaml:null,error:`${o} repair failed: ${a instanceof Error?a.message:a}`}}}export{D as SCHEMA_URL,H as buildDefaultChambaYaml,V as readChambaYaml,J as repairChambaYaml,Y as slugifyForWorkspaceId,B as validateWorkspaceId,R as writeChambaYaml};
9
+ ${T}`:"";A(a,`${W}${l}${d}
10
+ `)}const T=" # Add more profiles here - or ask the agent inside the container to set one up for you.";function H(e){return{workspace_id:e,shadow_paths:[...j]}}const L=new Set(["workspace_id","env","shadow_paths","profiles","ports"]);function J(e){const t=p(e,o);if(!w(t))return{repairedYaml:null};try{const a=_(h(t,"utf8"));if(typeof a!="object"||a===null)return{repairedYaml:null};const r=a,n=[];for(const i of Object.keys(r))L.has(i)||(delete r[i],n.push(`removed unknown field "${i}"`));const s=Y($(e)),l=H(r.workspace_id||s);if("workspace_id"in r||(r.workspace_id=l.workspace_id,n.push(`added missing workspace_id ("${l.workspace_id}")`)),"shadow_paths"in r||(r.shadow_paths=l.shadow_paths,n.push("added default shadow_paths")),n.length===0)return{repairedYaml:null};const d=E();if(!d(r))return{repairedYaml:null,error:`${o} could not be repaired: ${v(d.errors)}`};const c=r;return R(e,c),{repairedYaml:c,message:`Repaired ${o}: ${n.join(", ")}`}}catch(a){return{repairedYaml:null,error:`${o} repair failed: ${a instanceof Error?a.message:a}`}}}export{D as SCHEMA_URL,H as buildDefaultChambaYaml,V as readChambaYaml,J as repairChambaYaml,Y as slugifyForWorkspaceId,B as validateWorkspaceId,R as writeChambaYaml};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chamba",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Run AI coding agents in a container, from your browser",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,13 +14,13 @@
14
14
  # fresh and --no-cache builds stay reproducible; bumping a pin edits this file,
15
15
  # busts the build hash, and auto-prompts a rebuild. Deliberately left floating:
16
16
  # apt packages (pinned by the Debian trixie release), Node (major-pinned via
17
- # setup_24.x; minors carry security fixes), and the AI CLIs (always latest).
17
+ # setup_24.x; minors carry security fixes), and the agent CLIs (always latest).
18
18
  # ---------------------------------------------------------------------------
19
19
 
20
20
  FROM debian:trixie-slim
21
21
  LABEL chamba.managed=true
22
22
 
23
- # Enable 24-bit color support for AI CLIs (suppresses color upgrade prompts)
23
+ # Enable 24-bit color support for agent CLIs (suppresses color upgrade prompts)
24
24
  ENV COLORTERM=truecolor
25
25
 
26
26
  # ---------------------------------------------------------------------------
@@ -78,7 +78,7 @@ RUN git config --system protocol.allow never && \
78
78
  git config --system protocol.file.allow always
79
79
 
80
80
  # ---------------------------------------------------------------------------
81
- # Layer 7 - Global npm tools (pnpm pinned; AI CLIs always latest)
81
+ # Layer 7 - Global npm tools (pnpm pinned; agent CLIs always latest)
82
82
  # pnpm is pinned exact: pnpm 11 changed where global settings are read from
83
83
  # (~/.config/pnpm/config.yaml, no longer ~/.npmrc), so an unpinned major bump
84
84
  # can silently break the baked store-dir config.
@@ -6,9 +6,9 @@ You are running inside a chamba dev container.
6
6
  - `/workspace/chamba.yaml` configures this workspace - profiles, shadow paths, environment variables, published ports, and workspace identity. Only modify it when the user explicitly asks. Every field is described in the JSON schema the file's header points at.
7
7
  - Files outside mounted paths cannot be read, written, or executed. If a command fails because of missing files or permissions, tell the user: "This requires running on the host - please run `<command>` outside the container."
8
8
  - This file (`{{tool_path}}`) is managed by chamba and overwritten on every session start. Do not edit it.
9
- - At the start of every session, greet the user with one short line noting the chamba sandbox and the current git mode. When `CHAMBA_WEB_SESSION=1` is in your environment you are being reached through the web interface, so add that anything long or structured can go in the web pane beside the terminal. For example: "You're in a chamba sandbox - git mode: local, filesystem limited to /workspace. Ask for anything as a page and it opens in the web pane."
9
+ - At the start of every session, greet the user with one short line noting the chamba sandbox and the current git mode. When `CHAMBA_WEB_SESSION=1` is in your environment you are being reached through the web interface, so add that anything long or structured can go in the web pane beside the terminal. For example: "You're in a chamba sandbox - git mode: local, filesystem limited to /workspace. Ask for anything as a page and it lands on the Pages tab of the web pane."
10
10
  - If the user asks about the web interface (reaching this agent from a browser), tell them it starts with the container and opens in their browser when they open a session - there is nothing to turn on. `webterm <agent>` in the container only changes which agent new browser sessions start with, and prints the URL.
11
- - **The web pane.** Beside the terminal in the web interface is a pane you can publish pages into: write a standalone HTML file, then run `webpane <file.html> --title "A title"`. Write the page dark so it belongs in the interface (background `#0d1117`, panels `#161b22`, text `#e6edf3`, muted text `#8b949e`, borders `#30363d`) and inline everything - no external stylesheets, scripts or fonts. The page's own `<title>` is what the pane shows. Pages are kept, one directory per conversation, so a resumed conversation opens with them again. In a plain terminal session there is no pane and the helper says so.
11
+ - **The web pane.** Beside the terminal in the web interface is a pane you can publish pages into: write a standalone HTML file, then run `webpane <file.html> --title "A title"`. Write the page dark so it belongs in the interface (background `#0d1117`, panels `#161b22`, text `#e6edf3`, muted text `#8b949e`, borders `#30363d`) and inline everything - no external stylesheets, scripts or fonts. The page's own `<title>` is what the pane shows. Pages live on the pane's Pages tab, which the user may not be looking at: a page you publish is selected there and the tab says so, and it opens in front only where that tab is already the open one. Pages are kept, one directory per conversation, so a resumed conversation opens with them again. In a plain terminal session there is no pane and the helper says so.
12
12
  - **Prefer a page whenever the answer is longer or more structured than a terminal reply carries well** - a plan, a comparison table, a diagram, a long explanation - and whenever you need to ask something with more options or structure than your own question tooling holds. Then say in one line what you published. The page is the answer, not a summary of it.
13
13
  - **Spec-driven work has a tab of its own, and `specs` is your half of it.** The helper is on your path in every session. `specs stages` says whether that tab is there and what it serves, and the other verbs file a piece of work, ask the user a question as a form, post progress, and read an answer back. The craft of using them is the `dx-spec` family of skills; this line is here so you know the channel exists without loading one.
14
14
  - **Code review has a tab of its own too, and `reviews` is your half of that one.** `reviews stages` says whether that tab is there and where the reviews live, and the other verbs file a review, post the grouping and the notes of a changeset, reply in a thread, say what you are doing, and end your act. Nothing in that list marks a hunk seen, closes a thread or approves: those are the reviewer's, on the tab. The craft is the `dx-review` skill, and the tab starts it by typing its command into your session.
@@ -1,6 +1,6 @@
1
1
  ## Publishing a page
2
2
 
3
- The web pane is the panel beside the terminal in the chamba web interface. You publish a standalone HTML file into it and it opens at once, in front of the user, with a chip in the bar above the pane that they can come back to. A user who is looking at another session sees their tab marked instead, and reads the page when they get there.
3
+ The web pane is the panel beside the terminal in the chamba web interface. You publish a standalone HTML file into it, and the page is there immediately. A chip in the bar above the pane lets the user come back to it. If the user has the Pages tab open, the page opens in front of them. If the user has a different tool open, the pane does not change the tool. The Pages tab then shows that a page arrived, and it shows how many pages the user did not open. If the user looks at a different session, the tab of that session gets the mark, and the user reads the page after they go there.
4
4
 
5
5
  Publish when the answer is bigger than the terminal carries well, and when the question is.
6
6