chamba 0.6.1 → 0.8.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 (118) hide show
  1. package/LICENSE +53 -14
  2. package/README.md +38 -11
  3. package/dist/commands/advanced.js +7 -278
  4. package/dist/commands/dev.js +11 -612
  5. package/dist/commands/doctor.js +1 -29
  6. package/dist/commands/menu.js +1 -80
  7. package/dist/commands/onboard.js +6 -230
  8. package/dist/commands/settings.js +15 -349
  9. package/dist/lib/agent-commands.js +2 -0
  10. package/dist/lib/agent-context.js +6 -184
  11. package/dist/lib/browser.js +1 -40
  12. package/dist/lib/chamba-yaml.js +10 -191
  13. package/dist/lib/constants.js +1 -125
  14. package/dist/lib/dockerfile-builder.js +41 -260
  15. package/dist/lib/env.js +2 -78
  16. package/dist/lib/git-env.js +1 -21
  17. package/dist/lib/global-config.js +4 -66
  18. package/dist/lib/pnpm-store.js +1 -19
  19. package/dist/lib/ports.js +1 -210
  20. package/dist/lib/safe-rm.js +1 -26
  21. package/dist/lib/sessions.js +2 -34
  22. package/dist/lib/shadows.js +1 -176
  23. package/dist/lib/skills.js +2 -0
  24. package/dist/lib/templates.js +1 -0
  25. package/dist/lib/webterm.js +1 -305
  26. package/dist/lib/workspace-identity.js +4 -260
  27. package/package.json +6 -6
  28. package/templates/Dockerfile +24 -12
  29. package/templates/claude-statusline.sh +5 -7
  30. package/templates/context/baseline.md +2 -0
  31. package/templates/pane-apps/client/assets/c-BNa-DeUl.json +3552 -0
  32. package/templates/pane-apps/client/assets/cpp-B-T4NRoH.json +20239 -0
  33. package/templates/pane-apps/client/assets/csharp-BbxHChhA.json +6010 -0
  34. package/templates/pane-apps/client/assets/css-CWCxuwmz.json +1860 -0
  35. package/templates/pane-apps/client/assets/diff-B-2N89g8.json +154 -0
  36. package/templates/pane-apps/client/assets/docker-DWTvYW26.json +103 -0
  37. package/templates/pane-apps/client/assets/files-D0nJgFAA.js +12 -0
  38. package/templates/pane-apps/client/assets/files-h0K1vZyQ.css +1 -0
  39. package/templates/pane-apps/client/assets/go-B2hyYeNg.json +3156 -0
  40. package/templates/pane-apps/client/assets/graphql-Z6Id2aNO.json +1292 -0
  41. package/templates/pane-apps/client/assets/html-BtzvlIfu.json +2627 -0
  42. package/templates/pane-apps/client/assets/ini-Bn3Twap1.json +108 -0
  43. package/templates/pane-apps/client/assets/java-C7t2dwLO.json +1885 -0
  44. package/templates/pane-apps/client/assets/javascript-DuC2v0C0.json +5996 -0
  45. package/templates/pane-apps/client/assets/json-CwdkWeV5.json +206 -0
  46. package/templates/pane-apps/client/assets/jsonc-MYWDbTU3.json +206 -0
  47. package/templates/pane-apps/client/assets/jsx-Cn8EZuIC.json +5996 -0
  48. package/templates/pane-apps/client/assets/kotlin-CFNOz1gw.json +580 -0
  49. package/templates/pane-apps/client/assets/make-BVnlFCcl.json +629 -0
  50. package/templates/pane-apps/client/assets/markdown-B4Xk2WM_.json +3263 -0
  51. package/templates/pane-apps/client/assets/php-CAQzQmmI.json +4188 -0
  52. package/templates/pane-apps/client/assets/python-CYQee8m4.json +4174 -0
  53. package/templates/pane-apps/client/assets/reviews-BsoGZ35r.css +1 -0
  54. package/templates/pane-apps/client/assets/reviews-iW0Mbn4e.js +153 -0
  55. package/templates/pane-apps/client/assets/ruby-D7R58tus.json +3114 -0
  56. package/templates/pane-apps/client/assets/rust-BFBbFiei.json +1103 -0
  57. package/templates/pane-apps/client/assets/scss-TQRhBkPG.json +1874 -0
  58. package/templates/pane-apps/client/assets/shellscript-DieAkC4W.json +2375 -0
  59. package/templates/pane-apps/client/assets/specs-D9z3neR-.js +13 -0
  60. package/templates/pane-apps/client/assets/sql-Bxd030LV.json +634 -0
  61. package/templates/pane-apps/client/assets/toml-ChrKGzsV.json +430 -0
  62. package/templates/pane-apps/client/assets/tsx-D2e90MFw.json +5996 -0
  63. package/templates/pane-apps/client/assets/typescript-DonXQ_n1.json +5747 -0
  64. package/templates/pane-apps/client/assets/xml-B17r2RXF.json +382 -0
  65. package/templates/pane-apps/client/assets/yaml-CKn4h1zy.json +627 -0
  66. package/templates/pane-apps/client/reviews/index.html +15 -0
  67. package/templates/pane-apps/client/specs/index.html +14 -0
  68. package/templates/pane-apps/server/reviews.mjs +20 -0
  69. package/templates/pane-apps/server/specs.mjs +5 -0
  70. package/templates/skills/chamba-statusline/SKILL.md +7 -19
  71. package/templates/skills/dx-review/SKILL.md +123 -0
  72. package/templates/skills/dx-review/references/acts.md +162 -0
  73. package/templates/skills/dx-spec/SKILL.md +561 -0
  74. package/templates/skills/dx-spec/references/imagination-guide.md +140 -0
  75. package/templates/skills/dx-spec/references/principles-template.md +2 -0
  76. package/templates/skills/dx-spec/references/review-guide.md +127 -0
  77. package/templates/skills/dx-spec/references/spec-guide.md +145 -0
  78. package/templates/skills/dx-spec/references/stages.md +484 -0
  79. package/templates/skills/dx-spec-execute/SKILL.md +437 -0
  80. package/templates/startup.mjs +10 -4
  81. package/templates/tool-helper.sh +166 -0
  82. package/templates/webterm/README.md +79 -9
  83. package/templates/webterm/color.js +61 -0
  84. package/templates/webterm/config.js +74 -0
  85. package/templates/webterm/context/claude.md +0 -1
  86. package/templates/webterm/public/app/alerts.js +4 -4
  87. package/templates/webterm/public/app/anchored.js +81 -0
  88. package/templates/webterm/public/app/composer.js +4 -1
  89. package/templates/webterm/public/app/connection.js +9 -0
  90. package/templates/webterm/public/app/dom.js +15 -5
  91. package/templates/webterm/public/app/frames.js +51 -10
  92. package/templates/webterm/public/app/main.js +26 -6
  93. package/templates/webterm/public/app/new-session.js +13 -41
  94. package/templates/webterm/public/app/palette.js +58 -0
  95. package/templates/webterm/public/app/pane-shape.js +167 -0
  96. package/templates/webterm/public/app/pane-shell.js +380 -0
  97. package/templates/webterm/public/app/pane.js +77 -193
  98. package/templates/webterm/public/app/reviews-host.js +15 -0
  99. package/templates/webterm/public/app/specs-host.js +16 -0
  100. package/templates/webterm/public/app/state.js +5 -0
  101. package/templates/webterm/public/app/tabs.js +6 -2
  102. package/templates/webterm/public/app/terminal.js +8 -0
  103. package/templates/webterm/public/app/theme.js +75 -27
  104. package/templates/webterm/public/app/tool-host.js +302 -0
  105. package/templates/webterm/public/app/workspace-color.js +192 -0
  106. package/templates/webterm/public/index.html +68 -30
  107. package/templates/webterm/public/styles.css +270 -34
  108. package/templates/webterm/server.js +321 -0
  109. package/templates/webterm/tool-document.js +67 -0
  110. package/templates/webterm/tools/commands.js +61 -0
  111. package/templates/webterm/tools/index.js +25 -0
  112. package/templates/webterm/tools/mount.js +337 -0
  113. package/templates/webterm/tools/paths.js +34 -0
  114. package/templates/webterm/tools/reviews.js +133 -0
  115. package/templates/webterm/tools/specs.js +154 -0
  116. package/templates/webterm/typed-line.js +148 -0
  117. package/templates/context/context-usage.md +0 -1
  118. package/templates/context-usage.sh +0 -266
