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.
- package/README.md +13 -6
- package/dist/commands/dev.js +11 -11
- package/dist/commands/settings.js +1 -1
- package/dist/lib/agent-context.js +33 -7
- package/dist/lib/chamba-yaml.js +1 -1
- package/dist/lib/constants.js +4 -4
- package/dist/lib/dockerfile-builder.js +2 -1
- package/dist/lib/ports.js +4 -4
- package/dist/lib/safe-rm.js +13 -3
- package/dist/lib/webterm.js +7 -7
- package/package.json +3 -5
- package/templates/Dockerfile +20 -1
- package/templates/context/web-pane-craft.md +1 -1
- package/templates/pane-apps/client/assets/specs-B1970L17.css +1 -0
- package/templates/pane-apps/client/assets/specs-cEee_SPn.js +23 -0
- package/templates/pane-apps/client/specs/index.html +13 -0
- package/templates/pane-apps/server/specs.mjs +1588 -0
- package/templates/skills/chamba-statusline/SKILL.md +1 -1
- package/templates/skills/dx-spec/SKILL.md +365 -0
- package/templates/skills/dx-spec/references/imagination-guide.md +140 -0
- package/templates/skills/dx-spec/references/review-guide.md +173 -0
- package/templates/skills/dx-spec/references/spec-guide.md +125 -0
- package/templates/skills/dx-spec/references/stages.md +399 -0
- package/templates/skills/dx-spec-config/SKILL.md +313 -0
- package/templates/skills/dx-spec-config/references/principles-template.md +12 -0
- package/templates/skills/dx-spec-execute/SKILL.md +324 -0
- package/templates/specs.sh +106 -0
- package/templates/webterm/README.md +50 -14
- package/templates/webterm/artifacts.js +11 -11
- package/templates/webterm/config.js +52 -9
- package/templates/webterm/conversation.js +3 -3
- package/templates/webterm/pane.js +14 -3
- package/templates/webterm/proc.js +1 -1
- package/templates/webterm/public/app/alerts.js +5 -5
- package/templates/webterm/public/app/composer.js +5 -2
- package/templates/webterm/public/app/connection.js +2 -2
- package/templates/webterm/public/app/dictation.js +1 -1
- package/templates/webterm/public/app/dom.js +13 -5
- package/templates/webterm/public/app/frames.js +8 -1
- package/templates/webterm/public/app/main.js +8 -2
- package/templates/webterm/public/app/new-session.js +1 -1
- package/templates/webterm/public/app/pane-shell.js +315 -0
- package/templates/webterm/public/app/pane.js +58 -183
- package/templates/webterm/public/app/specs-host.js +222 -0
- package/templates/webterm/public/app/state.js +1 -1
- package/templates/webterm/public/app/tabs.js +1 -1
- package/templates/webterm/public/app/terminal.js +8 -0
- package/templates/webterm/public/index.html +51 -27
- package/templates/webterm/public/styles.css +144 -30
- package/templates/webterm/server.js +300 -11
- package/templates/webterm/sessions.js +7 -7
- package/templates/webterm/snapshot.js +2 -2
- package/templates/webterm/specs.js +358 -0
- package/templates/webterm/tool-document.js +67 -0
- 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
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
<
|
|
39
|
-
<span id="
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
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>‹</button>
|
|
65
|
+
<div id="chips"></div>
|
|
66
|
+
<button type="button" id="pane-next" class="pane-nav" title="Newer pages" aria-label="Newer pages" hidden>›</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">−</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
|
|
84
|
-
aria-label="Put the last answer
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
630
|
-
the narrow-screen layout - still do. The value here is what shows before the first
|
|
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
|
|
668
|
-
|
|
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 #
|
|
897
|
-
#pane.collapsed
|
|
1010
|
+
#pane.collapsed #panebar,
|
|
1011
|
+
#pane.collapsed .tool-panel {
|
|
898
1012
|
display: none;
|
|
899
1013
|
}
|
|
900
1014
|
|