chamba 0.6.0 → 0.7.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 (55) hide show
  1. package/README.md +13 -6
  2. package/dist/commands/dev.js +11 -11
  3. package/dist/commands/settings.js +1 -1
  4. package/dist/lib/agent-context.js +33 -7
  5. package/dist/lib/chamba-yaml.js +1 -1
  6. package/dist/lib/constants.js +4 -4
  7. package/dist/lib/dockerfile-builder.js +2 -1
  8. package/dist/lib/ports.js +4 -4
  9. package/dist/lib/safe-rm.js +13 -3
  10. package/dist/lib/webterm.js +7 -7
  11. package/package.json +3 -5
  12. package/templates/Dockerfile +20 -1
  13. package/templates/context/web-pane-craft.md +1 -1
  14. package/templates/pane-apps/client/assets/specs-B1970L17.css +1 -0
  15. package/templates/pane-apps/client/assets/specs-cEee_SPn.js +23 -0
  16. package/templates/pane-apps/client/specs/index.html +13 -0
  17. package/templates/pane-apps/server/specs.mjs +1588 -0
  18. package/templates/skills/chamba-statusline/SKILL.md +1 -1
  19. package/templates/skills/dx-spec/SKILL.md +365 -0
  20. package/templates/skills/dx-spec/references/imagination-guide.md +140 -0
  21. package/templates/skills/dx-spec/references/review-guide.md +173 -0
  22. package/templates/skills/dx-spec/references/spec-guide.md +125 -0
  23. package/templates/skills/dx-spec/references/stages.md +399 -0
  24. package/templates/skills/dx-spec-config/SKILL.md +313 -0
  25. package/templates/skills/dx-spec-config/references/principles-template.md +12 -0
  26. package/templates/skills/dx-spec-execute/SKILL.md +324 -0
  27. package/templates/specs.sh +106 -0
  28. package/templates/webterm/README.md +50 -14
  29. package/templates/webterm/artifacts.js +11 -11
  30. package/templates/webterm/config.js +52 -9
  31. package/templates/webterm/conversation.js +3 -3
  32. package/templates/webterm/pane.js +14 -3
  33. package/templates/webterm/proc.js +1 -1
  34. package/templates/webterm/public/app/alerts.js +5 -5
  35. package/templates/webterm/public/app/composer.js +5 -2
  36. package/templates/webterm/public/app/connection.js +2 -2
  37. package/templates/webterm/public/app/dictation.js +1 -1
  38. package/templates/webterm/public/app/dom.js +13 -5
  39. package/templates/webterm/public/app/frames.js +8 -1
  40. package/templates/webterm/public/app/main.js +8 -2
  41. package/templates/webterm/public/app/new-session.js +1 -1
  42. package/templates/webterm/public/app/pane-shell.js +315 -0
  43. package/templates/webterm/public/app/pane.js +58 -183
  44. package/templates/webterm/public/app/specs-host.js +222 -0
  45. package/templates/webterm/public/app/state.js +1 -1
  46. package/templates/webterm/public/app/tabs.js +1 -1
  47. package/templates/webterm/public/app/terminal.js +8 -0
  48. package/templates/webterm/public/index.html +51 -27
  49. package/templates/webterm/public/styles.css +144 -30
  50. package/templates/webterm/server.js +300 -11
  51. package/templates/webterm/sessions.js +7 -7
  52. package/templates/webterm/snapshot.js +2 -2
  53. package/templates/webterm/specs.js +358 -0
  54. package/templates/webterm/tool-document.js +67 -0
  55. package/templates/webterm/typed-line.js +85 -0
@@ -27,34 +27,58 @@
27
27
  <span id="note"></span>
28
28
  </div>
29
29
 
30
- <!-- The web pane, rendered by app/pane.js: the pages this session's agent published, with the chips
31
- bar and the counter drawn out here by the interface, and the page itself inside a sandboxed
32
- frame. Both it and its drag handle are hidden until the session has a page. -->
30
+ <!-- The web pane, rendered by app/pane-shell.js: the tool tabs and the two width controls are the
31
+ pane's own chrome, and one panel per tool sits under them - Pages (app/pane.js) and Specs
32
+ (app/specs-host.js). Both the pane and its drag handle are hidden until there is something in it. -->
33
33
  <div id="grip" hidden></div>
34
34
  <aside id="pane" hidden>