@@ -527,6 +527,13 @@ body {
527
527
  display: flex;
528
528
  flex: 1;
529
529
  min-height: 0;
530
+ /* Stated once because two rules need it: the grip is this wide, and a full-width pane is the row less
531
+ the grip - which is what keeps the grip on the screen with the terminal squeezed out behind it. */
532
+ --grip-width: 12px;
533
+ /* The terminal's own inset, on both sides. A margin does not shrink with the box it is on, so a
534
+ full-width pane has to leave it as well or the row is wider than the window and the pane's own
535
+ controls, which sit at its far end, go off the screen. */
536
+ --term-gutter: 24px;
530
537
  }
531
538
 
532
539
  #termwrap {
@@ -537,7 +544,7 @@ body {
537
544
  /* Spacing via margin, not padding: FitAddon measures the wrapper height but does not subtract
538
545
  its padding, so wrapper padding makes it propose one row too many and the last line clips.
539
546
  Margin gives the same visual inset (page and terminal share a background) without breaking fit. */
540
- margin: 8px 12px;
547
+ margin: 8px calc(var(--term-gutter) / 2);
541
548
  }
542
549
 
543
550
  #term {
@@ -595,7 +602,7 @@ body {
595
602
  #grip {
596
603
  position: relative;
597
604
  flex: none;
598
- width: 12px;
605
+ width: var(--grip-width);
599
606
  background: var(--panel);
600
607
  border-left: 1px solid var(--border);
601
608
  border-right: 1px solid var(--border);
@@ -626,17 +633,28 @@ body.dragging {
626
633
  user-select: none;
627
634
  }
628
635
 
629
- /* The width is app/pane.js's, in a custom property so the two rules that must win - the collapsed spine and
630
- the narrow-screen layout - still do. The value here is what shows before the first drag. */
636
+ /* The width is app/pane-shell.js's, in a custom property so the three rules that must win - the collapsed
637
+ spine, the full row and the narrow-screen layout - still do. The value here shows for the moment before the
638
+ first draw sets the property, so it is the same half the pane's own default is. */
631
639
  #pane {
632
640
  display: flex;
633
641
  flex: none;
634
642
  flex-direction: column;
635
- width: var(--pane-width, 44%);
643
+ width: var(--pane-width, 50%);
636
644
  min-width: 0;
637
645
  background: var(--bg);
638
646
  }
