agenter-app 1.1.0 → 1.3.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 +168 -130
- package/cli.js +43 -0
- package/lib/memory.js +101 -0
- package/lib/terminal.js +127 -0
- package/lib/update.js +69 -0
- package/package.json +1 -1
- package/public/app.js +500 -21
- package/public/index.html +89 -10
- package/public/style.css +119 -10
- package/scripts/pick-folder.ps1 +85 -0
- package/server.js +205 -17
package/public/index.html
CHANGED
|
@@ -17,11 +17,14 @@
|
|
|
17
17
|
<div class="app" id="app">
|
|
18
18
|
<aside class="sidebar" id="sidebar">
|
|
19
19
|
<div class="brand-row">
|
|
20
|
-
<div class="brand"><span class="logo"></span>Agenter</div>
|
|
20
|
+
<div class="brand"><span class="logo"></span><span class="brand-name">Agenter</span></div>
|
|
21
21
|
<span class="conn" id="conn" title="Connecting…"></span>
|
|
22
|
+
<button class="btn ghost icon nav-min-btn" id="navMinBtn" type="button" data-nav-min title="Collapse sidebar (B)" aria-label="Collapse sidebar" aria-expanded="true">
|
|
23
|
+
<svg class="ic" viewBox="0 0 24 24"><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M9 3v18"/></svg>
|
|
24
|
+
</button>
|
|
22
25
|
</div>
|
|
23
26
|
|
|
24
|
-
<button class="nav-item" id="navInbox" type="button">
|
|
27
|
+
<button class="nav-item" id="navInbox" type="button" title="Inbox">
|
|
25
28
|
<svg class="ic" viewBox="0 0 24 24"><polyline points="22 12 16 12 14 15 10 15 8 12 2 12"/><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/></svg>
|
|
26
29
|
<span>Inbox</span>
|
|
27
30
|
<span class="count" id="inboxCount" hidden></span>
|
|
@@ -80,13 +83,24 @@
|
|
|
80
83
|
</button>
|
|
81
84
|
</div>
|
|
82
85
|
</div>
|
|
83
|
-
<div class="accent-row"
|
|
86
|
+
<div class="accent-row">
|
|
84
87
|
<span>Accent</span>
|
|
85
|
-
<
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
<div class="swatches" id="accentPicker" role="radiogroup" aria-label="Accent color">
|
|
89
|
+
<button type="button" role="radio" data-accent="sage" style="--sw:#b7d4a6" title="Sage"></button>
|
|
90
|
+
<button type="button" role="radio" data-accent="mint" style="--sw:#8fe0b4" title="Mint"></button>
|
|
91
|
+
<button type="button" role="radio" data-accent="teal" style="--sw:#73cfcb" title="Teal"></button>
|
|
92
|
+
<button type="button" role="radio" data-accent="sky" style="--sw:#8cc4ef" title="Sky"></button>
|
|
93
|
+
<button type="button" role="radio" data-accent="indigo" style="--sw:#a0aef5" title="Indigo"></button>
|
|
94
|
+
<button type="button" role="radio" data-accent="lavender" style="--sw:#b8acf2" title="Lavender"></button>
|
|
95
|
+
<button type="button" role="radio" data-accent="plum" style="--sw:#d49ae0" title="Plum"></button>
|
|
96
|
+
<button type="button" role="radio" data-accent="magenta" style="--sw:#f08fd0" title="Magenta"></button>
|
|
97
|
+
<button type="button" role="radio" data-accent="rose" style="--sw:#e58aa6" title="Rose"></button>
|
|
98
|
+
<button type="button" role="radio" data-accent="coral" style="--sw:#f29a8b" title="Coral"></button>
|
|
99
|
+
<button type="button" role="radio" data-accent="clay" style="--sw:#dc9474" title="Clay"></button>
|
|
100
|
+
<button type="button" role="radio" data-accent="amber" style="--sw:#eec15f" title="Amber"></button>
|
|
101
|
+
<button type="button" role="radio" data-accent="lemon" style="--sw:#e3d96b" title="Lemon"></button>
|
|
102
|
+
<button type="button" role="radio" data-accent="slate" style="--sw:#a9b8c6" title="Slate"></button>
|
|
103
|
+
</div>
|
|
90
104
|
</div>
|
|
91
105
|
</div>
|
|
92
106
|
</details>
|
|
@@ -103,6 +117,7 @@
|
|
|
103
117
|
<div class="scrim" id="scrim"></div>
|
|
104
118
|
|
|
105
119
|
<main class="main">
|
|
120
|
+
<div class="update-bar" id="updateBar" role="status" hidden></div>
|
|
106
121
|
<header class="main-head" id="mainHead"></header>
|
|
107
122
|
<div class="split" id="split">
|
|
108
123
|
<div class="chat-col">
|
|
@@ -129,11 +144,42 @@
|
|
|
129
144
|
<div class="pv-body" id="pvBody"></div>
|
|
130
145
|
</section>
|
|
131
146
|
</div>
|
|
147
|
+
<section class="term" id="term" aria-label="Terminal" hidden>
|
|
148
|
+
<div class="term-bar">
|
|
149
|
+
<span class="term-title">PowerShell</span>
|
|
150
|
+
<span class="term-cwd mono" id="termCwd"></span>
|
|
151
|
+
<button class="btn ghost small" type="button" id="termStop" data-term-stop title="Stop the running command. This also ends the shell, so variables start fresh" hidden>Stop</button>
|
|
152
|
+
<button class="btn ghost small" type="button" data-term-clear>Clear</button>
|
|
153
|
+
<button class="btn ghost icon" type="button" data-term-toggle title="Close terminal" aria-label="Close terminal">
|
|
154
|
+
<svg class="ic" viewBox="0 0 24 24"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
|
155
|
+
</button>
|
|
156
|
+
</div>
|
|
157
|
+
<pre class="term-out" id="termOut" tabindex="0"></pre>
|
|
158
|
+
<form class="term-line" id="termForm" autocomplete="off">
|
|
159
|
+
<span class="term-prompt mono" id="termPrompt">></span>
|
|
160
|
+
<input class="term-input mono" id="termInput" type="text" spellcheck="false" aria-label="Command" placeholder="Type a command">
|
|
161
|
+
</form>
|
|
162
|
+
</section>
|
|
132
163
|
</main>
|
|
133
164
|
</div>
|
|
134
165
|
|
|
135
166
|
<div class="toasts" id="toasts" aria-live="polite"></div>
|
|
136
167
|
|
|
168
|
+
<div id="moreMenu" class="more-menu" popover role="menu" aria-label="More actions">
|
|
169
|
+
<button type="button" role="menuitem" data-memory>
|
|
170
|
+
<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H20v20H6.5a2.5 2.5 0 0 1 0-5H20"/></svg>
|
|
171
|
+
<span>Memory</span>
|
|
172
|
+
</button>
|
|
173
|
+
<button type="button" role="menuitem" data-carry>
|
|
174
|
+
<svg class="ic" viewBox="0 0 24 24"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>
|
|
175
|
+
<span>Carry to a new chat</span>
|
|
176
|
+
</button>
|
|
177
|
+
<button type="button" role="menuitem" data-open-vscode>
|
|
178
|
+
<svg class="ic" viewBox="0 0 24 24"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>
|
|
179
|
+
<span>Open in VS Code</span>
|
|
180
|
+
</button>
|
|
181
|
+
</div>
|
|
182
|
+
|
|
137
183
|
<dialog id="newDialog" class="new-dialog">
|
|
138
184
|
<form id="newForm" autocomplete="off">
|
|
139
185
|
<div class="new-head">
|
|
@@ -145,18 +191,48 @@
|
|
|
145
191
|
</div>
|
|
146
192
|
<p class="dlg-sub" id="newSub"></p>
|
|
147
193
|
<label class="field-label" for="newCwd">Project folder</label>
|
|
148
|
-
<
|
|
194
|
+
<div class="folder-row">
|
|
195
|
+
<input class="field mono" id="newCwd" list="newCwdList" placeholder="C:\Users\you\Projects\my-app" spellcheck="false" required>
|
|
196
|
+
<button class="btn" type="button" id="newBrowse">Browse…</button>
|
|
197
|
+
</div>
|
|
149
198
|
<datalist id="newCwdList"></datalist>
|
|
199
|
+
<div class="new-carry" id="newCarry" hidden>
|
|
200
|
+
<span id="newCarryText"></span>
|
|
201
|
+
<button class="btn ghost small" type="button" data-carry-drop>Remove</button>
|
|
202
|
+
</div>
|
|
150
203
|
<label class="field-label" for="newMsg">First message</label>
|
|
151
|
-
<textarea class="field" id="newMsg" rows="4" placeholder="What should Claude do?"
|
|
204
|
+
<textarea class="field" id="newMsg" rows="4" placeholder="What should Claude do?"></textarea>
|
|
205
|
+
<div class="attach-row" data-attach="new" hidden></div>
|
|
152
206
|
<div class="dlg-error" id="newError" hidden></div>
|
|
153
207
|
<div class="dlg-actions">
|
|
208
|
+
<button class="btn ghost attach-left" type="button" data-attach-pick title="Attach images (or paste / drop them)">
|
|
209
|
+
<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><rect width="18" height="18" x="3" y="3" rx="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.1-3.1a2 2 0 0 0-2.8 0L6 21"/></svg>Attach images
|
|
210
|
+
</button>
|
|
154
211
|
<button class="btn ghost" type="button" data-new-cancel>Cancel</button>
|
|
155
212
|
<button class="btn primary" type="submit" id="newStart">Start session</button>
|
|
156
213
|
</div>
|
|
157
214
|
</form>
|
|
158
215
|
</dialog>
|
|
159
216
|
|
|
217
|
+
<dialog id="memDialog" class="mem-dialog">
|
|
218
|
+
<div class="mem-head">
|
|
219
|
+
<h2>Memory</h2>
|
|
220
|
+
<span id="memSub"></span>
|
|
221
|
+
</div>
|
|
222
|
+
<div class="mem-body">
|
|
223
|
+
<nav class="mem-list" id="memList" aria-label="Memory files"></nav>
|
|
224
|
+
<div class="mem-edit">
|
|
225
|
+
<div class="mem-path mono" id="memPath"></div>
|
|
226
|
+
<textarea class="field mono" id="memText" spellcheck="false" aria-label="File contents"></textarea>
|
|
227
|
+
<div class="dlg-error" id="memError" hidden></div>
|
|
228
|
+
</div>
|
|
229
|
+
</div>
|
|
230
|
+
<div class="dlg-actions">
|
|
231
|
+
<button class="btn ghost" type="button" data-mem-close>Close</button>
|
|
232
|
+
<button class="btn primary" type="button" id="memSave" disabled>Save</button>
|
|
233
|
+
</div>
|
|
234
|
+
</dialog>
|
|
235
|
+
|
|
160
236
|
<dialog id="helpDialog">
|
|
161
237
|
<h2>Keyboard shortcuts</h2>
|
|
162
238
|
<dl class="keys">
|
|
@@ -170,11 +246,14 @@
|
|
|
170
246
|
<dt><kbd>I</kbd></dt><dd>Open the inbox</dd>
|
|
171
247
|
<dt><kbd>/</kbd></dt><dd>Filter sessions</dd>
|
|
172
248
|
<dt><kbd>T</kbd></dt><dd>Switch theme (system → light → dark)</dd>
|
|
249
|
+
<dt><kbd>`</kbd></dt><dd>Show or hide the terminal</dd>
|
|
250
|
+
<dt><kbd>B</kbd></dt><dd>Collapse or expand the sidebar</dd>
|
|
173
251
|
<dt><kbd>Esc</kbd></dt><dd>Leave a text box / close this</dd>
|
|
174
252
|
</dl>
|
|
175
253
|
<form method="dialog"><button class="btn primary">Got it</button></form>
|
|
176
254
|
</dialog>
|
|
177
255
|
|
|
256
|
+
<input type="file" id="attachInput" accept="image/png,image/jpeg,image/gif,image/webp" multiple hidden>
|
|
178
257
|
<script src="/app.js"></script>
|
|
179
258
|
</body>
|
|
180
259
|
</html>
|
package/public/style.css
CHANGED
|
@@ -72,6 +72,15 @@
|
|
|
72
72
|
:root[data-accent="teal"] { --accent: #73cfcb; --accent-deep: #1d7a76; }
|
|
73
73
|
:root[data-accent="rose"] { --accent: #e58aa6; --accent-deep: #ad3a61; }
|
|
74
74
|
:root[data-accent="lavender"] { --accent: #b8acf2; --accent-deep: #6450c4; }
|
|
75
|
+
:root[data-accent="mint"] { --accent: #8fe0b4; --accent-deep: #1b7049; }
|
|
76
|
+
:root[data-accent="sky"] { --accent: #8cc4ef; --accent-deep: #27689f; }
|
|
77
|
+
:root[data-accent="indigo"] { --accent: #a0aef5; --accent-deep: #3f51bf; }
|
|
78
|
+
:root[data-accent="plum"] { --accent: #d49ae0; --accent-deep: #8b3a9b; }
|
|
79
|
+
:root[data-accent="magenta"] { --accent: #f08fd0; --accent-deep: #a82a83; }
|
|
80
|
+
:root[data-accent="coral"] { --accent: #f29a8b; --accent-deep: #b03f2b; }
|
|
81
|
+
:root[data-accent="amber"] { --accent: #eec15f; --accent-deep: #855b05; }
|
|
82
|
+
:root[data-accent="lemon"] { --accent: #e3d96b; --accent-deep: #6d640b; }
|
|
83
|
+
:root[data-accent="slate"] { --accent: #a9b8c6; --accent-deep: #4b5f72; }
|
|
75
84
|
|
|
76
85
|
* { box-sizing: border-box; }
|
|
77
86
|
html, body { height: 100%; margin: 0; }
|
|
@@ -101,7 +110,9 @@ kbd {
|
|
|
101
110
|
width: 300px; flex: none; display: flex; flex-direction: column; gap: 6px;
|
|
102
111
|
background: var(--sidebar); border-right: 1px solid var(--border); padding: 14px 10px 10px; min-height: 0;
|
|
103
112
|
}
|
|
104
|
-
.brand-row { display: flex; align-items: center;
|
|
113
|
+
.brand-row { display: flex; align-items: center; gap: 8px; padding: 0 6px 8px; }
|
|
114
|
+
.brand-row .brand { margin-right: auto; }
|
|
115
|
+
.nav-min-btn { padding: 4px; color: var(--muted); }
|
|
105
116
|
.brand { display: flex; align-items: center; gap: 9px; font-weight: 700; font-size: 15px; letter-spacing: -.01em; }
|
|
106
117
|
.logo { width: 22px; height: 22px; border-radius: 7px; background: var(--accent); position: relative; }
|
|
107
118
|
.logo::after { content: ""; position: absolute; inset: 6px; background: var(--accent-text); transform: rotate(45deg); border-radius: 2px; }
|
|
@@ -115,6 +126,7 @@ kbd {
|
|
|
115
126
|
}
|
|
116
127
|
.nav-item:hover { background: var(--hover); }
|
|
117
128
|
.nav-item.active { background: var(--panel); box-shadow: var(--shadow-sm); }
|
|
129
|
+
.nav-item:disabled { opacity: .6; cursor: progress; }
|
|
118
130
|
.count { margin-left: auto; min-width: 20px; padding: 0 6px; border-radius: 99px; background: var(--warn); color: #fff; font-size: 11.5px; font-weight: 700; text-align: center; line-height: 19px; }
|
|
119
131
|
|
|
120
132
|
.search { position: relative; display: flex; align-items: center; margin: 4px 0 2px; }
|
|
@@ -236,7 +248,8 @@ kbd {
|
|
|
236
248
|
.segmented button:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
|
|
237
249
|
.segmented .ic { width: 14px; height: 14px; }
|
|
238
250
|
.accent-row { display: flex; align-items: center; gap: 7px; font-size: 13px; color: var(--text-2); }
|
|
239
|
-
.accent-row span { margin-right: auto; }
|
|
251
|
+
.accent-row > span { margin-right: auto; }
|
|
252
|
+
.swatches { display: grid; grid-template-columns: repeat(7, 16px); gap: 7px; }
|
|
240
253
|
.accent-row button {
|
|
241
254
|
width: 16px; height: 16px; border-radius: 4px; border: 0; padding: 0; cursor: pointer;
|
|
242
255
|
background: var(--sw); box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .15);
|
|
@@ -276,16 +289,17 @@ kbd {
|
|
|
276
289
|
.btn.primary kbd { background: transparent; color: inherit; border-color: currentColor; opacity: .7; }
|
|
277
290
|
|
|
278
291
|
/* ---------- main ---------- */
|
|
279
|
-
|
|
292
|
+
/* Measured as a container: what matters is the room left beside the sidebar, not the window. */
|
|
293
|
+
.main { flex: 1; display: flex; flex-direction: column; min-width: 0; container: main / inline-size; }
|
|
280
294
|
.main-head {
|
|
281
|
-
display: flex; align-items: center; gap: 12px; padding: 12px 24px; min-height: 64px;
|
|
295
|
+
display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding: 12px 24px; min-height: 64px;
|
|
282
296
|
border-bottom: 1px solid var(--border); background: var(--panel);
|
|
283
297
|
}
|
|
284
|
-
.head-text { min-width: 0; flex: 1; }
|
|
298
|
+
.head-text { min-width: 0; flex: 1 1 180px; }
|
|
285
299
|
.head-title { display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: 16px; letter-spacing: -.01em; }
|
|
286
300
|
.head-title span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
287
301
|
.head-sub { font-size: 12.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
288
|
-
.head-actions { display: flex; align-items: center; gap: 8px;
|
|
302
|
+
.head-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; min-width: 0; }
|
|
289
303
|
.menu-btn { display: none; }
|
|
290
304
|
.path-chip { cursor: pointer; border: 0; background: none; padding: 0; color: var(--muted); font-size: 12px; }
|
|
291
305
|
.path-chip:hover { color: var(--text); text-decoration: underline; }
|
|
@@ -318,6 +332,59 @@ dialog.new-dialog { max-width: 520px; }
|
|
|
318
332
|
.new-dialog .dlg-error { margin-top: 12px; font-size: 13px; color: var(--danger); }
|
|
319
333
|
.new-dialog .dlg-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 18px; }
|
|
320
334
|
|
|
335
|
+
.new-dialog .folder-row { display: flex; gap: 8px; }
|
|
336
|
+
.new-dialog .folder-row .field { flex: 1; min-width: 0; }
|
|
337
|
+
.new-carry { display: flex; align-items: center; gap: 8px; margin-top: 10px; padding: 7px 10px; border-radius: 8px; background: var(--accent-soft); font-size: 12.5px; }
|
|
338
|
+
.new-carry[hidden] { display: none; }
|
|
339
|
+
.new-carry span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
340
|
+
|
|
341
|
+
/* ---------- update bar ---------- */
|
|
342
|
+
.update-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; padding: 8px 24px; background: var(--accent-soft); border-bottom: 1px solid var(--border); font-size: 13px; }
|
|
343
|
+
.update-bar[hidden] { display: none; }
|
|
344
|
+
.update-bar .update-text { flex: 1 1 240px; min-width: 0; }
|
|
345
|
+
.update-bar .update-text code { font-size: 12px; }
|
|
346
|
+
|
|
347
|
+
/* ---------- more menu ---------- */
|
|
348
|
+
.more-menu { position: fixed; inset: auto; margin: 0; min-width: 200px; padding: 4px; border: 1px solid var(--border); border-radius: 10px; background: var(--panel); color: var(--text); box-shadow: var(--shadow); }
|
|
349
|
+
.more-menu button { display: flex; align-items: center; gap: 10px; width: 100%; padding: 7px 10px; border: 0; border-radius: 7px; background: none; cursor: pointer; font-size: 13px; text-align: left; }
|
|
350
|
+
.more-menu button:hover, .more-menu button:focus-visible { background: var(--hover); outline: none; }
|
|
351
|
+
.more-menu .ic { color: var(--muted); }
|
|
352
|
+
|
|
353
|
+
/* ---------- terminal ---------- */
|
|
354
|
+
.term { flex: none; height: min(36vh, 360px); min-height: 160px; display: flex; flex-direction: column; border-top: 1px solid var(--border); background: var(--code-bg); }
|
|
355
|
+
.term[hidden] { display: none; }
|
|
356
|
+
.term-bar { display: flex; align-items: center; gap: 6px; padding: 4px 8px 4px 14px; border-bottom: 1px solid var(--border); background: var(--panel); }
|
|
357
|
+
.term-title { font-size: 12px; font-weight: 600; flex: none; }
|
|
358
|
+
.term-cwd { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); font-size: 12px; }
|
|
359
|
+
.term-bar .btn.icon { padding: 4px; }
|
|
360
|
+
.term-out { flex: 1; min-height: 0; overflow: auto; padding: 8px 14px; font-size: 12.5px; line-height: 1.45; outline: none; }
|
|
361
|
+
.term-line { display: flex; align-items: center; gap: 8px; padding: 6px 14px; border-top: 1px solid var(--border); }
|
|
362
|
+
.term-prompt { color: var(--accent-ink); flex: none; }
|
|
363
|
+
.term-input { flex: 1; min-width: 0; border: 0; outline: none; background: none; color: var(--text); padding: 0; }
|
|
364
|
+
.term-input::placeholder { color: var(--muted); }
|
|
365
|
+
|
|
366
|
+
/* ---------- memory ---------- */
|
|
367
|
+
dialog.mem-dialog { max-width: 860px; }
|
|
368
|
+
.mem-dialog[open] { display: flex; flex-direction: column; height: min(640px, calc(100vh - 48px)); }
|
|
369
|
+
.mem-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 12px; min-width: 0; }
|
|
370
|
+
.mem-head h2 { margin: 0; flex: none; }
|
|
371
|
+
.mem-head span { color: var(--muted); font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
372
|
+
.mem-body { flex: 1; min-height: 0; display: grid; grid-template-columns: 220px minmax(0, 1fr); gap: 14px; }
|
|
373
|
+
.mem-list { overflow-y: auto; }
|
|
374
|
+
.mem-group { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); padding: 10px 8px 4px; }
|
|
375
|
+
.mem-group:first-child { padding-top: 0; }
|
|
376
|
+
.mem-file { display: flex; align-items: center; gap: 6px; width: 100%; padding: 5px 8px; border: 0; border-radius: 7px; background: none; cursor: pointer; font-size: 13px; text-align: left; }
|
|
377
|
+
.mem-file span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
378
|
+
.mem-file:hover { background: var(--hover); }
|
|
379
|
+
.mem-file[aria-current="true"] { background: var(--accent-soft); }
|
|
380
|
+
.mem-file .new { margin-left: auto; flex: none; color: var(--muted); font-size: 11px; }
|
|
381
|
+
.mem-file .dirty { margin-left: auto; flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--warn); }
|
|
382
|
+
.mem-edit { display: flex; flex-direction: column; gap: 8px; min-height: 0; min-width: 0; }
|
|
383
|
+
.mem-path { font-size: 11.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
384
|
+
.mem-edit textarea { flex: 1; min-height: 0; resize: none; line-height: 1.5; }
|
|
385
|
+
.mem-dialog .dlg-error { font-size: 13px; color: var(--danger); }
|
|
386
|
+
.mem-dialog .dlg-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 14px; }
|
|
387
|
+
|
|
321
388
|
/* ---------- steering ---------- */
|
|
322
389
|
.kind-steer .reply-row .hint { white-space: normal; }
|
|
323
390
|
.link { border: 0; background: none; padding: 0; font: inherit; color: var(--accent-ink); text-decoration: underline; cursor: pointer; }
|
|
@@ -363,6 +430,9 @@ dialog.new-dialog { max-width: 520px; }
|
|
|
363
430
|
.convo { display: flex; flex-direction: column; gap: 10px; }
|
|
364
431
|
.msg-user { align-self: flex-end; max-width: 78%; background: var(--accent-soft); border: 1px solid transparent; padding: 9px 14px; border-radius: 14px 14px 4px 14px; white-space: pre-wrap; word-break: break-word; }
|
|
365
432
|
.msg-user.from-dash { border-color: var(--accent-ink); }
|
|
433
|
+
.carried { margin-top: 6px; font-size: 12.5px; color: var(--text-2); white-space: normal; }
|
|
434
|
+
.carried > summary { cursor: pointer; }
|
|
435
|
+
.carried pre { margin-top: 6px; max-height: 280px; overflow: auto; font-size: 12px; }
|
|
366
436
|
.live-echo { display: flex; justify-content: flex-end; margin-top: 12px; }
|
|
367
437
|
.msg-claude { display: grid; grid-template-columns: 26px 1fr; gap: 10px; align-items: start; }
|
|
368
438
|
.claude-mark { width: 26px; height: 26px; border-radius: 8px; background: var(--panel); border: 1px solid var(--border); display: grid; place-items: center; color: var(--accent-ink); }
|
|
@@ -479,6 +549,19 @@ dialog.new-dialog { max-width: 520px; }
|
|
|
479
549
|
.reply-box textarea { width: 100%; min-height: 64px; max-height: 260px; resize: none; border: 0; background: transparent; color: var(--text); font: inherit; padding: 10px 12px 4px; outline: none; display: block; }
|
|
480
550
|
.reply-row { display: flex; align-items: center; gap: 8px; padding: 6px 8px 8px 12px; }
|
|
481
551
|
.reply-row .hint { color: var(--muted); font-size: 12px; margin-right: auto; }
|
|
552
|
+
.reply-box.drop-over, #newForm.drop-over .field#newMsg { border-color: var(--accent-ink); box-shadow: 0 0 0 3px var(--accent-soft); }
|
|
553
|
+
|
|
554
|
+
/* Images waiting to go with a message. */
|
|
555
|
+
.attach-row { display: flex; flex-wrap: wrap; gap: 8px; padding: 6px 12px 2px; }
|
|
556
|
+
.attach-row[hidden] { display: none; }
|
|
557
|
+
#newDialog .attach-row { padding: 10px 0 0; }
|
|
558
|
+
.thumb { position: relative; width: 64px; height: 64px; border-radius: 8px; overflow: hidden; border: 1px solid var(--border); background: var(--panel-2); flex: none; }
|
|
559
|
+
.thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
|
560
|
+
.thumb-x { position: absolute; top: 3px; right: 3px; width: 20px; height: 20px; border: 0; border-radius: 50%; padding: 0; background: rgba(0, 0, 0, .6); color: #fff; font-size: 14px; line-height: 20px; cursor: pointer; opacity: .85; }
|
|
561
|
+
.thumb-x:hover, .thumb-x:focus-visible { opacity: 1; background: var(--danger); }
|
|
562
|
+
.attach-btn { padding-inline: 7px; }
|
|
563
|
+
.attach-btn .ic { margin: 0; }
|
|
564
|
+
.new-dialog .dlg-actions .attach-left { margin-right: auto; }
|
|
482
565
|
|
|
483
566
|
.question { margin-bottom: 14px; }
|
|
484
567
|
.q-title { font-weight: 600; margin-bottom: 8px; display: flex; gap: 8px; align-items: center; }
|
|
@@ -495,7 +578,7 @@ dialog.new-dialog { max-width: 520px; }
|
|
|
495
578
|
.section-title { display: flex; align-items: baseline; gap: 8px; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); margin: 26px 0 10px; }
|
|
496
579
|
#inboxPending > .section-title { margin-top: 0; }
|
|
497
580
|
.all-clear { display: flex; align-items: center; gap: 14px; padding: 18px 20px; border-radius: var(--radius); background: var(--panel); border: 1px solid var(--border); }
|
|
498
|
-
.all-clear .big { width: 38px; height: 38px; border-radius: 50%; background: var(--
|
|
581
|
+
.all-clear .big { width: 38px; height: 38px; border-radius: 50%; background: var(--accent-soft); color: var(--accent-ink); display: grid; place-items: center; flex: none; }
|
|
499
582
|
.all-clear b { display: block; }
|
|
500
583
|
.all-clear span { color: var(--muted); font-size: 13px; }
|
|
501
584
|
.tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 10px; }
|
|
@@ -538,23 +621,49 @@ dialog form { text-align: right; }
|
|
|
538
621
|
*, *::before, *::after { animation: none !important; transition: none !important; }
|
|
539
622
|
}
|
|
540
623
|
|
|
624
|
+
/* ---------- collapsed sidebar: a rail of icons and sessions ---------- */
|
|
625
|
+
@media (min-width: 801px) {
|
|
626
|
+
.app.nav-min .sidebar { width: 60px; padding: 14px 8px 10px; align-items: stretch; }
|
|
627
|
+
.app.nav-min .brand-row { flex-direction: column; padding: 0 0 8px; }
|
|
628
|
+
.app.nav-min .brand { margin: 0; }
|
|
629
|
+
.app.nav-min .brand-name, .app.nav-min .search, .app.nav-min .usage, .app.nav-min .sidebar-foot, .app.nav-min .group-label { display: none; }
|
|
630
|
+
.app.nav-min .nav-item { justify-content: center; padding: 8px 0; position: relative; }
|
|
631
|
+
.app.nav-min .nav-item > span:not(.count) { display: none; }
|
|
632
|
+
.app.nav-min .nav-item .count { position: absolute; top: 0; right: 0; min-width: 16px; padding: 0 4px; line-height: 15px; font-size: 10px; }
|
|
633
|
+
.app.nav-min .session-list { margin: 0; padding: 0; }
|
|
634
|
+
.app.nav-min .s-item { grid-template-columns: 32px; justify-content: center; padding: 6px 0; }
|
|
635
|
+
.app.nav-min .s-main, .app.nav-min .s-when { display: none; }
|
|
636
|
+
}
|
|
637
|
+
|
|
541
638
|
/* ---------- small screens ---------- */
|
|
542
639
|
@media (max-width: 800px) {
|
|
543
640
|
.sidebar { position: fixed; inset: 0 auto 0 0; z-index: 40; transform: translateX(-100%); transition: transform .2s; box-shadow: var(--shadow); width: min(300px, 86vw); }
|
|
544
641
|
.app.nav-open .sidebar { transform: none; }
|
|
545
642
|
.app.nav-open .scrim { display: block; position: fixed; inset: 0; background: rgba(0, 0, 0, .35); z-index: 30; }
|
|
546
643
|
.menu-btn { display: inline-flex; }
|
|
644
|
+
.search kbd { display: none; }
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/* Going by the space beside the sidebar, so the same room lays out the same way whether
|
|
648
|
+
the sidebar is open, collapsed or a drawer. */
|
|
649
|
+
@container main (max-width: 900px) {
|
|
650
|
+
.head-actions .label { display: none; }
|
|
651
|
+
}
|
|
652
|
+
@container main (max-width: 760px) {
|
|
547
653
|
.main-head { padding: 10px 16px; }
|
|
654
|
+
.update-bar { padding: 8px 16px; }
|
|
548
655
|
.content { padding: 16px; }
|
|
549
656
|
.dock { padding: 0 16px 14px; }
|
|
550
|
-
.head-actions .label { display: none; }
|
|
551
657
|
.msg-user { max-width: 92%; }
|
|
552
|
-
.btn kbd, .reply-row .hint
|
|
658
|
+
.btn kbd, .reply-row .hint { display: none; }
|
|
553
659
|
.tools { margin-left: 8px; }
|
|
554
660
|
/* No room side by side: the app goes on top, the conversation below. */
|
|
555
661
|
.split { flex-direction: column; }
|
|
556
662
|
.splitter { display: none; }
|
|
557
|
-
.preview { order: -1; width: auto; max-width: none; min-width: 0; height: 48vh; border-bottom: 1px solid var(--border); }
|
|
663
|
+
.preview { order: -1; width: auto; max-width: none; min-width: 0; height: 48vh; flex: none; border-bottom: 1px solid var(--border); }
|
|
664
|
+
}
|
|
665
|
+
@media (max-width: 640px) {
|
|
666
|
+
.mem-body { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 2fr) minmax(0, 5fr); }
|
|
558
667
|
}
|
|
559
668
|
|
|
560
669
|
.auth-lost { position: fixed; top: 12px; left: 50%; transform: translateX(-50%); z-index: 1000; max-width: calc(100vw - 32px); padding: 10px 14px; border-radius: 10px; background: #5c2a26; color: #fff; font-size: 13px; }
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# The Windows folder window behind New session. Prints the folder you chose, or nothing if
|
|
2
|
+
# you cancel.
|
|
3
|
+
Add-Type -AssemblyName System.Windows.Forms
|
|
4
|
+
|
|
5
|
+
# Windows won't let a background process take focus, so without this the window could open
|
|
6
|
+
# behind the dashboard and clicking New session would seem to do nothing. Joining the input
|
|
7
|
+
# of the window that has focus is what makes SetForegroundWindow allowed.
|
|
8
|
+
Add-Type @"
|
|
9
|
+
using System;
|
|
10
|
+
using System.Text;
|
|
11
|
+
using System.Runtime.InteropServices;
|
|
12
|
+
public static class PickFolderWindow {
|
|
13
|
+
[DllImport("user32.dll")] static extern IntPtr GetForegroundWindow();
|
|
14
|
+
[DllImport("user32.dll")] static extern uint GetWindowThreadProcessId(IntPtr h, IntPtr p);
|
|
15
|
+
[DllImport("kernel32.dll")] static extern uint GetCurrentThreadId();
|
|
16
|
+
[DllImport("user32.dll")] static extern bool AttachThreadInput(uint a, uint b, bool attach);
|
|
17
|
+
[DllImport("user32.dll")] static extern bool SetForegroundWindow(IntPtr h);
|
|
18
|
+
[DllImport("user32.dll")] static extern bool BringWindowToTop(IntPtr h);
|
|
19
|
+
[DllImport("user32.dll")] static extern bool IsWindowVisible(IntPtr h);
|
|
20
|
+
[DllImport("user32.dll", CharSet = CharSet.Unicode)] static extern int GetClassName(IntPtr h, StringBuilder name, int size);
|
|
21
|
+
delegate bool WindowVisitor(IntPtr h, IntPtr data);
|
|
22
|
+
[DllImport("user32.dll")] static extern bool EnumThreadWindows(uint thread, WindowVisitor visit, IntPtr data);
|
|
23
|
+
[DllImport("user32.dll")] static extern bool SetWindowPos(IntPtr h, IntPtr after, int x, int y, int cx, int cy, uint flags);
|
|
24
|
+
// Dialogs are the #32770 class. Runs on the dialog's thread, so its windows are ours.
|
|
25
|
+
static IntPtr FindDialog(uint thread) {
|
|
26
|
+
IntPtr found = IntPtr.Zero;
|
|
27
|
+
EnumThreadWindows(thread, (h, data) => {
|
|
28
|
+
StringBuilder name = new StringBuilder(16);
|
|
29
|
+
GetClassName(h, name, 16);
|
|
30
|
+
if (name.ToString() != "#32770" || !IsWindowVisible(h)) return true;
|
|
31
|
+
found = h;
|
|
32
|
+
return false;
|
|
33
|
+
}, IntPtr.Zero);
|
|
34
|
+
return found;
|
|
35
|
+
}
|
|
36
|
+
// True once the dialog really has focus.
|
|
37
|
+
public static bool BringForward() {
|
|
38
|
+
uint self = GetCurrentThreadId();
|
|
39
|
+
IntPtr dialog = FindDialog(self);
|
|
40
|
+
if (dialog == IntPtr.Zero) return false; // not up yet
|
|
41
|
+
if (GetForegroundWindow() == dialog) return true;
|
|
42
|
+
SetWindowPos(dialog, new IntPtr(-1), 0, 0, 0, 0, 0x0043); // topmost, no move or size, show
|
|
43
|
+
uint focused = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
|
|
44
|
+
bool joined = focused != 0 && focused != self && AttachThreadInput(self, focused, true);
|
|
45
|
+
BringWindowToTop(dialog);
|
|
46
|
+
SetForegroundWindow(dialog);
|
|
47
|
+
if (joined) AttachThreadInput(self, focused, false);
|
|
48
|
+
return GetForegroundWindow() == dialog;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
"@
|
|
52
|
+
|
|
53
|
+
[Console]::OutputEncoding = [Text.UTF8Encoding]::new($false)
|
|
54
|
+
|
|
55
|
+
$owner = New-Object System.Windows.Forms.Form
|
|
56
|
+
$owner.TopMost = $true
|
|
57
|
+
# Windows can still refuse focus, and this keeps the window findable when it does.
|
|
58
|
+
$owner.ShowInTaskbar = $true
|
|
59
|
+
$owner.Text = 'Agenter: choose a folder'
|
|
60
|
+
$owner.FormBorderStyle = 'None'
|
|
61
|
+
$owner.Opacity = 0
|
|
62
|
+
$owner.StartPosition = 'Manual'
|
|
63
|
+
$owner.Location = New-Object System.Drawing.Point(-32000, -32000)
|
|
64
|
+
$owner.Show()
|
|
65
|
+
|
|
66
|
+
$dialog = New-Object System.Windows.Forms.FolderBrowserDialog
|
|
67
|
+
$dialog.Description = 'Choose the project folder for this session'
|
|
68
|
+
$dialog.ShowNewFolderButton = $true
|
|
69
|
+
if ($env:AGENTER_PICK_START -and (Test-Path -LiteralPath $env:AGENTER_PICK_START)) { $dialog.SelectedPath = $env:AGENTER_PICK_START }
|
|
70
|
+
|
|
71
|
+
# Runs inside the dialog's own message loop. Keeps trying for a few seconds, then lets you be.
|
|
72
|
+
$raise = New-Object System.Windows.Forms.Timer
|
|
73
|
+
$raise.Interval = 50
|
|
74
|
+
$script:tries = 0
|
|
75
|
+
$raise.add_Tick({
|
|
76
|
+
$script:tries++
|
|
77
|
+
if ([PickFolderWindow]::BringForward() -or $script:tries -ge 60) { $raise.Stop() }
|
|
78
|
+
})
|
|
79
|
+
$raise.Start()
|
|
80
|
+
|
|
81
|
+
if ($dialog.ShowDialog($owner) -eq [System.Windows.Forms.DialogResult]::OK) {
|
|
82
|
+
[Console]::Out.Write($dialog.SelectedPath)
|
|
83
|
+
}
|
|
84
|
+
$raise.Dispose()
|
|
85
|
+
$owner.Dispose()
|