bitpull 0.1.23 → 0.1.25

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 (135) hide show
  1. package/README.md +2 -1
  2. package/bitpull.cjs +11701 -10690
  3. package/package.json +3 -2
  4. package/ui/ide-terminal.js +57 -0
  5. package/ui/ide.css +271 -0
  6. package/ui/ide.html +178 -0
  7. package/ui/ide.js +1336 -0
  8. package/ui/monaco/vs/abap-D-t0cyap.js +1 -0
  9. package/ui/monaco/vs/apex-CcIm7xu6.js +1 -0
  10. package/ui/monaco/vs/assets/css.worker-BpD9FCKP.js +97 -0
  11. package/ui/monaco/vs/assets/editor.worker-_vAIFJDs.js +30 -0
  12. package/ui/monaco/vs/assets/editorWebWorkerMain-DEgFqX2K.js +30 -0
  13. package/ui/monaco/vs/assets/html.worker-CLuInTTy.js +474 -0
  14. package/ui/monaco/vs/assets/json.worker-Csf_TLih.js +62 -0
  15. package/ui/monaco/vs/assets/ts.worker-g3pjEjl4.js +67722 -0
  16. package/ui/monaco/vs/azcli-BA0tQDCg.js +1 -0
  17. package/ui/monaco/vs/basic-languages/monaco.contribution.js +1 -0
  18. package/ui/monaco/vs/bat-C397hTD6.js +1 -0
  19. package/ui/monaco/vs/bicep-DF5aW17k.js +2 -0
  20. package/ui/monaco/vs/cameligo-plsz8qhj.js +1 -0
  21. package/ui/monaco/vs/clojure-Y2auQMzK.js +1 -0
  22. package/ui/monaco/vs/coffee-Bu45yuWE.js +1 -0
  23. package/ui/monaco/vs/cpp-CkKPQIni.js +1 -0
  24. package/ui/monaco/vs/csharp-CX28MZyh.js +1 -0
  25. package/ui/monaco/vs/csp-D8uWnyxW.js +1 -0
  26. package/ui/monaco/vs/css-CaeNmE3S.js +3 -0
  27. package/ui/monaco/vs/css.worker-BInK4lsP.js +1 -0
  28. package/ui/monaco/vs/cssMode-eIUIN_ru.js +1 -0
  29. package/ui/monaco/vs/cypher-DVThT8BS.js +1 -0
  30. package/ui/monaco/vs/dart-CmGfCvrO.js +1 -0
  31. package/ui/monaco/vs/dockerfile-CZqqYdch.js +1 -0
  32. package/ui/monaco/vs/ecl-30fUercY.js +1 -0
  33. package/ui/monaco/vs/editor/editor.main.css +1 -0
  34. package/ui/monaco/vs/editor/editor.main.js +1 -0
  35. package/ui/monaco/vs/editor/editor.worker.js +1 -0
  36. package/ui/monaco/vs/editor-BdtEMBbM.js +892 -0
  37. package/ui/monaco/vs/editor.js +1 -0
  38. package/ui/monaco/vs/editorWorkerHost-B_VpI68A.js +35 -0
  39. package/ui/monaco/vs/elixir-xjPaIfzF.js +1 -0
  40. package/ui/monaco/vs/flow9-DqtmStfK.js +1 -0
  41. package/ui/monaco/vs/freemarker2-B-FhRNBn.js +3 -0
  42. package/ui/monaco/vs/fsharp-BOMdg4U1.js +1 -0
  43. package/ui/monaco/vs/go-D_hbi-Jt.js +1 -0
  44. package/ui/monaco/vs/graphql-CKUU4kLG.js +1 -0
  45. package/ui/monaco/vs/handlebars-BJBfNnbX.js +1 -0
  46. package/ui/monaco/vs/hcl-DTaboeZW.js +1 -0
  47. package/ui/monaco/vs/html-BTio3wpy.js +1 -0
  48. package/ui/monaco/vs/html.worker-C1TNvQ72.js +1 -0
  49. package/ui/monaco/vs/htmlMode-aw5QYZo7.js +1 -0
  50. package/ui/monaco/vs/index-049xrXrp.js +1 -0
  51. package/ui/monaco/vs/index-DZH_zysX.js +5 -0
  52. package/ui/monaco/vs/index.js +1 -0
  53. package/ui/monaco/vs/ini-CsNwO04R.js +1 -0
  54. package/ui/monaco/vs/initialize-CAIC7-3s.js +1 -0
  55. package/ui/monaco/vs/java-CI4ZMsH9.js +1 -0
  56. package/ui/monaco/vs/javascript-B_IYblwB.js +1 -0
  57. package/ui/monaco/vs/json.worker-Bp7U0-9w.js +1 -0
  58. package/ui/monaco/vs/jsonMode-w7Q_ZLTt.js +1 -0
  59. package/ui/monaco/vs/julia-BwzEvaQw.js +1 -0
  60. package/ui/monaco/vs/kotlin-IUYPiTV8.js +1 -0
  61. package/ui/monaco/vs/less-C0eDYdqa.js +2 -0
  62. package/ui/monaco/vs/lexon-iON-Kj97.js +1 -0
  63. package/ui/monaco/vs/liquid-CXh4HpyA.js +1 -0
  64. package/ui/monaco/vs/loader.js +1368 -0
  65. package/ui/monaco/vs/lspLanguageFeatures-Cog3rVVE.js +2 -0
  66. package/ui/monaco/vs/lua-DtygF91M.js +1 -0
  67. package/ui/monaco/vs/m3-CsR4AuFi.js +1 -0
  68. package/ui/monaco/vs/main-BEx-Fmlo.js +15 -0
  69. package/ui/monaco/vs/main-DsK8pnKg.js +3 -0
  70. package/ui/monaco/vs/markdown-C_rD0bIw.js +1 -0
  71. package/ui/monaco/vs/mdx-BcFcCtz9.js +1 -0
  72. package/ui/monaco/vs/mips-CiYP61RB.js +1 -0
  73. package/ui/monaco/vs/monaco.contribution-BuX2NvO2.js +1 -0
  74. package/ui/monaco/vs/monaco.contribution-C7tY_xnl.js +1 -0
  75. package/ui/monaco/vs/monaco.contribution-CY2lwFI8.js +1 -0
  76. package/ui/monaco/vs/monaco.contribution-D1-wBxcq.js +1 -0
  77. package/ui/monaco/vs/msdax-C38-sJlp.js +1 -0
  78. package/ui/monaco/vs/mysql-CdtbpvbG.js +1 -0
  79. package/ui/monaco/vs/nls/lang/de.js +9 -0
  80. package/ui/monaco/vs/nls/lang/es.js +9 -0
  81. package/ui/monaco/vs/nls/lang/fr.js +9 -0
  82. package/ui/monaco/vs/nls/lang/it.js +9 -0
  83. package/ui/monaco/vs/nls/lang/pt-br.js +9 -0
  84. package/ui/monaco/vs/nls/lang/ru.js +9 -0
  85. package/ui/monaco/vs/nls/lang/zh-cn.js +9 -0
  86. package/ui/monaco/vs/nls.messages-loader.js +1 -0
  87. package/ui/monaco/vs/objective-c-CntZFaHX.js +1 -0
  88. package/ui/monaco/vs/pascal-r6kuqfl_.js +1 -0
  89. package/ui/monaco/vs/pascaligo-BiXoTmXh.js +1 -0
  90. package/ui/monaco/vs/perl-DABw_TcH.js +1 -0
  91. package/ui/monaco/vs/pgsql-me_jFXeX.js +1 -0
  92. package/ui/monaco/vs/php-D_kh-9LK.js +1 -0
  93. package/ui/monaco/vs/pla-VfZjczW0.js +1 -0
  94. package/ui/monaco/vs/postiats-BBSzz8Pk.js +1 -0
  95. package/ui/monaco/vs/powerquery-Dt-g_2cc.js +1 -0
  96. package/ui/monaco/vs/powershell-B-7ap1zc.js +1 -0
  97. package/ui/monaco/vs/protobuf-BmtuEB1A.js +2 -0
  98. package/ui/monaco/vs/pug-BRpRNeEb.js +1 -0
  99. package/ui/monaco/vs/python-CasA8BlK.js +1 -0
  100. package/ui/monaco/vs/qsharp-BzsFaUU9.js +1 -0
  101. package/ui/monaco/vs/r-f8dDdrp4.js +1 -0
  102. package/ui/monaco/vs/razor-IGOwKAHu.js +1 -0
  103. package/ui/monaco/vs/redis-fvZQY4PI.js +1 -0
  104. package/ui/monaco/vs/redshift-45Et0LQi.js +1 -0
  105. package/ui/monaco/vs/restructuredtext-C7UUFKFD.js +1 -0
  106. package/ui/monaco/vs/ruby-CZO8zYTz.js +1 -0
  107. package/ui/monaco/vs/rust-Bfetafyc.js +1 -0
  108. package/ui/monaco/vs/sb-3GYllVck.js +1 -0
  109. package/ui/monaco/vs/scala-foMgrKo1.js +1 -0
  110. package/ui/monaco/vs/scheme-CHdMtr7p.js +1 -0
  111. package/ui/monaco/vs/scss-C1cmLt9V.js +3 -0
  112. package/ui/monaco/vs/shell-ClXCKCEW.js +1 -0
  113. package/ui/monaco/vs/solidity-MZ6ExpPy.js +1 -0
  114. package/ui/monaco/vs/sophia-DWkuSsPQ.js +1 -0
  115. package/ui/monaco/vs/sparql-AUGFYSyk.js +1 -0
  116. package/ui/monaco/vs/sql-32GpJSV2.js +1 -0
  117. package/ui/monaco/vs/st-CuDFIVZ_.js +1 -0
  118. package/ui/monaco/vs/swift-t-PfMj7W.js +1 -0
  119. package/ui/monaco/vs/systemverilog-Ch4vA8Yt.js +1 -0
  120. package/ui/monaco/vs/tcl-D74tq1nH.js +1 -0
  121. package/ui/monaco/vs/toggleHighContrast-DuqAmExZ.js +65 -0
  122. package/ui/monaco/vs/ts.worker-BLYAhMkX.js +1 -0
  123. package/ui/monaco/vs/tsMode-DB1GiNun.js +11 -0
  124. package/ui/monaco/vs/twig-C6taOxMV.js +1 -0
  125. package/ui/monaco/vs/typescript-BTLNeq8B.js +1 -0
  126. package/ui/monaco/vs/typespec-8OfoLt6R.js +1 -0
  127. package/ui/monaco/vs/vb-Dyb2648j.js +1 -0
  128. package/ui/monaco/vs/wgsl-BhLXMOR0.js +298 -0
  129. package/ui/monaco/vs/workers-BeMslOxK.js +1 -0
  130. package/ui/monaco/vs/xml-DHCggo_L.js +1 -0
  131. package/ui/monaco/vs/yaml-C-RIivnc.js +1 -0
  132. package/ui/terminal.js +328 -0
  133. package/ui/vendor/addon-fit.mjs +18 -0
  134. package/ui/vendor/xterm.css +285 -0
  135. package/ui/vendor/xterm.mjs +53 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bitpull",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