639
647
 
648
+ /* The far end of the range: the pane takes the row and the terminal is squeezed out of it rather than hidden,
649
+ so the terminal keeps its place in the layout and comes back at whatever the next width is. The grip is
650
+ what the row leaves over, which is what keeps the way back on the screen, and the terminal's gutter is left
651
+ as well - it is a margin, so it stays whatever the box it is on shrinks to, and taking the row without it
652
+ would push the pane's own controls past the right edge of the window. Both are the same background, so what
653
+ the terminal leaves behind reads as part of the pane. */
654
+ #pane.full {
655
+ width: calc(100% - var(--grip-width) - var(--term-gutter));
656
+ }
657
+
640
658
  /* A page arrived and opened itself: one pulse of the workspace colour along the pane's own edge, and nothing
641
659
  moves. Inset, so it is drawn over the pane rather than pushing the layout about, and over the frame's edge
642
660
  rather than under it. ARRIVAL_MS in app/pane.js must match the duration - it is what takes the class off
@@ -664,20 +682,8 @@ body.dragging {
664
682
  }
665
683
  }
666
684
 
667
- /* The pagination bar: this session's pages as chips, the arrows for a bar too narrow to hold them, and where
668
- in the history the open page sits. Drawn by the interface, outside the page's frame, so it always says the
669
- truth about which page is open. */
670
- #pagebar {
671
- display: flex;
672
- flex: none;
673
- align-items: center;
674
- gap: 6px;
675
- padding: 7px 10px;
676
- background: var(--panel);
677
- border-bottom: 1px solid var(--border);
678
- overflow: hidden;
679
- }
680
-
685
+ /* The small square buttons of the pane's two bars: the width controls up in the pane's own chrome, and the
686
+ chip arrows down in the Pages bar. */
681
687
  .pane-nav {
682
688
  flex: none;
683
689
  padding: 1px 6px;
@@ -695,6 +701,127 @@ body.dragging {
695
701
  color: var(--text);
696
702
  }
697
703
 
704
+ /* The pane's own bar: which tool is open, and how wide the pane is. Nothing in it belongs to a tool, which is
705
+ what stops a tool from moving the pane or from saying which tool the user is looking at. */
706
+ #panebar {
707
+ display: flex;
708
+ flex: none;
709
+ align-items: center;
710
+ gap: 2px;
711
+ padding: 0 8px;
712
+ background: var(--bg);
713
+ border-bottom: 1px solid var(--border);
714
+ }
715
+
716
+ #tool-tabs {
717
+ display: flex;
718
+ gap: 2px;
719
+ min-width: 0;
720
+ overflow: hidden;
721
+ }
722
+
723
+ /* A tab is a label with a line under it: the pane's bar is chrome rather than a surface of its own, and the
724
+ workspace's colour under the open one is what says which tool is on the screen. */
725
+ .tool-tab {
726
+ display: flex;
727
+ flex: none;
728
+ align-items: center;
729
+ gap: 6px;
730
+ height: 34px;
731
+ padding: 0 12px;
732
+ border: none;
733
+ /* On every tab, transparent until one is open, so the open one takes no extra height and the row of them
734
+ does not move as the tool changes. */
735
+ border-bottom: 2px solid transparent;
736
+ background: none;
737
+ color: var(--muted);
738
+ font: inherit;
739
+ font-size: 13px;
740
+ cursor: pointer;
741
+ }
742
+
743
+ .tool-tab:hover {
744
+ color: var(--text);
745
+ }
746
+
747
+ .tool-tab.on {
748
+ border-bottom-color: var(--ws);
749
+ color: var(--text);
750
+ }
751
+
752
+ /* What is waiting in a tool nobody is looking at. The same green as everything else that means "something
753
+ happened here". */
754
+ .tool-mark {
755
+ padding: 0 5px;
756
+ border-radius: 8px;
757
+ background: var(--accent);
758
+ color: #04140b;
759
+ font-size: 9.5px;
760
+ font-weight: 700;
761
+ }
762
+
763
+ /* A tool that counts nothing says only that something arrived, so its mark carries no number and is drawn
764
+ as the dot it means. */
765
+ .tool-mark.dot {
766
+ width: 6px;
767
+ height: 6px;
768
+ padding: 0;
769
+ border-radius: 50%;
770
+ align-self: center;
771
+ }
772
+
773
+ #pane-ctl {
774
+ display: flex;
775
+ flex: none;
776
+ margin-left: auto;
777
+ gap: 2px;
778
+ }
779
+
780
+ /* The three widths, drawn as one row: the whole window, half of it, and away. */
781
+ #pane-ctl .pane-nav {
782
+ display: flex;
783
+ align-items: center;
784
+ justify-content: center;
785
+ width: 28px;
786
+ height: 28px;
787
+ padding: 0;
788
+ border-radius: 6px;
789
+ }
790
+
791
+ /* The pane is already in the state the button names, so the button says so - and for the far end it is also
792
+ the way back from it. */
793
+ #pane-ctl .pane-nav.on {
794
+ background: #10151c;
795
+ color: var(--accent);
796
+ }
797
+
798
+ /* One tool's panel. Only the open one is on the screen, and each fills whatever the pane's bar leaves. */
799
+ .tool-panel {
800
+ display: flex;
801
+ flex: 1;
802
+ flex-direction: column;
803
+ min-width: 0;
804
+ min-height: 0;
805
+ }
806
+
807
+ .tool-panel[hidden] {
808
+ display: none;
809
+ }
810
+
811
+ /* The pagination bar: this session's pages as chips, the arrows for a bar too narrow to hold them, and where
812
+ in the history the open page sits. Drawn by the interface, outside the page's frame, so it always says the
813
+ truth about which page is open. */
814
+ #pagebar {
815
+ display: flex;
816
+ flex: none;
817
+ align-items: center;
818
+ gap: 6px;
819
+ padding: 7px 10px;
820
+ background: var(--panel);
821
+ border-bottom: 1px solid var(--border);
822
+ overflow: hidden;
823
+ }
824
+
698
825
  #chips {