35
- <div id="pagebar">
36
- <button type="button" id="pane-prev" class="pane-nav" title="Older pages" aria-label="Older pages" hidden>&#8249;</button>
37
- <div id="chips"></div>
38
- <button type="button" id="pane-next" class="pane-nav" title="Newer pages" aria-label="Newer pages" hidden>&#8250;</button>
39
- <span id="page-count"></span>
40
- <!-- How big the shown page is drawn, for this browser. Interface furniture: no agent knows it
41
- exists, and a page written before it scales like any other. -->
42
- <span id="page-size">
43
- <button type="button" id="page-smaller" title="Smaller text" aria-label="Smaller text">&#8722;</button>
44
- <span id="page-size-val"></span>
45
- <button type="button" id="page-bigger" title="Larger text" aria-label="Larger text">+</button>
35
+ <!-- The pane's own bar: which tool is open, and how wide the pane is. Nothing in it belongs to a
36
+ tool, so a tool can never move the pane or say which tool the user is looking at. -->
37
+ <div id="panebar">
38
+ <div id="tool-tabs"></div>
39
+ <span id="pane-ctl">
40
+ <!-- The pane's edge to the far wall, and back again. -->
41
+ <button type="button" id="pane-full" class="pane-nav" title="Full width" aria-label="Full width">
42
+ <svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
43
+ <path d="M4 5v14" />
44
+ <path d="M20 12H9" />
45
+ <path d="M13 8l-4 4 4 4" />
46
+ </svg>
47
+ </button>
48
+ <!-- An arrow into the pane's own edge: put it away, that way. Inline because this bar is
49
+ static chrome, unlike the session bar's icons, which are drawn per frame. -->
50
+ <button type="button" id="pane-collapse" class="pane-nav" title="Collapse the pane" aria-label="Collapse the pane">
51
+ <svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
52
+ <path d="M4 12h11" />
53
+ <path d="M11 8l4 4-4 4" />
54
+ <path d="M20 5v14" />
55
+ </svg>
56
+ </button>
46
57
  </span>
47
- <!-- An arrow into the pane's own edge: put it away, that way. Inline because this bar is static
48
- chrome, unlike the session bar's icons, which are drawn per frame. -->
49
- <button type="button" id="pane-collapse" class="pane-nav" title="Collapse the web pane" aria-label="Collapse the web pane">
50
- <svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
51
- <path d="M4 12h11" />
52
- <path d="M11 8l4 4-4 4" />
53
- <path d="M20 5v14" />
54
- </svg>
55
- </button>
56
58
  </div>
57
- <div id="page-doc"></div>
59
+
60
+ <!-- Pages: the pages this session's agent published, with the chips bar and the counter drawn out
61
+ here by the interface, and the page itself inside a sandboxed frame. -->
62
+ <div id="tool-pages" class="tool-panel">
63
+ <div id="pagebar">
64
+ <button type="button" id="pane-prev" class="pane-nav" title="Older pages" aria-label="Older pages" hidden>&#8249;</button>
65
+ <div id="chips"></div>
66
+ <button type="button" id="pane-next" class="pane-nav" title="Newer pages" aria-label="Newer pages" hidden>&#8250;</button>
67
+ <span id="page-count"></span>
68
+ <!-- How big the shown page is drawn, for this browser. Interface furniture: no agent knows
69
+ it exists, and a page written before it scales like any other. -->
70
+ <span id="page-size">
71
+ <button type="button" id="page-smaller" title="Smaller text" aria-label="Smaller text">&#8722;</button>
72
+ <span id="page-size-val"></span>
73
+ <button type="button" id="page-bigger" title="Larger text" aria-label="Larger text">+</button>
74
+ </span>
75
+ </div>
76
+ <div id="page-doc"></div>
77
+ </div>
78
+
79
+ <!-- Specs: the spec workspace, in a frame of its own. -->
80
+ <div id="tool-specs" class="tool-panel" hidden></div>
81
+
58
82
  <button type="button" id="spine" title="Open the web pane" aria-label="Open the web pane">
59
83
  <span class="label"><span id="spine-badge" hidden></span> Web pane</span>
60
84
  </button>
@@ -80,10 +104,10 @@
80
104
  <!-- The one button that sends without being written: it types a fixed sentence into the
81
105
  session, through the same paste path as anything else, and leaves the box alone. Its
82
106
  place in the markup is what puts it above Send: the block fills row by row. -->
83
- <button type="button" id="ask-page" class="icon-btn" title="Put the last answer in the web pane"
84
- aria-label="Put the last answer in the web pane">
107
+ <button type="button" id="ask-page" class="icon-btn" title="Put the last answer on a page"
108
+ aria-label="Put the last answer on a page">
85
109
  <svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round">
86
- <title>Put the last answer in the web pane</title>
110
+ <title>Put the last answer on a page</title>
87
111
  <rect x="3" y="4" width="18" height="16" rx="2" />
88
112
  <path d="M14 4v16" />
89
113
  <path d="M17 9h1" />