4
4
  "description": "BitPull (bitpull.cloud): share signed, AI-readable code, computing power and open AI models with AI tools through MCP. CLI and MCP server.",
5
5
  "mcpName": "io.github.SamuealPK/bitpull",
6
6
  "bin": {
@@ -8,7 +8,8 @@
8
8
  },
9
9
  "files": [
10
10
  "bitpull.cjs",
11
- "README.md"
11
+ "README.md",
12
+ "ui"
12
13
  ],
13
14
  "engines": {
14
15
  "node": ">=20"
@@ -0,0 +1,57 @@
1
+ // Plugs the terminal into the Projects editor: the bottom panel's "Terminal" tab, ⌘J/Ctrl+J, a shell in
2
+ // the project's folder, and the agent's commands shown read-only in an "Agent" tab. The agent never types
3
+ // into a shell: its commands run through the Projects path, with its approvals, and only appear here.
4
+ import { mountTerminal } from "./terminal.js";
5
+
6
+ function register() {
7
+ const ide = window.BitPullIDE;
8
+ if (!ide || !ide.terminal) return setTimeout(register, 50);
9
+ let host = null;
10
+ let opts = null;
11
+ let term = null;
12
+ let current = null;
13
+ const start = () => {
14
+ if (term || !host || !opts || !opts.folder) return;
15
+ term = mountTerminal(host, { cwd: opts.folder, token: opts.token, t: opts.t });
16
+ };
17
+ ide.terminal.register({
18
+ mount(container, o) {
19
+ host = container;
20
+ opts = { ...o };
21
+ },
22
+ open() {
23
+ start();
24
+ if (term) term.fit();
25
+ },
26
+ close() {
27
+ /* the panel hides it; shells keep running until the page closes */
28
+ },
29
+ newTab() {
30
+ start();
31
+ if (term) term.newTab();
32
+ },
33
+ runVisible(command) {
34
+ start();
35
+ current = term ? term.runVisible(command) : null;
36
+ return current;
37
+ },
38
+ agentOutput(text) {
39
+ if (current) current.write(String(text).replace(/\r?\n/g, "\r\n"));
40
+ },
41
+ agentDone(code) {
42
+ if (current) current.done(code);
43
+ current = null;
44
+ },
45
+ folderChanged(folder) {
46
+ if (!opts) return;
47
+ opts.folder = folder;
48
+ // A new folder is a new place to work: the old shells close, new ones open there.
49
+ if (term) {
50
+ term.dispose();
51
+ term = null;
52
+ start();
53
+ }
54
+ },
55
+ });
56
+ }
57
+ register();
package/ui/ide.css ADDED
@@ -0,0 +1,271 @@
1
+ /* BitPull projects: the layout and look of a modern code editor (VS Code conventions), BitPull's own icons. */
2
+ :root {
3
+ --surface: var(--bg); --bg: #1f1f1f; --side: #181818; --bar: #181818; --raised: #2a2d2e; --hover: #2a2d2e; --sel: #37373d; --sel-focus: #04395e;
4
+ --text: #cccccc; --bright: #e7e7e7; --muted: #9d9d9d; --faint: #6e7681; --line: #2b2b2b; --line2: #3c3c3c;
5
+ --accent: #0078d4; --accent-ink: #ffffff; --focus: #0078d4; --input: #313131;
6
+ --good: #73c991; --warn: #cca700; --bad: #f14c4c; --mod: #e2c08d; --new: #73c991; --del: #c74e39; --ign: #8c8c8c;
7
+ --guide: #585858; --tab: #181818; --tab-on: #1f1f1f;
8
+ --w-side: 260px; --w-agent: 380px; --s-panel: 240px;
9
+ color-scheme: dark;
10
+ }
11
+ @media (prefers-color-scheme: light) {
12
+ :root { --bg: #ffffff; --side: #f8f8f8; --bar: #f8f8f8; --raised: #f2f2f2; --hover: #f2f2f2; --sel: #e4e6f1; --sel-focus: #cce5ff;
13
+ --text: #3b3b3b; --bright: #1f1f1f; --muted: #6e6e6e; --faint: #8b8b8b; --line: #e5e5e5; --line2: #cecece;
14
+ --accent: #005fb8; --focus: #005fb8; --input: #ffffff; --good: #388a34; --warn: #bf8803; --bad: #e51400; --mod: #895503; --new: #388a34; --del: #ad0707; --ign: #8e8e90;
15
+ --guide: #cfcfcf; --tab: #f8f8f8; --tab-on: #ffffff; color-scheme: light; }
16
+ }
17
+ * { box-sizing: border-box; }
18
+ html, body { height: 100%; margin: 0; }
19
+ body { background: var(--bg); color: var(--text); font: 13px/1.4 -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, "Noto Sans", sans-serif; overflow: hidden; }
20
+ [hidden] { display: none !important; }
21
+ .grow { flex: 1 1 auto; min-width: 0; }
22
+ .muted { color: var(--muted); }
23
+ .small { font-size: 12px; }
24
+ .pad { padding: 6px 12px; }
25
+ .row { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; margin-top: 8px; }
26
+ .row.end { justify-content: flex-end; }
27
+ a { color: var(--accent); }
28
+
29
+ /* ---- icons: drawn in the page, coloured by their text colour ---- */
30
+ svg.i { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; display: block; flex: none; }
31
+ svg.f { width: 16px; height: 16px; display: block; flex: none; }
32
+
33
+ /* ---- buttons ---- */
34
+ :where(#ide, #modal, #menu) button { font: inherit; color: inherit; cursor: pointer; }
35
+ :where(#ide, #modal) button:focus-visible, :where(#ide, #modal) input:focus-visible, :where(#ide, #modal) select:focus-visible, :where(#ide, #modal) textarea:focus-visible, .item:focus-visible { outline: 1px solid var(--focus); outline-offset: -1px; }
36
+ button.primary, #modal button.primary { background: var(--accent); color: var(--accent-ink); border: 1px solid transparent; border-radius: 4px; padding: 4px 12px; }
37
+ button.primary:hover { filter: brightness(1.1); }
38
+ button.ghost { background: transparent; border: 1px solid var(--line2); border-radius: 4px; padding: 4px 10px; color: var(--text); }
39
+ button.ghost:hover { background: var(--hover); }
40
+ button.danger, #modal button.danger { background: var(--bad); color: #fff; border: 0; border-radius: 4px; padding: 4px 12px; }
41
+ button.ib { background: transparent; border: 0; border-radius: 5px; width: 22px; height: 22px; display: inline-flex; align-items: center; justify-content: center; padding: 0; color: var(--text); }
42
+ button.ib:hover { background: var(--hover); }
43
+ button.ib.danger { color: var(--bad); background: transparent; }
44
+ button:disabled { opacity: .5; cursor: default; }
45
+ button.wide { width: 100%; display: flex; gap: 6px; justify-content: center; align-items: center; padding: 5px 10px; }
46
+
47
+ /* ---- form fields ---- */
48
+ :where(#ide, #modal) :is(input[type=text], input[type=number], select, textarea) { background: var(--input); color: var(--bright); border: 1px solid var(--line2); border-radius: 4px; padding: 4px 6px; font: inherit; min-width: 0; }
49
+ :where(#ide, #modal) textarea { width: 100%; resize: none; }
50
+ .field { display: flex; align-items: center; gap: 4px; background: var(--input); border: 1px solid var(--line2); border-radius: 4px; padding: 0 4px; }
51
+ .field:focus-within { border-color: var(--focus); }
52
+ .field input[type=text] { border: 0 !important; background: transparent !important; flex: 1; padding: 4px 2px !important; outline: none; }
53
+ .field .opt { display: inline-flex; align-items: center; border-radius: 3px; padding: 0 3px; color: var(--muted); cursor: pointer; font-size: 12px; }
54
+ .field .opt input { position: absolute; opacity: 0; pointer-events: none; }
55
+ .field .opt:has(input:checked) { background: var(--sel-focus); color: var(--bright); outline: 1px solid var(--focus); }
56
+ .field svg.i { color: var(--muted); }
57
+
58
+ /* ---- the frame ---- */
59
+ #ide { display: grid; grid-template-rows: 35px minmax(0, 1fr) 22px; height: 100%; }
60
+ #titlebar { display: flex; align-items: center; gap: 2px; padding: 0 6px; background: var(--bar); border-bottom: 1px solid var(--line); min-width: 0; }
61
+ button.tb { background: transparent; border: 0; border-radius: 5px; height: 26px; min-width: 26px; padding: 0 6px; display: inline-flex; align-items: center; gap: 5px; color: var(--text); }
62
+ button.tb:hover, button.tb.on { background: var(--hover); }
63
+ button.tb.folder { font-weight: 600; max-width: 260px; }
64
+ #folder-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
65
+ button.tb.search { width: min(520px, 46vw); justify-content: center; border: 1px solid var(--line2); background: var(--input); height: 24px; }
66
+ button.tb.search span.muted { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
67
+
68
+ #workbench { display: grid; min-height: 0; min-width: 0; overflow: hidden; }
69
+ #activity { grid-area: act; display: flex; flex-direction: column; align-items: center; gap: 2px; padding-top: 4px; background: var(--side); border-inline-end: 1px solid var(--line); }
70
+ #activity button { position: relative; background: transparent; border: 0; width: 48px; height: 44px; display: flex; align-items: center; justify-content: center; color: var(--faint); }
71
+ #activity button svg.i { width: 22px; height: 22px; stroke-width: 1.4; }
72
+ #activity button:hover, #activity button.on { color: var(--bright); }
73
+ #activity button.on::before { content: ""; position: absolute; inset-inline-start: 0; top: 0; bottom: 0; width: 2px; background: var(--accent); }
74
+ #side { grid-area: side; background: var(--side); overflow: hidden; display: flex; flex-direction: column; min-width: 0; border-inline-end: 1px solid var(--line); }
75
+ #side > section { display: flex; flex-direction: column; min-height: 0; flex: 1; overflow: auto; }
76
+ #editor-area { grid-area: edit; display: flex; flex-direction: column; min-width: 0; min-height: 0; background: var(--bg); }
77
+ #panel { grid-area: panel; display: flex; flex-direction: column; min-width: 0; min-height: 0; background: var(--bg); border-top: 1px solid var(--line); }
78
+ #panel.at-left, #panel.at-right { border-top: 0; border-inline-start: 1px solid var(--line); }
79
+ #panel.at-top { border-top: 0; border-bottom: 1px solid var(--line); }
80
+ #agent { grid-area: agent; display: flex; flex-direction: column; min-width: 0; min-height: 0; background: var(--side); border-inline-start: 1px solid var(--line); }
81
+ .sash { position: relative; z-index: 4; }
82
+ .sash[data-split="side"] { grid-area: s1; }
83
+ .sash[data-split="panel"] { grid-area: s2; }
84
+ .sash[data-split="agent"] { grid-area: s3; }
85
+ .sash.v { cursor: col-resize; }
86
+ .sash.h { cursor: row-resize; }
87
+ .sash::after { content: ""; position: absolute; inset: 0; margin: -2px; }
88
+ .sash:hover::after, .sash.drag::after { background: var(--focus); opacity: .8; margin: 0; }
89
+ .sash.v:hover::after, .sash.v.drag::after { inset-inline: -1px; }
90
+ .sash.h:hover::after, .sash.h.drag::after { inset-block: -1px; }
91
+
92
+ /* ---- side bar ---- */
93
+ .view-title { display: flex; align-items: center; height: 35px; padding: 0 8px 0 20px; font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); flex: none; }
94
+ .pane { display: flex; flex-direction: column; min-height: 0; border-top: 1px solid var(--line); flex: none; }
95
+ .pane:first-of-type { border-top: 0; }
96
+ .pane.open { flex: 1 1 0; }
97
+ .pane-head { display: flex; align-items: center; gap: 2px; height: 22px; padding-inline: 2px 6px; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .02em; color: var(--text); cursor: pointer; user-select: none; flex: none; }
98
+ .pane-head .twist { color: var(--text); transition: transform .1s; }
99
+ .pane.open .pane-head .twist { transform: rotate(90deg); }
100
+ :dir(rtl) .pane-head .twist { transform: scaleX(-1); }
101
+ :dir(rtl) .pane.open .pane-head .twist { transform: rotate(90deg); }
102
+ .pane-acts { display: none; gap: 2px; }
103
+ .pane-head:hover .pane-acts, .pane:focus-within .pane-acts { display: inline-flex; }
104
+ .pane-body { overflow: auto; min-height: 0; flex: 1; display: none; }
105
+ .pane.open .pane-body { display: block; }
106
+ .pane-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
107
+ .sub-head { padding: 6px 12px 2px; font-size: 11px; font-weight: 700; text-transform: uppercase; color: var(--muted); }
108
+
109
+ /* ---- lists and the tree ---- */
110
+ #ide ul.list, #ide ul.tree, #modal ul.list, #menu ul { list-style: none; margin: 0; padding: 0; }
111
+ ul.list li { display: flex; gap: 6px; align-items: center; height: 22px; padding: 0 12px; cursor: pointer; white-space: nowrap; overflow: hidden; }
112
+ ul.list li .name { overflow: hidden; text-overflow: ellipsis; }
113
+ ul.list li:hover { background: var(--hover); }
114
+ ul.list li.on { background: var(--sel); }
115
+ ul.tree ul { list-style: none; margin: 0; padding: 0; }
116
+ ul.tree .item { position: relative; display: flex; align-items: center; gap: 4px; height: 22px; padding-inline-end: 8px; cursor: pointer; white-space: nowrap; color: var(--text); }
117
+ ul.tree .item:hover { background: var(--hover); }
118
+ ul.tree .item.on { background: var(--sel); }
119
+ #side:focus-within ul.tree .item.on { background: var(--sel-focus); outline: 1px solid var(--focus); outline-offset: -1px; }
120
+ ul.tree .item .twist { width: 16px; color: var(--text); flex: none; }
121
+ ul.tree .item.open .twist svg { transform: rotate(90deg); }
122
+ :dir(rtl) ul.tree .item .twist svg { transform: scaleX(-1); }
123
+ :dir(rtl) ul.tree .item.open .twist svg { transform: rotate(90deg); }
124
+ ul.tree .item .name { overflow: hidden; text-overflow: ellipsis; }
125
+ ul.tree .item .git { margin-inline-start: auto; font-size: 11px; font-weight: 600; padding-inline-start: 6px; }
126
+ ul.tree .item.dot .name, ul.tree .item.ignored .name { color: var(--ign); }
127
+ ul.tree .item.ignored svg.f { opacity: .55; }
128
+ ul.tree .item.git-M .name, ul.tree .item.git-M .git { color: var(--mod); }
129
+ ul.tree .item.git-U .name, ul.tree .item.git-U .git, ul.tree .item.git-A .name, ul.tree .item.git-A .git { color: var(--new); }
130
+ ul.tree .item.git-D .name, ul.tree .item.git-D .git { color: var(--del); }
131
+ ul.tree .item .acts { display: none; gap: 1px; margin-inline-start: 4px; }
132
+ ul.tree .item:hover .acts { display: inline-flex; }
133
+ ul.tree .item:hover .git { display: none; }
134
+ .guide { position: absolute; top: 0; bottom: 0; width: 1px; background: transparent; }
135
+ #side:hover .guide { background: var(--guide); opacity: .45; }
136
+ .badge { font-size: 11px; padding: 0 6px; border-radius: 9px; background: var(--raised); color: var(--muted); flex: none; }
137
+ .badge.bad { color: var(--bad); } .badge.warn { color: var(--warn); } .badge.good { color: var(--good); }
138
+ .count { font-size: 11px; min-width: 18px; padding: 0 5px; border-radius: 9px; background: var(--raised); color: var(--text); text-align: center; }
139
+
140
+ /* ---- editor area ---- */
141
+ #tabs-row { display: flex; align-items: stretch; height: 35px; background: var(--tab); border-bottom: 1px solid var(--line); flex: none; }
142
+ #tabs { display: flex; overflow-x: auto; overflow-y: hidden; flex: 1; scrollbar-width: none; }
143
+ #tabs .tab { display: flex; gap: 6px; align-items: center; padding: 0 6px 0 10px; border-inline-end: 1px solid var(--line); cursor: pointer; white-space: nowrap; color: var(--muted); min-width: 0; position: relative; background: var(--tab); }
144
+ #tabs .tab:hover { color: var(--text); }
145
+ #tabs .tab.on { color: var(--bright); background: var(--tab-on); }
146
+ #tabs .tab.on::after { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 1px; background: var(--accent); }
147
+ #tabs .tab .x { width: 20px; height: 20px; border: 0; background: transparent; border-radius: 4px; display: inline-flex; align-items: center; justify-content: center; visibility: hidden; padding: 0; color: inherit; }
148
+ #tabs .tab:hover .x, #tabs .tab.on .x { visibility: visible; }
149
+ #tabs .tab .x:hover { background: var(--hover); }
150
+ #tabs .tab.dirty .x { visibility: visible; }
151
+ #tabs .tab.dirty .x svg { display: none; }
152
+ #tabs .tab.dirty .x::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: currentColor; }
153
+ #tabs .tab.dirty .x:hover svg { display: block; }
154
+ #tabs .tab.dirty .x:hover::before { display: none; }
155
+ .tabs-acts { display: flex; align-items: center; gap: 2px; padding: 0 6px; }
156
+ #crumbs { display: flex; align-items: center; gap: 2px; height: 22px; padding: 0 12px; font-size: 12.5px; white-space: nowrap; overflow: hidden; flex: none; }
157
+ #crumbs span.sep { opacity: .7; }
158
+ #crumbs .c { cursor: default; display: inline-flex; align-items: center; gap: 4px; }
159
+ #crumbs span.sep { display: inline-flex; }
160
+ #crumbs svg { width: 14px; height: 14px; }
161
+ #crumbs .c:last-child { color: var(--text); }
162
+ #review { display: flex; gap: 6px; align-items: center; padding: 4px 10px; border-bottom: 1px solid var(--line); background: var(--side); flex-wrap: wrap; flex: none; }
163
+ #editor-wrap { position: relative; flex: 1 1 auto; min-height: 0; display: flex; overflow: hidden; }
164
+ #editor, #editor2 { position: relative; flex: 1 1 0; min-width: 0; height: 100%; overflow: hidden; }
165
+ #editor2 { border-inline-start: 1px solid var(--line); }
166
+ #diff { position: absolute; inset: 0; }
167
+ #welcome { position: absolute; inset: 0; overflow: auto; display: flex; align-items: center; justify-content: center; background: var(--bg); }
168
+ .welcome-box { max-width: 560px; padding: 24px; text-align: center; }
169
+ .welcome-box .logo { color: var(--line2); display: flex; justify-content: center; margin-bottom: 8px; }
170
+ .welcome-box .logo svg.i { width: 96px; height: 96px; stroke-width: .8; }
171
+ .welcome-box h2 { font-weight: 400; color: var(--text); margin: 6px 0; font-size: 20px; }
172
+ table.keys { margin: 18px auto 0; border-collapse: collapse; color: var(--muted); }
173
+ table.keys td { padding: 4px 10px; text-align: start; }
174
+ table.keys td:last-child { text-align: end; }
175
+ kbd { font: 11px ui-monospace, Menlo, Consolas, monospace; background: var(--raised); border: 1px solid var(--line2); border-bottom-width: 2px; border-radius: 3px; padding: 1px 5px; margin-inline: 1px; color: var(--text); }
176
+
177
+ /* ---- panel ---- */
178
+ .panel-head { display: flex; align-items: center; height: 35px; padding: 0 8px; flex: none; }
179
+ .ptabs { display: flex; align-items: center; gap: 4px; min-width: 0; overflow: hidden; }
180
+ .ptabs button[data-bottom] { background: transparent; border: 0; padding: 0 8px; height: 26px; display: inline-flex; align-items: center; gap: 5px; color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: .02em; position: relative; }
181
+ .ptabs button[data-bottom]:hover { color: var(--text); }
182
+ .ptabs button[data-bottom].on { color: var(--bright); }
183
+ .ptabs button[data-bottom].on::after { content: ""; position: absolute; left: 8px; right: 8px; bottom: -4px; height: 1px; background: var(--bright); }
184
+ #panel:not(.icons) .ptabs .pic { display: none; }
185
+ .pacts { display: flex; gap: 2px; }
186
+ .panel-body { flex: 1; min-height: 0; position: relative; }
187
+ .panel-body > div[data-bpanel] { position: absolute; inset: 0; overflow: auto; }
188
+ #output { margin: 0; padding: 4px 16px; white-space: pre-wrap; font: 12px/1.45 ui-monospace, Menlo, Consolas, monospace; direction: ltr; text-align: left; }
189
+ #terminal-host { position: absolute; inset: 0; }
190
+ #problems li { height: 22px; }
191
+ table.grid { width: 100%; border-collapse: collapse; font-size: 12.5px; }
192
+ table.grid th { text-align: start; font-weight: 600; color: var(--muted); padding: 4px 12px; border-bottom: 1px solid var(--line); }
193
+ table.grid td { padding: 3px 12px; border-bottom: 1px solid var(--line); }
194
+ table.grid tr:hover td { background: var(--hover); }
195
+
196
+ /* the terminal, with icon buttons like an editor's */
197
+ .bp-term { background: var(--bg) !important; }
198
+ .bp-term .xterm, .bp-term .xterm-viewport, .bp-term .xterm-screen, .bp-term-pane { background: var(--bg) !important; }
199
+ .bp-term-bar button.ib { padding: 0 !important; width: 24px; height: 22px; display: inline-flex; align-items: center; justify-content: center; border: 0 !important; }
200
+ .bp-term-bar button.ib:hover { background: var(--hover); }
201
+ .bp-term-bar { border-bottom: 0 !important; padding: 0 8px 0 12px !important; height: 28px; flex-direction: row-reverse; }
202
+ .bp-term-bar .bp-tabs { justify-content: flex-start; }
203
+ .bp-term-bar button { font-size: 12px !important; padding: 2px 8px !important; }
204
+ .bp-term-pane { padding: 2px 0 0 14px !important; }
205
+
206
+ /* ---- agent ---- */
207
+ .agent-top { padding: 8px; display: flex; flex-direction: column; gap: 6px; border-bottom: 1px solid var(--line); flex: none; }
208
+ ul.list.agents { max-height: 150px; overflow: auto; }
209
+ ul.list.agents li { padding: 0 6px; border-radius: 4px; }
210
+ .agent-title { padding: 6px 12px 0; }
211
+ #agent-log { flex: 1; overflow: auto; display: flex; flex-direction: column; gap: 10px; padding: 8px 12px; min-height: 0; }
212
+ .ev { white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.5; }
213
+ .ev.user { background: var(--input); border: 1px solid var(--line2); padding: 6px 10px; border-radius: 6px; }
214
+ .ev.action, .ev.notice { color: var(--muted); font-size: 12px; display: flex; gap: 6px; align-items: center; }
215
+ .ev.error { color: var(--bad); }
216
+ .ev.output { font: 11.5px/1.4 ui-monospace, Menlo, Consolas, monospace; background: var(--bg); border: 1px solid var(--line); border-radius: 4px; padding: 6px 8px; max-height: 180px; overflow: auto; direction: ltr; text-align: left; }
217
+ #agent-pending, #agent-limit { margin: 0 12px 8px; border: 1px solid var(--focus); border-radius: 6px; padding: 10px; background: var(--bg); }
218
+ #agent-limit { border-color: var(--warn); }
219
+ #agent-pending code, .code { font: 12px/1.4 ui-monospace, Menlo, Consolas, monospace; background: var(--input); padding: 6px 8px; border-radius: 4px; display: block; white-space: pre-wrap; overflow-wrap: anywhere; direction: ltr; text-align: left; margin: 6px 0; }
220
+ #agent-changes { padding: 0 12px; }
221
+ #agent-status { padding: 2px 12px 6px; }
222
+ #composer { position: relative; margin: 0 8px 8px; border: 1px solid var(--line2); border-radius: 8px; background: var(--input); padding: 6px; }
223
+ #composer:focus-within { border-color: var(--focus); }
224
+ #composer textarea { border: 0 !important; background: transparent !important; outline: none; padding: 2px 4px !important; min-height: 52px; max-height: 240px; }
225
+ .composer-bar { display: flex; align-items: center; gap: 4px; }
226
+ .composer-bar select { border: 0 !important; background: transparent !important; color: var(--muted) !important; font-size: 12px !important; padding: 2px 4px !important; max-width: 46%; }
227
+ .composer-bar select:hover { color: var(--text) !important; background: var(--hover) !important; }
228
+ button.send { width: 26px; height: 26px; border-radius: 50%; border: 0; background: var(--bright); color: var(--bg); display: inline-flex; align-items: center; justify-content: center; padding: 0; }
229
+ button.send:disabled { opacity: .35; }
230
+ #mode-hint { padding: 4px 4px 0; }
231
+ #mode-hint.auto { color: var(--warn); }
232
+ .popup { position: absolute; bottom: 100%; inset-inline: 0; max-height: 220px; overflow: auto; background: var(--side); border: 1px solid var(--line2); border-radius: 6px; box-shadow: 0 4px 16px rgba(0,0,0,.35); z-index: 5; margin-bottom: 4px; }
233
+
234
+ /* ---- status bar ---- */
235
+ #statusbar { display: flex; align-items: center; gap: 2px; padding: 0 6px; background: var(--bar); border-top: 1px solid var(--line); font-size: 12px; color: var(--muted); min-width: 0; overflow: hidden; }
236
+ .sb { display: inline-flex; align-items: center; gap: 4px; height: 22px; padding: 0 6px; white-space: nowrap; background: transparent; border: 0; color: inherit; font: inherit; }
237
+ button.sb:hover { background: var(--hover); color: var(--text); }
238
+ .sb svg.i { width: 14px; height: 14px; }
239
+ #sb-mode.auto { color: var(--warn); }
240
+
241
+ /* ---- menus, modal, tooltip ---- */
242
+ .menu { position: fixed; z-index: 40; min-width: 200px; max-width: 360px; background: var(--side); border: 1px solid var(--line2); border-radius: 6px; padding: 4px; box-shadow: 0 6px 24px rgba(0,0,0,.4); }
243
+ .menu li { display: flex; align-items: center; gap: 8px; height: 26px; padding: 0 8px; border-radius: 4px; cursor: pointer; white-space: nowrap; }
244
+ .menu li:hover, .menu li.on { background: var(--sel-focus); color: var(--bright); }
245
+ .menu li .check { width: 14px; }
246
+ .menu li .keys { margin-inline-start: auto; color: var(--muted); font-size: 12px; padding-inline-start: 16px; }
247
+ .menu li.sep { height: 1px; padding: 0; margin: 4px 2px; background: var(--line2); cursor: default; }
248
+ .menu li.head { cursor: default; color: var(--muted); font-size: 11px; text-transform: uppercase; height: 22px; }
249
+ .menu li.head:hover { background: transparent; color: var(--muted); }
250
+ #modal { position: fixed; inset: 0; background: rgba(0,0,0,.35); display: flex; align-items: flex-start; justify-content: center; padding-top: 8vh; z-index: 30; }
251
+ #modal .box { background: var(--side); border: 1px solid var(--line2); border-radius: 8px; padding: 14px; width: min(620px, calc(100% - 32px)); max-height: 80vh; overflow: auto; box-shadow: 0 8px 32px rgba(0,0,0,.45); }
252
+ #modal h3 { margin: 0 0 8px; font-size: 14px; font-weight: 600; color: var(--bright); }
253
+ #modal input[type=text], #modal textarea { width: 100%; }
254
+ #modal ul.list li { border-radius: 4px; padding: 0 8px; }
255
+ #modal ul.list li.on { background: var(--sel-focus); }
256
+ #modal ul.list li .keys { margin-inline-start: auto; color: var(--muted); font-size: 12px; }
257
+ #modal dl { margin: 0; } #modal dt { font-weight: 600; margin-top: 8px; } #modal dd { margin: 2px 0 0; color: var(--muted); }
258
+ #modal button { padding: 4px 12px; border-radius: 4px; border: 1px solid var(--line2); background: transparent; }
259
+ #tip { position: fixed; z-index: 50; max-width: 320px; background: var(--side); color: var(--text); border: 1px solid var(--line2); padding: 4px 8px; border-radius: 4px; font-size: 12px; pointer-events: none; box-shadow: 0 2px 8px rgba(0,0,0,.3); }
260
+
261
+ /* ---- a narrow window: one column that scrolls ---- */
262
+ #ide.narrow #workbench { overflow-y: auto; overflow-x: hidden; }
263
+ #ide.narrow .sash { display: none; }
264
+ #ide.narrow #activity { flex-direction: row; justify-content: flex-start; padding: 0 4px; border-inline-end: 0; border-bottom: 1px solid var(--line); }
265
+ #ide.narrow #activity button { height: 36px; width: 40px; }
266
+ #ide.narrow #activity button.on::before { top: auto; bottom: 0; left: 6px; right: 6px; width: auto; height: 2px; }
267
+ #ide.narrow button.tb.search { width: auto; flex: 1; }
268
+ #ide.narrow #palette-label { display: none; }
269
+
270
+ /* Monaco draws long lines under the minimap, whose canvas is slightly transparent: a solid ground hides them. */
271
+ .monaco-editor .minimap { background: var(--bg); }
package/ui/ide.html ADDED
@@ -0,0 +1,178 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>BitPull · Projects</title>
7
+ <link rel="icon" href="data:,">
8
+ <script>
9
+ // The token stays in the address's fragment, which never reaches a server. With it the page asks the app
10
+ // for a cookie that opens its own files (the editor), then loads them.
11
+ (function () {
12
+ var p = new URLSearchParams(location.hash.slice(1));
13
+ window.__BITPULL__ = { token: p.get("token") || "", lang: p.get("lang") || "", folder: p.get("folder") || "" };
14
+ fetch("/api/ui/session", { method: "POST", headers: { "x-bitpull-token": window.__BITPULL__.token } }).then(function (r) {
15
+ if (!r.ok) { document.body.textContent = "BitPull: open this page from the app."; return; }
16
+ // Monaco's own stylesheet: without it the editor has no gutter and draws its minimap anywhere.
17
+ ["/ui/monaco/vs/editor/editor.main.css", "/ui/ide.css"].forEach(function (href) {
18
+ var css = document.createElement("link");
19
+ css.rel = "stylesheet";
20
+ css.href = href;
21
+ document.head.appendChild(css);
22
+ });
23
+ var s = document.createElement("script");
24
+ s.src = "/ui/ide.js";
25
+ document.body.appendChild(s);
26
+ var term = document.createElement("script");
27
+ term.type = "module";
28
+ term.src = "/ui/ide-terminal.js";
29
+ document.body.appendChild(term);
30
+ });
31
+ })();
32
+ </script>
33
+ </head>
34
+ <body>
35
+ <div id="ide" hidden>
36
+ <header id="titlebar">
37
+ <button class="tb" id="back" data-tip="tip.ide.back" data-icon="back"></button>
38
+ <button class="tb folder" id="folder-btn" data-tip="tip.pj.folder"><span data-icon="folder"></span><span id="folder-name"></span><span data-icon="chevron-down"></span></button>
39
+ <select id="folder" hidden></select>
40
+ <div class="grow"></div>
41
+ <button class="tb search" id="palette-btn" data-tip="tip.ide.palette"><span data-icon="search"></span><span id="palette-label" class="muted"></span></button>
42
+ <div class="grow"></div>
43
+ <button class="tb" id="toggle-side" data-tip="tip.ide.toggle.side" data-icon="layout-left"></button>
44
+ <button class="tb" id="toggle-panel" data-tip="tip.ide.toggle.panel" data-icon="layout-bottom"></button>
45
+ <button class="tb" id="toggle-agent" data-tip="tip.ide.toggle.agent" data-icon="layout-right"></button>
46
+ <button class="tb" id="settings-btn" data-tip="tip.ide.settings" data-icon="gear"></button>
47
+ </header>
48
+ <div id="workbench">
49
+ <nav id="activity">
50
+ <button data-side="files" class="on" data-tip="tip.ide.files" data-icon="files"></button>
51
+ <button data-side="search" data-tip="tip.ide.search" data-icon="search"></button>
52
+ <button data-side="git" data-tip="tip.ide.git" data-icon="git"></button>
53
+ <button id="views-more" data-tip="tip.ide.views" data-icon="chevron-down"></button>
54
+ </nav>
55
+ <aside id="side">
56
+ <section data-panel="files">
57
+ <div class="view-title"><span data-i18n="ide.explorer"></span></div>
58
+ <div class="pane open" data-pane="tree">
59
+ <div class="pane-head"><span data-icon="chevron-right" class="twist"></span><span id="tree-title" class="pane-name"></span><span class="grow"></span>
60
+ <span class="pane-acts"><button class="ib" id="new-file" data-tip="tip.ide.new_file" data-icon="new-file"></button><button class="ib" id="new-dir" data-tip="tip.ide.new_dir" data-icon="new-folder"></button><button class="ib" id="refresh" data-tip="tip.ide.refresh" data-icon="refresh"></button><button class="ib" id="collapse-all" data-tip="tip.ide.collapse" data-icon="collapse"></button></span></div>
61
+ <div class="pane-body"><ul id="tree" class="tree" role="tree"></ul></div>
62
+ </div>
63
+ <div class="pane" data-pane="outline">
64
+ <div class="pane-head"><span data-icon="chevron-right" class="twist"></span><span class="pane-name" data-i18n="ide.outline"></span></div>
65
+ <div class="pane-body"><ul id="outline" class="list"></ul></div>
66
+ </div>
67
+ <div class="pane" data-pane="history">
68
+ <div class="pane-head"><span data-icon="chevron-right" class="twist"></span><span class="pane-name" data-i18n="ide.history"></span></div>
69
+ <div class="pane-body"><p class="muted small pad" data-i18n="ide.history.hint"></p><ul id="history" class="list"></ul></div>
70
+ </div>
71
+ </section>
72
+ <section data-panel="search" hidden>
73
+ <div class="view-title"><span data-i18n="ide.search"></span></div>
74
+ <div class="pad">
75
+ <div class="field"><input type="text" id="search-q" data-i18n-placeholder="ide.search.placeholder"><label class="opt" data-tip="tip.ide.search.case"><input type="checkbox" id="search-case"><span>Aa</span></label><label class="opt" data-tip="tip.ide.search.regex"><input type="checkbox" id="search-regex"><span>.*</span></label></div>
76
+ <div id="search-info" class="muted small"></div>
77
+ </div>
78
+ <ul id="search-results" class="list"></ul>
79
+ </section>
80
+ <section data-panel="git" hidden>
81
+ <div class="view-title"><span data-i18n="ide.git"></span><span class="grow"></span><button class="ib" id="git-refresh" data-tip="tip.ide.refresh" data-icon="refresh"></button></div>
82
+ <div class="pad">
83
+ <div id="git-branch" class="muted small"></div>
84
+ <textarea id="git-message" rows="2" data-i18n-placeholder="ide.git.message"></textarea>
85
+ <div class="row"><button class="primary grow" id="git-commit" data-i18n="ide.git.commit" data-tip="tip.ide.git.commit"></button><button class="ghost" id="git-push" data-i18n="ide.git.push" data-tip="tip.ide.git.push"></button></div>
86
+ </div>
87
+ <div class="sub-head" data-i18n="ide.git.staged"></div>
88
+ <ul id="git-staged" class="list"></ul>
89
+ <div class="sub-head" data-i18n="ide.git.changes"></div>
90
+ <ul id="git-changes" class="list"></ul>
91
+ <div id="git-msg" class="muted small pad"></div>
92
+ </section>
93
+ <section data-panel="outline" hidden>
94
+ <div class="view-title"><span data-i18n="ide.outline"></span></div>
95
+ <ul id="outline-view" class="list"></ul>
96
+ </section>
97
+ <section data-panel="history" hidden>
98
+ <div class="view-title"><span data-i18n="ide.history"></span></div>
99
+ <ul id="history-view" class="list"></ul>
100
+ </section>
101
+ </aside>
102
+ <div class="sash" data-split="side" data-tip="tip.ide.resize"></div>
103
+ <main id="editor-area">
104
+ <div id="tabs-row"><div id="tabs" role="tablist"></div><div class="tabs-acts"><button class="ib" id="split-editor" data-tip="tip.ide.split" data-icon="split"></button><button class="ib" id="editor-more" data-tip="tip.ide.more" data-icon="more"></button></div></div>
105
+ <div id="crumbs" class="muted"></div>
106
+ <div id="review" hidden>
107
+ <span id="review-title"></span><span class="grow"></span>
108
+ <span id="review-hunks"></span>
109
+ <button class="primary" id="review-accept" data-tip="tip.ide.review.accept"></button>
110
+ <button class="ghost" id="review-reject" data-tip="tip.ide.review.reject"></button>
111
+ <button class="ghost" id="review-close" data-i18n="ide.close" data-tip="tip.ide.close"></button>
112
+ </div>
113
+ <div id="editor-wrap">
114
+ <div id="editor" dir="ltr"></div>
115
+ <div id="editor2" dir="ltr" hidden></div>
116
+ <div id="diff" dir="ltr" hidden></div>
117
+ <div id="welcome"><div class="welcome-box"><div class="logo" data-icon="logo"></div><h2 data-i18n="ide.welcome"></h2><p class="muted" data-i18n="ide.welcome.text"></p><table id="keys" class="keys"></table></div></div>
118
+ </div>
119
+ </main>
120
+ <div class="sash" data-split="panel" data-tip="tip.ide.resize"></div>
121
+ <section id="panel">
122
+ <div class="panel-head">
123
+ <div class="ptabs"><button data-bottom="problems" class="on" data-tip="tip.ide.problems"><span data-icon="problems" class="pic"></span><span data-i18n="ide.problems"></span><span id="problems-count" class="count" hidden></span></button><button data-bottom="output" data-tip="tip.ide.output"><span data-icon="output" class="pic"></span><span data-i18n="ide.output"></span></button><button data-bottom="terminal" data-tip="tip.ide.terminal"><span data-icon="terminal" class="pic"></span><span data-i18n="pj.tab.terminal"></span></button><button data-bottom="ports" data-tip="tip.ide.ports" hidden><span data-icon="ports" class="pic"></span><span data-i18n="ide.ports"></span><span id="ports-count" class="count" hidden></span></button><button class="ib" id="panel-more" data-tip="tip.ide.panel.more" data-icon="more"></button></div>
124
+ <span class="grow"></span>
125
+ <div class="pacts"><button class="ib" id="problems-run" data-tip="tip.ide.problems.run" data-icon="play"></button><button class="ib" id="panel-max" data-tip="tip.ide.panel.max" data-icon="maximize"></button><button class="ib" id="bottom-close" data-tip="tip.ide.close" data-icon="close"></button></div>
126
+ </div>
127
+ <div class="panel-body">
128
+ <div data-bpanel="problems"><ul id="problems" class="list"></ul></div>
129
+ <div data-bpanel="output" hidden><pre id="output"></pre></div>
130
+ <div data-bpanel="terminal" hidden><div id="terminal-host"></div></div>
131
+ <div data-bpanel="ports" hidden><table id="ports" class="grid"><thead><tr><th data-i18n="ide.ports.port"></th><th data-i18n="ide.ports.address"></th><th data-i18n="ide.ports.process"></th><th></th></tr></thead><tbody></tbody></table><p id="ports-empty" class="muted small pad" data-i18n="ide.ports.none"></p></div>
132
+ </div>
133
+ </section>
134
+ <div class="sash" data-split="agent" data-tip="tip.ide.resize"></div>
135
+ <aside id="agent">
136
+ <div class="agent-top">
137
+ <div class="field"><span data-icon="search"></span><input type="text" id="agents-q" data-i18n-placeholder="ide.agents.search"></div>
138
+ <button class="ghost wide" id="agent-new" data-tip="tip.ide.agent.new"><span data-icon="plus"></span><span data-i18n="ide.agent.new"></span></button>
139
+ <ul id="agents-list" class="list agents"></ul>
140
+ </div>
141
+ <div class="agent-title"><span id="agents-toggle" class="muted small"></span></div>
142
+ <div id="agent-log"></div>
143
+ <div id="agent-pending" hidden></div>
144
+ <div id="agent-limit" hidden><strong data-i18n="ide.limit.title"></strong><p id="agent-limit-text" class="small"></p>
145
+ <div class="row"><button class="primary" id="limit-go" data-i18n="ide.limit.go" data-tip="tip.pj.continue"></button><button class="ghost" id="limit-stop" data-i18n="ide.limit.stop" data-tip="tip.pj.stop"></button><button class="ghost" id="limit-edit" data-i18n="ide.limit.edit" data-tip="tip.pj.limits"></button></div></div>
146
+ <div id="agent-changes" class="small"></div>
147
+ <div id="agent-status" class="muted small"></div>
148
+ <div id="composer">
149
+ <ul id="mention" class="list popup" hidden></ul>
150
+ <textarea id="prompt" rows="3" data-i18n-placeholder="ide.prompt.placeholder"></textarea>
151
+ <div class="composer-bar">
152
+ <select id="model" data-tip="tip.pj.model"></select>
153
+ <select id="mode" data-tip="tip.ide.mode"><option value="ask" data-i18n="pj.mode.ask"></option><option value="edits" data-i18n="pj.mode.edits"></option><option value="auto" data-i18n="pj.mode.auto"></option></select>
154
+ <span class="grow"></span>
155
+ <button class="ib" id="agent-undo" data-tip="tip.pj.undo" data-icon="undo" hidden></button>
156
+ <button class="ib danger" id="agent-stop" data-tip="tip.pj.stop" data-icon="stop" hidden></button>
157
+ <button class="send" id="agent-send" data-tip="tip.pj.send" data-icon="send"></button>
158
+ </div>
159
+ <div id="mode-hint" class="muted small"></div>
160
+ </div>
161
+ </aside>
162
+ </div>
163
+ <footer id="statusbar">
164
+ <button class="sb" id="sb-branch" data-tip="tip.ide.git" hidden><span data-icon="git"></span><span></span></button>
165
+ <button class="sb" id="sb-problems" data-tip="tip.ide.problems"><span data-icon="error"></span><span id="sb-errors">0</span><span data-icon="warning"></span><span id="sb-warnings">0</span></button>
166
+ <span class="grow"></span>
167
+ <span class="sb" id="sb-pos" hidden></span>
168
+ <span class="sb" id="sb-lang" hidden></span>
169
+ <span class="sb" id="sb-enc" hidden>UTF-8</span>
170
+ <button class="sb" id="sb-model" data-tip="tip.pj.model"></button>
171
+ <button class="sb" id="sb-mode" data-tip="tip.ide.mode"></button>
172
+ </footer>
173
+ </div>
174
+ <div id="menu" class="menu" hidden></div>
175
+ <div id="modal" hidden><div class="box"><h3 id="modal-title"></h3><div id="modal-body"></div><div class="row end" id="modal-buttons"></div></div></div>
176
+ <div id="tip" role="tooltip" hidden></div>
177
+ </body>
178
+ </html>