699
826
  display: flex;
700
827
  gap: 6px;
@@ -810,15 +937,6 @@ body.dragging {
810
937
  letter-spacing: 0.02em;
811
938
  }
812
939
 
813
- /* Out of the way, at the end of the bar: the pane is put away far more often than the chips are paged. */
814
- #pane-collapse {
815
- display: flex;
816
- align-items: center;
817
- justify-content: center;
818
- margin-left: 4px;
819
- padding: 2px 5px;
820
- }
821
-
822
940
  #page-doc {
823
941
  flex: 1;
824
942
  min-width: 0;
@@ -841,10 +959,21 @@ body.dragging {
841
959
  zoom: var(--page-zoom, 1);
842
960
  }
843
961
 
962
+ /* A tool's own client, in a frame of its own. It fills the panel and this side styles nothing inside it: the
963
+ tool ships its own document, its own stylesheet and its own theme, and the shell cannot reach in anyway. */
964
+ .tool-frame {
965
+ display: block;
966
+ width: 100%;
967
+ height: 100%;
968
+ border: none;
969
+ background: var(--bg);
970
+ }
971
+
844
972
  /* A page is a document with an event loop of its own, and a pointer that crosses into it during a drag is a
845
973
  pointer the grip has to keep. Capture does that in every engine that has it; taking the frame out of the
846
974
  hit test for the length of the drag is what makes it true everywhere. */