@@ -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,8 +633,9 @@ 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 is what shows before the first
638
+ drag. */
631
639
  #pane {
632
640
  display: flex;
633
641
  flex: none;
@@ -637,6 +645,16 @@ body.dragging {
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,112 @@ 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: flex-end;
710
+ gap: 2px;
711
+ padding: 7px 10px 0;
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 folder mouth: the open one carries the panel's own background up into the bar, so the two read
724
+ as one surface and the others read as behind it. */
725
+ .tool-tab {
726
+ display: flex;
727
+ flex: none;
728
+ align-items: center;
729
+ gap: 6px;
730
+ padding: 4px 14px;
731
+ border: 1px solid transparent;
732
+ border-bottom: none;
733
+ border-radius: 7px 7px 0 0;
734
+ background: none;
735
+ color: var(--muted);
736
+ font: inherit;
737
+ font-size: 12.5px;
738
+ cursor: pointer;
739
+ }
740
+
741
+ .tool-tab:hover {
742
+ color: var(--text);
743
+ }
744
+
745
+ .tool-tab.on {
746
+ background: var(--panel);
747
+ border-color: var(--border);
748
+ color: var(--text);
749
+ }
750
+
751
+ /* What is waiting in a tool nobody is looking at. The same green as everything else that means "something
752
+ happened here". */
753
+ .tool-mark {
754
+ padding: 0 5px;
755
+ border-radius: 8px;
756
+ background: var(--accent);
757
+ color: #04140b;
758
+ font-size: 9.5px;
759
+ font-weight: 700;
760
+ }
761
+
762
+ #pane-ctl {
763
+ display: flex;
764
+ flex: none;
765
+ margin-left: auto;
766
+ gap: 4px;
767
+ padding-bottom: 5px;
768
+ }
769
+
770
+ #pane-ctl .pane-nav {
771
+ display: flex;
772
+ align-items: center;
773
+ justify-content: center;
774
+ padding: 2px 5px;
775
+ }
776
+
777
+ /* The pane is already at the far end, and the button is the way back from it. */
778
+ #pane-ctl .pane-nav.on {
779
+ background: #10151c;
780
+ color: var(--accent);
781
+ }
782
+
783
+ /* One tool's panel. Only the open one is on the screen, and each fills whatever the pane's bar leaves. */
784
+ .tool-panel {
785
+ display: flex;
786
+ flex: 1;
787
+ flex-direction: column;
788
+ min-width: 0;
789
+ min-height: 0;
790
+ }
791
+
792
+ .tool-panel[hidden] {
793
+ display: none;
794
+ }
795
+
796
+ /* The pagination bar: this session's pages as chips, the arrows for a bar too narrow to hold them, and where
797
+ in the history the open page sits. Drawn by the interface, outside the page's frame, so it always says the
798
+ truth about which page is open. */
799
+ #pagebar {
800
+ display: flex;
801
+ flex: none;
802
+ align-items: center;
803
+ gap: 6px;
804
+ padding: 7px 10px;
805
+ background: var(--panel);
806
+ border-bottom: 1px solid var(--border);
807
+ overflow: hidden;
808
+ }
809
+
698
810
  #chips {
699
811
  display: flex;
700
812
  gap: 6px;
@@ -810,15 +922,6 @@ body.dragging {
810
922
  letter-spacing: 0.02em;
811
923
  }
812
924
 
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
925
  #page-doc {
823
926
  flex: 1;
824
927
  min-width: 0;
@@ -841,10 +944,21 @@ body.dragging {
841
944
  zoom: var(--page-zoom, 1);
842
945
  }
843
946
 
947
+ /* A tool's own client, in a frame of its own. It fills the panel and this side styles nothing inside it: the
948
+ tool ships its own document, its own stylesheet and its own theme, and the shell cannot reach in anyway. */
949
+ .tool-frame {
950
+ display: block;
951
+ width: 100%;
952
+ height: 100%;
953
+ border: none;
954
+ background: var(--bg);
955
+ }
956
+
844
957
  /* 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
958
  pointer the grip has to keep. Capture does that in every engine that has it; taking the frame out of the
846
959
  hit test for the length of the drag is what makes it true everywhere. */
847
- body.dragging .page-frame {
960
+ body.dragging .page-frame,
961
+ body.dragging .tool-frame {
848
962
  pointer-events: none;
849
963
  }
850
964
 
@@ -893,8 +1007,8 @@ body.dragging .page-frame {
893
1007
  width: 30px;
894
1008
  }
895
1009
 
896
- #pane.collapsed #pagebar,
897
- #pane.collapsed #page-doc {
1010
+ #pane.collapsed #panebar,
1011
+ #pane.collapsed .tool-panel {
898
1012
  display: none;
899
1013
  }
900
1014