847
- body.dragging .page-frame {
975
+ body.dragging .page-frame,
976
+ body.dragging .tool-frame {
848
977
  pointer-events: none;
849
978
  }
850
979
 
@@ -893,8 +1022,8 @@ body.dragging .page-frame {
893
1022
  width: 30px;
894
1023
  }
895
1024
 
896
- #pane.collapsed #pagebar,
897
- #pane.collapsed #page-doc {
1025
+ #pane.collapsed #panebar,
1026
+ #pane.collapsed .tool-panel {
898
1027
  display: none;
899
1028
  }
900
1029
 
@@ -939,6 +1068,14 @@ body.dragging .page-frame {
939
1068
  writing-mode: horizontal-tb;
940
1069
  }
941
1070
 
1071
+ #spine-badge.dot {
1072
+ display: inline-block;
1073
+ width: 6px;
1074
+ height: 6px;
1075
+ padding: 0;
1076
+ border-radius: 50%;
1077
+ }
1078
+
942
1079
  #spine-badge[hidden] {
943
1080
  display: none;
944
1081
  }
@@ -957,13 +1094,17 @@ body.dragging .page-frame {
957
1094
 
958
1095
  /* ---- Overlay cards (take over / end session / limit reached) ---- */
959
1096
 
1097
+ /* Fixed to the viewport and above every pop, so the card is in the middle of the screen whatever the width of
1098
+ the terminal column beside the pane. */
960
1099
  #overlay {
961
1100
  display: none;
962
- position: absolute;
1101
+ position: fixed;
963
1102
  inset: 0;
1103
+ z-index: 70;
964
1104
  background: rgba(13, 17, 23, 0.82);
965
1105
  align-items: center;
966
1106
  justify-content: center;
1107
+ padding: 16px;
967
1108
  }
968
1109
 
969
1110
  #overlay.show {
@@ -971,7 +1112,9 @@ body.dragging .page-frame {
971
1112
  }
972
1113
 
973
1114
  .card {
1115
+ width: 100%;
974
1116
  max-width: 460px;
1117
+ box-sizing: border-box;
975
1118
  padding: 18px 20px;
976
1119
  background: var(--panel);
977
1120
  border: 1px solid var(--border);
@@ -1087,9 +1230,102 @@ body.dragging .page-frame {
1087
1230
  }
1088
1231
  }
1089
1232
 
1233
+ /* ---- The workspace colour ---- */
1234
+
1235
+ /* The one control in the bar about what this window *is* rather than what it does, so it sits beside the name
1236
+ it belongs with. It carries no colour of its own, and is drawn exactly as the bell and the power button
1237
+ are: the bar already says which colour is in force, on the edge of the active tab, and a filled swatch in
1238
+ a row of glyphs reads as something that wandered in rather than as one of the row. */
1239
+ #wscolorbtn {
1240
+ display: flex;
1241
+ align-items: center;
1242
+ justify-content: center;
1243
+ padding: 4px;
1244
+ background: transparent;
1245
+ color: var(--muted);
1246
+ border: 1px solid transparent;
1247
+ border-radius: 7px;
1248
+ cursor: pointer;
1249
+ }
1250
+
1251
+ #wscolorbtn:hover:not(:disabled),
1252
+ #wscolorbtn.open {
1253
+ color: var(--text);
1254
+ border-color: var(--border);
1255
+ }
1256
+
1257
+ /* Nothing to open while this window is not talking to the server: a pick it could not send would be undone by
1258
+ the next frame, which is worse than not offering it. */
1259
+ #wscolorbtn:disabled {
1260
+ opacity: 0.45;
1261
+ cursor: default;
1262
+ }
1263
+
1264
+ /* Anchored under the button and hung off the body, like the new-session panel: the bar is emptied on every
1265
+ frame, and picking a colour is itself a frame, so a panel inside the bar would close as it was used. */
1266
+ #wscolorpop {
1267
+ position: fixed;
1268
+ z-index: 60;
1269
+ display: flex;
1270
+ flex-direction: column;
1271
+ width: 268px;
1272
+ padding: 12px;
1273
+ background: var(--panel);
1274
+ border: 1px solid var(--border);
1275
+ border-radius: 10px;
1276
+ box-shadow: 0 12px 28px rgba(0, 0, 0, 0.5);
1277
+ }
1278
+
1279
+ .wsgrid {
1280
+ display: grid;
1281
+ grid-template-columns: repeat(6, 1fr);
1282
+ gap: 8px;
1283
+ }
1284
+
1285
+ .wscell {
1286
+ display: flex;
1287
+ align-items: center;
1288
+ justify-content: center;
1289
+ aspect-ratio: 1;
1290
+ padding: 0;
1291
+ border: 1px solid rgba(255, 255, 255, 0.08);
1292
+ border-radius: 7px;
1293
+ cursor: pointer;
1294
+ }
1295
+
1296
+ /* Two rings rather than a thicker border, so the mark reads on every one of the eleven and the cell does not
1297
+ move when it lands. The mark says what is *stored*, so it sits on the automatic cell when nothing is. */
1298
+ .wscell.chosen {
1299
+ box-shadow:
1300
+ 0 0 0 2px var(--panel),
1301
+ 0 0 0 3.5px var(--text);
1302
+ }
1303
+
1304
+ /* Automatic takes the last cell: it is one of the choices rather than a button underneath them. */
1305
+ .wscell.auto {
1306
+ background: repeating-linear-gradient(135deg, var(--border) 0 4px, #21262d 4px 8px);
1307
+ color: var(--muted);
1308
+ font-size: 15px;
1309
+ line-height: 1;
1310
+ }
1311
+
1312
+ .wscolorfoot {
1313
+ margin: 11px 0 0;
1314
+ padding-top: 10px;
1315
+ color: var(--muted);
1316
+ border-top: 1px solid var(--border);
1317
+ font-size: 11.5px;
1318
+ line-height: 1.45;
1319
+ }
1320
+
1090
1321
  /* The moment the socket drops, before any curtain: a control whose answer goes nowhere must stop taking
1091
- clicks. The composer disables itself, so this is about the bar - its tabs, its X, its + New session. */
1092
- body.offline #tabbar {
1322
+ clicks. The composer disables itself, so this is about the bar - its tabs, its X, its + New session.
1323
+ The two anchored panels are named as well: they hang off the body rather than the bar, so the bar's own
1324
+ selector does not cover them. connection.js closes them outright when the socket goes, and this is the second
1325
+ line - a rule that holds whatever order things happen in. */
1326
+ body.offline #tabbar,
1327
+ body.offline #newpop,
1328
+ body.offline #wscolorpop {
1093
1329
  pointer-events: none;
1094
1330
  }
1095
1331