@oharness/server 0.9.3 → 0.11.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/dist/analytics.d.ts +32 -29
- package/dist/analytics.js +225 -278
- package/dist/analytics.js.map +1 -1
- package/dist/i18n.js +500 -64
- package/dist/i18n.js.map +1 -1
- package/dist/icons.js +1 -0
- package/dist/icons.js.map +1 -1
- package/dist/main.js +4 -0
- package/dist/main.js.map +1 -1
- package/dist/model-order.js +1 -0
- package/dist/model-order.js.map +1 -1
- package/dist/page/client/account.js +570 -27
- package/dist/page/client/account.js.map +1 -1
- package/dist/page/client/base.js +55 -12
- package/dist/page/client/base.js.map +1 -1
- package/dist/page/client/browser.js +1 -1
- package/dist/page/client/composer.js +802 -59
- package/dist/page/client/composer.js.map +1 -1
- package/dist/page/client/computer.d.ts +27 -0
- package/dist/page/client/computer.js +358 -0
- package/dist/page/client/computer.js.map +1 -0
- package/dist/page/client/dialogs.js +168 -6
- package/dist/page/client/dialogs.js.map +1 -1
- package/dist/page/client/events.js +119 -9
- package/dist/page/client/events.js.map +1 -1
- package/dist/page/client/files.js +86 -1
- package/dist/page/client/files.js.map +1 -1
- package/dist/page/client/index.js +8 -0
- package/dist/page/client/index.js.map +1 -1
- package/dist/page/client/panels.js +14 -10
- package/dist/page/client/panels.js.map +1 -1
- package/dist/page/client/ripple.d.ts +13 -0
- package/dist/page/client/ripple.js +247 -0
- package/dist/page/client/ripple.js.map +1 -0
- package/dist/page/client/routines.js +432 -45
- package/dist/page/client/routines.js.map +1 -1
- package/dist/page/client/shell.js +386 -104
- package/dist/page/client/shell.js.map +1 -1
- package/dist/page/client/state.js +278 -19
- package/dist/page/client/state.js.map +1 -1
- package/dist/page/client/tasks.d.ts +8 -0
- package/dist/page/client/tasks.js +293 -0
- package/dist/page/client/tasks.js.map +1 -0
- package/dist/page/client/terminal.js +34 -7
- package/dist/page/client/terminal.js.map +1 -1
- package/dist/page/client/theme.d.ts +17 -0
- package/dist/page/client/theme.js +365 -0
- package/dist/page/client/theme.js.map +1 -0
- package/dist/page/client/transcript.js +196 -8
- package/dist/page/client/transcript.js.map +1 -1
- package/dist/page/client/usage.js +1 -11
- package/dist/page/client/usage.js.map +1 -1
- package/dist/page/style.js +745 -76
- package/dist/page/style.js.map +1 -1
- package/dist/page.js +94 -16
- package/dist/page.js.map +1 -1
- package/dist/prefs.d.ts +31 -0
- package/dist/prefs.js +13 -1
- package/dist/prefs.js.map +1 -1
- package/dist/remote-crypto.d.ts +78 -0
- package/dist/remote-crypto.js +216 -0
- package/dist/remote-crypto.js.map +1 -0
- package/dist/remote.d.ts +103 -0
- package/dist/remote.js +498 -0
- package/dist/remote.js.map +1 -0
- package/dist/server.d.ts +70 -0
- package/dist/server.js +1738 -73
- package/dist/server.js.map +1 -1
- package/dist/starters.d.ts +92 -0
- package/dist/starters.js +213 -0
- package/dist/starters.js.map +1 -0
- package/dist/suggest.d.ts +42 -0
- package/dist/suggest.js +215 -0
- package/dist/suggest.js.map +1 -0
- package/dist/terminal.d.ts +28 -2
- package/dist/terminal.js +45 -3
- package/dist/terminal.js.map +1 -1
- package/dist/theme-assets.d.ts +39 -0
- package/dist/theme-assets.js +109 -0
- package/dist/theme-assets.js.map +1 -0
- package/dist/theme-store.d.ts +50 -0
- package/dist/theme-store.js +124 -0
- package/dist/theme-store.js.map +1 -0
- package/dist/theme-tools.d.ts +25 -0
- package/dist/theme-tools.js +243 -0
- package/dist/theme-tools.js.map +1 -0
- package/dist/turn-shots.d.ts +43 -0
- package/dist/turn-shots.js +80 -0
- package/dist/turn-shots.js.map +1 -0
- package/dist/user-theme.d.ts +143 -0
- package/dist/user-theme.js +510 -0
- package/dist/user-theme.js.map +1 -0
- package/package.json +2 -2
package/dist/page/style.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"style.js","sourceRoot":"","sources":["../../src/page/style.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,0EAA0E;AAC1E,MAAM,CAAC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAA;EAC7B,SAAS
|
|
1
|
+
{"version":3,"file":"style.js","sourceRoot":"","sources":["../../src/page/style.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,0EAA0E;AAC1E,MAAM,CAAC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAA;EAC7B,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyuHV,CAAC"}
|
package/dist/page.js
CHANGED
|
@@ -12,11 +12,8 @@ import { APP_SCRIPT } from "./page/client/index.js";
|
|
|
12
12
|
* an agent, and a CDN request from it would leak the session's existence and
|
|
13
13
|
* hand a third party script execution in a context that can run shell commands.
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* trade the paragraph above refuses — that is the point of it being a decision
|
|
18
|
-
* rather than a default, and the reason it is one variable to grep for rather
|
|
19
|
-
* than a setting buried in a config file.
|
|
15
|
+
* No exception for analytics either: the page hands usage events to this
|
|
16
|
+
* server's own /track, and analytics.ts decides whether they go anywhere.
|
|
20
17
|
*/
|
|
21
18
|
/**
|
|
22
19
|
* The tab icon, inlined.
|
|
@@ -83,14 +80,29 @@ ${ANALYTICS_STUB}
|
|
|
83
80
|
because it is ⌘K on one machine and Ctrl K on the next. -->
|
|
84
81
|
<!-- Home is the start page: a fresh session in the project on screen,
|
|
85
82
|
the same thing New session does, at the top of the places.
|
|
86
|
-
Lucide house on the 16 grid
|
|
87
|
-
|
|
83
|
+
Lucide house (the current one) on the 16 grid: a rounded roof and a
|
|
84
|
+
door that stops short of the eaves. The older house's sharp peak
|
|
85
|
+
and full-height door were the one hard-cornered shape in a rail of
|
|
86
|
+
rounded ones. -->
|
|
87
|
+
<button class="nav-item" id="nav-home" type="button"><svg class="ico" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 14V9.33a.67.67 0 0 0-.67-.66H6.67a.67.67 0 0 0-.67.66V14"/><path d="M2 6.67a1.33 1.33 0 0 1 .47-1.02l4.67-4a1.33 1.33 0 0 1 1.72 0l4.67 4A1.33 1.33 0 0 1 14 6.67v6a1.33 1.33 0 0 1-1.33 1.33H3.33A1.33 1.33 0 0 1 2 12.67Z"/></svg><span data-t="nav.home"></span></button>
|
|
88
88
|
<button class="nav-item" id="nav-search" type="button"><svg class="ico" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="7.33" cy="7.33" r="5.33"/><path d="m14 14-2.87-2.87"/></svg><span data-t="nav.search"></span><span class="count" id="palette-hint"></span></button>
|
|
89
89
|
<!-- Artifacts sit above Models because they belong to the work, not to the
|
|
90
90
|
configuration: this row answers "where did that chart go", which is a
|
|
91
|
-
question asked mid-task, while the three below it are settings.
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
question asked mid-task, while the three below it are settings.
|
|
92
|
+
Lucide shapes — things that were made. Two stacked rectangles read
|
|
93
|
+
as "copy" or "windows", and beside Sessions' two stacked bubbles
|
|
94
|
+
the pair were one icon drawn twice. -->
|
|
95
|
+
<button class="nav-item" id="nav-artifacts" type="button"><svg class="ico" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5.53 6.67a.47.47 0 0 1-.42-.72L7.6 2a.47.47 0 0 1 .8-.03l2.47 3.97a.47.47 0 0 1-.38.73Z"/><rect x="2" y="9.33" width="4.67" height="4.67" rx=".67"/><circle cx="11.67" cy="11.67" r="2.33"/></svg><span data-t="nav.artifacts"></span><span class="count" id="artifact-count"></span></button>
|
|
96
|
+
<!-- Lucide messages-square: two conversations. One bubble with text
|
|
97
|
+
lines read as "a message", and its lines blurred at 16px. -->
|
|
98
|
+
<button class="nav-item" id="nav-sessions" type="button"><svg class="ico" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9.33 6a1.33 1.33 0 0 1-1.33 1.33H4L1.33 10V2.67a1.33 1.33 0 0 1 1.34-1.34H8a1.33 1.33 0 0 1 1.33 1.34Z"/><path d="M12 6h1.33a1.33 1.33 0 0 1 1.34 1.33v7.34L12 12H8a1.33 1.33 0 0 1-1.33-1.33V10"/></svg><span data-t="nav.sessions"></span></button>
|
|
99
|
+
<!-- Usage, which Settings also reaches: what the account spent is looked
|
|
100
|
+
up often enough to earn a place of its own. Lucide chart-column-big:
|
|
101
|
+
a bar chart is what "usage" looks like everywhere else, and bars
|
|
102
|
+
drawn as columns rather than strokes still read as bars at 16px —
|
|
103
|
+
the thin-stroke chart's short bar was a dot, and a gauge was too
|
|
104
|
+
abstract to name the page. -->
|
|
105
|
+
<button class="nav-item" id="nav-usage" type="button"><svg class="ico" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 2v10.67A1.33 1.33 0 0 0 3.33 14H14"/><rect x="10" y="3.33" width="2.67" height="8" rx=".67"/><rect x="4.67" y="6.67" width="2.67" height="4.67" rx=".67"/></svg><span data-t="nav.usage"></span></button>
|
|
94
106
|
<button class="nav-item" id="nav-models" type="button"><svg class="ico" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 5.33a1.33 1.33 0 0 0-.67-1.15L8.67 1.51a1.33 1.33 0 0 0-1.33 0L2.67 4.18A1.33 1.33 0 0 0 2 5.33v5.33a1.33 1.33 0 0 0 .67 1.15l4.67 2.67a1.33 1.33 0 0 0 1.33 0l4.67-2.67A1.33 1.33 0 0 0 14 10.67Z"/><path d="m2.2 4.67 5.8 3.33 5.8-3.33"/><path d="M8 14.67V8"/></svg><span data-t="nav.models"></span><span class="count" id="model-count"></span></button>
|
|
95
107
|
<button class="nav-item" id="nav-routines" type="button"><svg class="ico" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="8" cy="8" r="6.67"/><path d="M8 4v4l2.67 1.33"/></svg><span data-t="nav.routines"></span><span class="count" id="routine-count"></span></button>
|
|
96
108
|
<button class="nav-item" id="nav-settings" type="button"><svg class="ico" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12.67 4.67h-6"/><path d="M9.33 11.33H3.33"/><circle cx="4.67" cy="4.67" r="2"/><circle cx="11.33" cy="11.33" r="2"/></svg><span data-t="nav.settings"></span></button>
|
|
@@ -107,7 +119,13 @@ ${ANALYTICS_STUB}
|
|
|
107
119
|
<span class="chev"></span>
|
|
108
120
|
</button>
|
|
109
121
|
<div id="side-new">
|
|
110
|
-
|
|
122
|
+
<!-- A soft square left open at the corner the pen comes in through, and a
|
|
123
|
+
plain capsule for the pen: no nib facet, which at 16px was a
|
|
124
|
+
smudge rather than a detail. The search row under it draws the
|
|
125
|
+
same lens as the rail's Search, as a bare icon at the row's end: a
|
|
126
|
+
second full row read as a second thing to do, and it is not. -->
|
|
127
|
+
<button class="nav-item" id="new" type="button"><svg class="ico" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7.33 2.67H5A2.33 2.33 0 0 0 2.67 5v6A2.33 2.33 0 0 0 5 13.33h6A2.33 2.33 0 0 0 13.33 11V8.67"/><path d="M12.1 2.9a1.27 1.27 0 0 1 1.8 1.8l-4.6 4.6a1.6 1.6 0 0 1-.72.4l-1.85.47.47-1.85a1.6 1.6 0 0 1 .4-.72Z"/></svg><span data-t="nav.new"></span></button>
|
|
128
|
+
<button id="side-search" type="button" data-t-title="nav.searchSessions" data-t-aria-label="nav.searchSessions"><svg class="ico-sm" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="7.33" cy="7.33" r="5.33"/><path d="m14 14-2.87-2.87"/></svg></button>
|
|
111
129
|
</div>
|
|
112
130
|
<div id="sessions"></div>
|
|
113
131
|
<!-- Pinned under the session list, where an account belongs and where
|
|
@@ -130,8 +148,25 @@ ${ANALYTICS_STUB}
|
|
|
130
148
|
<div id="split">
|
|
131
149
|
<div id="main">
|
|
132
150
|
<div id="tabs"></div>
|
|
151
|
+
<!-- The window Computer use is working in, live, floating over the
|
|
152
|
+
conversation while a turn works in it (see client/computer.ts).
|
|
153
|
+
Folded, it is the pill under it. -->
|
|
154
|
+
<div id="computer-float" hidden>
|
|
155
|
+
<!-- Over the picture, not above it: the app's name as a pill on the
|
|
156
|
+
left, the controls as round buttons on the right. -->
|
|
157
|
+
<div id="computer-head">
|
|
158
|
+
<span id="computer-label"><span id="computer-live" hidden><i></i></span><span id="computer-where"></span></span>
|
|
159
|
+
<button id="computer-grow" type="button" aria-pressed="false" data-t-title="computer.grow" data-t-aria-label="computer.grow"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 2.67h3.33V6"/><path d="M6 13.33H2.67V10"/><path d="m13.33 2.67-4 4"/><path d="m2.67 13.33 4-4"/></svg></button>
|
|
160
|
+
<button id="computer-stop" type="button" data-t-title="computer.stop" data-t-aria-label="computer.stop"><svg viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><rect x="4" y="4" width="8" height="8" rx="1.5"/></svg></button>
|
|
161
|
+
<button id="computer-hide" type="button" data-t-title="computer.hide" data-t-aria-label="computer.hide"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M4 8h8"/></svg></button>
|
|
162
|
+
</div>
|
|
163
|
+
<div id="computer-body"></div>
|
|
164
|
+
</div>
|
|
165
|
+
<button id="computer-pill" type="button" hidden data-t-title="computer.showPane"><i></i><span id="computer-pill-where"></span></button>
|
|
133
166
|
<div id="log">
|
|
134
167
|
<div id="empty">
|
|
168
|
+
<!-- A theme's art for a new session, when it has one (style.ts). -->
|
|
169
|
+
<div id="empty-art" aria-hidden="true"></div>
|
|
135
170
|
<div class="empty-brand">
|
|
136
171
|
<!-- Lighter stroke than the 18px sidebar copy: at 68px the 2.5 weight
|
|
137
172
|
scales to ~5px and reads much heavier than the wordmark next to it. -->
|
|
@@ -147,9 +182,9 @@ ${ANALYTICS_STUB}
|
|
|
147
182
|
</div>
|
|
148
183
|
<h1 data-t="empty.title"></h1>
|
|
149
184
|
<p><span data-t="empty.connected"></span> <span id="empty-cwd" class="mono"></span></p>
|
|
150
|
-
<!-- Filled by paintStarters():
|
|
151
|
-
|
|
152
|
-
|
|
185
|
+
<!-- Filled by paintStarters(): three rotating everyday offers for a
|
|
186
|
+
project with no memory, three written from its notes once it has
|
|
187
|
+
some. -->
|
|
153
188
|
<div id="starters"></div>
|
|
154
189
|
</div>
|
|
155
190
|
</div>
|
|
@@ -164,9 +199,25 @@ ${ANALYTICS_STUB}
|
|
|
164
199
|
rather than in it: what is in the box is the message being written,
|
|
165
200
|
and a row sharing that surface reads as part of it. -->
|
|
166
201
|
<div id="queued"></div>
|
|
202
|
+
<!-- What the message carries — pictures, clips, files, folders — as cards
|
|
203
|
+
above the box, not chips inside it (see renderTray). -->
|
|
204
|
+
<div id="tray"></div>
|
|
167
205
|
<div class="composer" id="composer-box">
|
|
168
206
|
<!-- The top edge is a grab handle: drag it to resize the field. -->
|
|
169
207
|
<div id="grip" role="separator" aria-orientation="horizontal" data-t-title="composer.resize"></div>
|
|
208
|
+
<!-- Dictation, floating over the box's top edge by the mic: listening
|
|
209
|
+
(the voice as bars, the time, cancel and done), then transcribing
|
|
210
|
+
and tidying, or what went wrong. -->
|
|
211
|
+
<div id="dictate-pop" class="dictate-pop" hidden role="status" aria-live="polite">
|
|
212
|
+
<span class="dp-dot" aria-hidden="true"></span>
|
|
213
|
+
<span class="dp-spin" aria-hidden="true"></span>
|
|
214
|
+
<span class="dp-text"></span>
|
|
215
|
+
<span class="dp-time"></span>
|
|
216
|
+
<canvas class="dp-wave" width="168" height="32" aria-hidden="true"></canvas>
|
|
217
|
+
<button type="button" class="dp-btn dp-cancel" data-t-title="dictate.cancel"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" aria-hidden="true"><path d="M4.5 4.5l7 7M11.5 4.5l-7 7"/></svg></button>
|
|
218
|
+
<button type="button" class="dp-btn dp-done" data-t-title="dictate.done"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7"/></svg></button>
|
|
219
|
+
<button type="button" class="dp-btn dp-close" data-t-title="dictate.close"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" aria-hidden="true"><path d="M4.5 4.5l7 7M11.5 4.5l-7 7"/></svg></button>
|
|
220
|
+
</div>
|
|
170
221
|
<div id="attachments"></div>
|
|
171
222
|
<!-- A textarea draws its own glyphs and cannot style a range of them, so
|
|
172
223
|
the chip behind a mention is painted on a layer underneath that
|
|
@@ -206,6 +257,7 @@ ${ANALYTICS_STUB}
|
|
|
206
257
|
<div class="menu" hidden></div>
|
|
207
258
|
</div>
|
|
208
259
|
<span class="composer-spacer"></span>
|
|
260
|
+
<button id="mic" class="icon-btn mic-btn" type="button" aria-pressed="false" data-t-title="composer.dictate"><svg class="mic-idle" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5.75" y="1.75" width="4.5" height="8" rx="2.25"/><path d="M3.25 7.5a4.75 4.75 0 0 0 9.5 0M8 12.25V14.5"/></svg><svg class="mic-stop" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><rect x="4.5" y="4.5" width="7" height="7" rx="2"/></svg></button>
|
|
209
261
|
<button id="stop" class="primary" type="button" hidden data-t-title="composer.stop"><svg viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><rect x="4" y="4" width="8" height="8" rx="1.5"/></svg></button>
|
|
210
262
|
<button id="send" class="primary" type="submit" data-t-title="composer.send"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 13V3.4M3.6 7.8 8 3.2l4.4 4.6"/></svg></button>
|
|
211
263
|
</div>
|
|
@@ -221,7 +273,7 @@ ${ANALYTICS_STUB}
|
|
|
221
273
|
<span id="cost"></span>
|
|
222
274
|
<span id="tokens"></span>
|
|
223
275
|
<span id="cache" data-t-title="usage.cacheHint"></span>
|
|
224
|
-
<
|
|
276
|
+
<button id="ctx" type="button" aria-haspopup="dialog" aria-expanded="false"></button>
|
|
225
277
|
<span id="ctxtext"></span>
|
|
226
278
|
</div>
|
|
227
279
|
</form>
|
|
@@ -261,7 +313,10 @@ ${ANALYTICS_STUB}
|
|
|
261
313
|
</span>
|
|
262
314
|
</div>
|
|
263
315
|
<div id="explorer-body">
|
|
264
|
-
<div id="explorer-
|
|
316
|
+
<div id="explorer-side">
|
|
317
|
+
<label id="explorer-find"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><circle cx="7" cy="7" r="4.5"/><path d="M10.5 10.5 14 14"/></svg><input id="explorer-q" type="search" autocomplete="off" spellcheck="false" data-t-placeholder="files.search" data-t-aria-label="files.search"></label>
|
|
318
|
+
<div id="explorer-tree" role="tree"></div>
|
|
319
|
+
</div>
|
|
265
320
|
<div id="explorer-split" role="separator" tabindex="0" data-t-aria-label="files.resize"></div>
|
|
266
321
|
<div id="explorer-view"></div>
|
|
267
322
|
</div>
|
|
@@ -426,6 +481,29 @@ ${ANALYTICS_STUB}
|
|
|
426
481
|
<!-- Importing a sign-in from the person's own browser. The confirmation is
|
|
427
482
|
the only path that reads anything out of that browser, so it names the
|
|
428
483
|
browser, the sites and what the agent can do with them afterwards. -->
|
|
484
|
+
<!-- Feedback: what kind, what happened, sent as the signed-in account. -->
|
|
485
|
+
<dialog id="feedback-dialog">
|
|
486
|
+
<div class="cn-head">
|
|
487
|
+
<div class="cn-naming">
|
|
488
|
+
<div class="cn-title" data-t="feedback.title"></div>
|
|
489
|
+
</div>
|
|
490
|
+
</div>
|
|
491
|
+
<div class="cn-body">
|
|
492
|
+
<div id="fb-kinds" class="fb-kinds" role="radiogroup"></div>
|
|
493
|
+
<textarea id="fb-message" rows="7" maxlength="5000"></textarea>
|
|
494
|
+
<!-- Attachments as square tiles, the last one the way to add another. -->
|
|
495
|
+
<div id="fb-files" class="fb-media"></div>
|
|
496
|
+
<input id="fb-file" type="file" multiple hidden
|
|
497
|
+
accept="image/png,image/jpeg,image/gif,image/webp,video/mp4,video/webm,video/quicktime">
|
|
498
|
+
<!-- Empty until there is something to say: an error, or that it was sent. -->
|
|
499
|
+
<p id="fb-status" class="fb-note"></p>
|
|
500
|
+
</div>
|
|
501
|
+
<div class="dlg-actions">
|
|
502
|
+
<button id="fb-cancel" type="button" class="quiet" data-t="models.cancel"></button>
|
|
503
|
+
<button id="fb-send" type="button" class="approve" data-t="feedback.send"></button>
|
|
504
|
+
</div>
|
|
505
|
+
</dialog>
|
|
506
|
+
|
|
429
507
|
<dialog id="browser-import-dialog">
|
|
430
508
|
<div class="cn-head">
|
|
431
509
|
<div class="cn-naming">
|
package/dist/page.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.js","sourceRoot":"","sources":["../src/page.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD
|
|
1
|
+
{"version":3,"file":"page.js","sourceRoot":"","sources":["../src/page.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD;;;;;;;;;;;GAWG;AAGH;;;;;;;GAOG;AACH,MAAM,OAAO,GAAG;;;;;yCAKyB,CAAC;AAE1C,MAAM,CAAC,MAAM,IAAI,GAAG;;;;;;;4CAOwB,kBAAkB,CAAC,OAAO,CAAC;SAC9D,KAAK;EACZ,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAwfK,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;qBACvB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;EAC1C,aAAa;EACb,UAAU;EACV,gBAAgB;;;QAGV,CAAC"}
|
package/dist/prefs.d.ts
CHANGED
|
@@ -40,6 +40,37 @@ export interface Prefs {
|
|
|
40
40
|
* routines fire when they are due rather than when the lid is next opened.
|
|
41
41
|
*/
|
|
42
42
|
keepAwake?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Whether a phone on this account may reach this machine through the relay
|
|
45
|
+
* (remote.ts). Absent is off: a machine is not offered to a phone until
|
|
46
|
+
* somebody at it says so.
|
|
47
|
+
*/
|
|
48
|
+
remote?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Whether Computer Use may take the real mouse and keyboard when an action
|
|
51
|
+
* cannot run in the background. `never` keeps it strictly in the background;
|
|
52
|
+
* absent is "ask", through the permission prompt each time.
|
|
53
|
+
*/
|
|
54
|
+
computerTakeover?: "ask" | "never";
|
|
55
|
+
/**
|
|
56
|
+
* Whether the agent may switch Computer use on by itself when a request
|
|
57
|
+
* needs it: `ask` (absent) through the permission prompt, `auto` without
|
|
58
|
+
* one, `off` only from the + menu.
|
|
59
|
+
*/
|
|
60
|
+
computerEnable?: "ask" | "auto" | "off";
|
|
61
|
+
/** Apps Computer Use refuses outright, beyond the built-in list: ids or names. */
|
|
62
|
+
computerBlockedApps?: string[];
|
|
63
|
+
/**
|
|
64
|
+
* Whether the windows and browser tabs a turn left are pictured under its
|
|
65
|
+
* reply when it ends. Absent is on.
|
|
66
|
+
*/
|
|
67
|
+
turnShots?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Whether a turn that ends on its own is followed by a guess at the next
|
|
70
|
+
* message, offered in the empty composer. Absent is on; off saves the small
|
|
71
|
+
* model call every turn makes for it.
|
|
72
|
+
*/
|
|
73
|
+
suggestions?: boolean;
|
|
43
74
|
/**
|
|
44
75
|
* Sessions and projects kept at the top of their list.
|
|
45
76
|
*
|
package/dist/prefs.js
CHANGED
|
@@ -5,7 +5,7 @@ import { parseJson } from "@oharness/engine/util/json.ts";
|
|
|
5
5
|
import { isEffortChoice } from "@oharness/engine/providers/types.ts";
|
|
6
6
|
import { renameWithRetry } from "@oharness/engine/util/fs.ts";
|
|
7
7
|
/** The lists that are arrays of strings, checked the same way on read. */
|
|
8
|
-
const STRING_LISTS = ["pinnedSessions", "pinnedProjects", "projectOrder"];
|
|
8
|
+
const STRING_LISTS = ["pinnedSessions", "pinnedProjects", "projectOrder", "computerBlockedApps"];
|
|
9
9
|
const FILE = () => userPath("prefs.json");
|
|
10
10
|
export async function readPrefs() {
|
|
11
11
|
let raw;
|
|
@@ -28,6 +28,18 @@ export async function readPrefs() {
|
|
|
28
28
|
}
|
|
29
29
|
if (typeof parsed.value.analytics === "boolean")
|
|
30
30
|
prefs.analytics = parsed.value.analytics;
|
|
31
|
+
if (typeof parsed.value.keepAwake === "boolean")
|
|
32
|
+
prefs.keepAwake = parsed.value.keepAwake;
|
|
33
|
+
if (typeof parsed.value.remote === "boolean")
|
|
34
|
+
prefs.remote = parsed.value.remote;
|
|
35
|
+
if (typeof parsed.value.turnShots === "boolean")
|
|
36
|
+
prefs.turnShots = parsed.value.turnShots;
|
|
37
|
+
if (parsed.value.computerTakeover === "ask" || parsed.value.computerTakeover === "never") {
|
|
38
|
+
prefs.computerTakeover = parsed.value.computerTakeover;
|
|
39
|
+
}
|
|
40
|
+
if (parsed.value.computerEnable === "ask" || parsed.value.computerEnable === "auto" || parsed.value.computerEnable === "off") {
|
|
41
|
+
prefs.computerEnable = parsed.value.computerEnable;
|
|
42
|
+
}
|
|
31
43
|
for (const key of STRING_LISTS) {
|
|
32
44
|
const value = parsed.value[key];
|
|
33
45
|
if (Array.isArray(value)) {
|
package/dist/prefs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prefs.js","sourceRoot":"","sources":["../src/prefs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAErE,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"prefs.js","sourceRoot":"","sources":["../src/prefs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { type KeyObject } from "node:crypto";
|
|
2
|
+
export declare function b64(bytes: Uint8Array): string;
|
|
3
|
+
export declare function unb64(text: unknown, length?: number): Buffer;
|
|
4
|
+
/** A long-term Ed25519 identity, kept as PKCS#8 so it can be stored and reloaded. */
|
|
5
|
+
export interface Identity {
|
|
6
|
+
privateKey: KeyObject;
|
|
7
|
+
publicRaw: Buffer;
|
|
8
|
+
}
|
|
9
|
+
export declare function newIdentity(): {
|
|
10
|
+
identity: Identity;
|
|
11
|
+
pkcs8: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function loadIdentity(pkcs8: string): Identity;
|
|
14
|
+
export declare function transcript(channel: string, phoneIdentity: Buffer, phoneEph: Buffer, macIdentity: Buffer, macEph: Buffer): Buffer;
|
|
15
|
+
export declare function pairingCode(t: Buffer): string;
|
|
16
|
+
/** One direction's key and counter. */
|
|
17
|
+
declare class Direction {
|
|
18
|
+
private counter;
|
|
19
|
+
private readonly key;
|
|
20
|
+
constructor(key: Buffer);
|
|
21
|
+
seal(plaintext: string): string;
|
|
22
|
+
open(frame: string): string;
|
|
23
|
+
}
|
|
24
|
+
export interface HelloFrame {
|
|
25
|
+
device: {
|
|
26
|
+
id: string;
|
|
27
|
+
name: string;
|
|
28
|
+
};
|
|
29
|
+
identity: Buffer;
|
|
30
|
+
eph: Buffer;
|
|
31
|
+
}
|
|
32
|
+
export declare function readHello(message: Record<string, unknown>): HelloFrame;
|
|
33
|
+
/**
|
|
34
|
+
* The Mac's side of one channel's handshake: answer the hello, then check the
|
|
35
|
+
* proof. `welcome()` is sent as plaintext; after `accept()` every frame is sealed.
|
|
36
|
+
*/
|
|
37
|
+
export declare class MacHandshake {
|
|
38
|
+
readonly transcript: Buffer;
|
|
39
|
+
readonly code: string;
|
|
40
|
+
private readonly sendKey;
|
|
41
|
+
private readonly receiveKey;
|
|
42
|
+
private readonly welcomeFrame;
|
|
43
|
+
readonly hello: HelloFrame;
|
|
44
|
+
constructor(channel: string, hello: HelloFrame, identity: Identity);
|
|
45
|
+
welcome(): Record<string, unknown>;
|
|
46
|
+
/** Checks the phone's proof; on success, the sealed session for this channel. */
|
|
47
|
+
accept(message: Record<string, unknown>): SealedSession;
|
|
48
|
+
}
|
|
49
|
+
export declare class SealedSession {
|
|
50
|
+
private readonly outgoing;
|
|
51
|
+
private readonly incoming;
|
|
52
|
+
constructor(outgoing: Direction, incoming: Direction);
|
|
53
|
+
seal(message: Record<string, unknown>): string;
|
|
54
|
+
open(frame: string): Record<string, unknown>;
|
|
55
|
+
}
|
|
56
|
+
export declare class PhoneHandshake {
|
|
57
|
+
readonly eph: import("crypto").KeyPairKeyObjectResult;
|
|
58
|
+
private readonly ephRaw;
|
|
59
|
+
readonly channel: string;
|
|
60
|
+
readonly device: {
|
|
61
|
+
id: string;
|
|
62
|
+
name: string;
|
|
63
|
+
};
|
|
64
|
+
readonly identity: Identity;
|
|
65
|
+
constructor(channel: string, device: {
|
|
66
|
+
id: string;
|
|
67
|
+
name: string;
|
|
68
|
+
}, identity: Identity);
|
|
69
|
+
hello(): Record<string, unknown>;
|
|
70
|
+
/** Verifies the welcome and returns the proof to send, the code, and the sealed session. */
|
|
71
|
+
finish(welcome: Record<string, unknown>): {
|
|
72
|
+
proof: Record<string, unknown>;
|
|
73
|
+
code: string;
|
|
74
|
+
macIdentity: Buffer;
|
|
75
|
+
session: SealedSession;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
export {};
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { createHash, createCipheriv, createDecipheriv, createPrivateKey, createPublicKey, diffieHellman, generateKeyPairSync, hkdfSync, sign, verify, } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* The cryptography of remote control, Mac side. The phone's half is
|
|
4
|
+
* HarnessKit's `RemoteCrypto.swift`, and the two must agree byte for byte.
|
|
5
|
+
*
|
|
6
|
+
* Every channel starts with a handshake that the relay forwards and cannot
|
|
7
|
+
* take part in:
|
|
8
|
+
*
|
|
9
|
+
* phone → mac {hs:"hello", v:1, device:{id,name}, identity, eph}
|
|
10
|
+
* mac → phone {hs:"welcome", identity, eph, sig} sig = Ed25519_mac(T)
|
|
11
|
+
* phone → mac {hs:"proof", sig} sig = Ed25519_phone(T)
|
|
12
|
+
*
|
|
13
|
+
* `identity` is the side's long-term Ed25519 public key and `eph` a fresh
|
|
14
|
+
* X25519 public key, each as 32 raw bytes in base64. The transcript is
|
|
15
|
+
*
|
|
16
|
+
* T = SHA-256("oharness-remote-v1" ‖ 0x00 ‖ channel ‖ 0x00 ‖
|
|
17
|
+
* phoneIdentity ‖ phoneEph ‖ macIdentity ‖ macEph)
|
|
18
|
+
*
|
|
19
|
+
* which binds both identities, both ephemeral keys and this channel. Each
|
|
20
|
+
* direction gets its own AES-256-GCM key:
|
|
21
|
+
*
|
|
22
|
+
* key = HKDF-SHA256(ikm = X25519(eph, eph'), salt = T, info = "oharness phone->mac" | "oharness mac->phone")
|
|
23
|
+
*
|
|
24
|
+
* and every sealed frame is `s.` + base64url(counter₈ ‖ ciphertext ‖ tag₁₆),
|
|
25
|
+
* nonce = 0x00000000 ‖ counter₈. Counters start at 0 and must arrive in
|
|
26
|
+
* order: the relay is one ordered socket, so anything else is a replay or a
|
|
27
|
+
* drop, and either way the channel is closed.
|
|
28
|
+
*
|
|
29
|
+
* The pairing code both screens show is the first four bytes of
|
|
30
|
+
* SHA-256("oharness-remote-sas" ‖ T), big-endian, mod 1 000 000, six digits.
|
|
31
|
+
* A relay that put itself in the middle would hold two different
|
|
32
|
+
* transcripts, so the two screens would show two different codes.
|
|
33
|
+
*/
|
|
34
|
+
const TRANSCRIPT_LABEL = "oharness-remote-v1";
|
|
35
|
+
const SAS_LABEL = "oharness-remote-sas";
|
|
36
|
+
const INFO_PHONE_TO_MAC = "oharness phone->mac";
|
|
37
|
+
const INFO_MAC_TO_PHONE = "oharness mac->phone";
|
|
38
|
+
export function b64(bytes) {
|
|
39
|
+
return Buffer.from(bytes).toString("base64");
|
|
40
|
+
}
|
|
41
|
+
export function unb64(text, length) {
|
|
42
|
+
if (typeof text !== "string")
|
|
43
|
+
throw new Error("expected base64");
|
|
44
|
+
const bytes = Buffer.from(text, "base64");
|
|
45
|
+
if (length !== undefined && bytes.length !== length)
|
|
46
|
+
throw new Error(`expected ${length} bytes`);
|
|
47
|
+
return bytes;
|
|
48
|
+
}
|
|
49
|
+
export function newIdentity() {
|
|
50
|
+
const { privateKey } = generateKeyPairSync("ed25519");
|
|
51
|
+
const pkcs8 = privateKey.export({ format: "der", type: "pkcs8" }).toString("base64");
|
|
52
|
+
return { identity: loadIdentity(pkcs8), pkcs8 };
|
|
53
|
+
}
|
|
54
|
+
export function loadIdentity(pkcs8) {
|
|
55
|
+
const privateKey = createPrivateKey({ key: Buffer.from(pkcs8, "base64"), format: "der", type: "pkcs8" });
|
|
56
|
+
return { privateKey, publicRaw: rawPublic(createPublicKey(privateKey)) };
|
|
57
|
+
}
|
|
58
|
+
function rawPublic(key) {
|
|
59
|
+
const jwk = key.export({ format: "jwk" });
|
|
60
|
+
if (typeof jwk.x !== "string")
|
|
61
|
+
throw new Error("not an OKP key");
|
|
62
|
+
return Buffer.from(jwk.x, "base64url");
|
|
63
|
+
}
|
|
64
|
+
function okpPublic(raw, crv) {
|
|
65
|
+
return createPublicKey({ key: { kty: "OKP", crv, x: raw.toString("base64url") }, format: "jwk" });
|
|
66
|
+
}
|
|
67
|
+
export function transcript(channel, phoneIdentity, phoneEph, macIdentity, macEph) {
|
|
68
|
+
return createHash("sha256")
|
|
69
|
+
.update(TRANSCRIPT_LABEL)
|
|
70
|
+
.update(Buffer.from([0]))
|
|
71
|
+
.update(channel)
|
|
72
|
+
.update(Buffer.from([0]))
|
|
73
|
+
.update(phoneIdentity)
|
|
74
|
+
.update(phoneEph)
|
|
75
|
+
.update(macIdentity)
|
|
76
|
+
.update(macEph)
|
|
77
|
+
.digest();
|
|
78
|
+
}
|
|
79
|
+
export function pairingCode(t) {
|
|
80
|
+
const digest = createHash("sha256").update(SAS_LABEL).update(t).digest();
|
|
81
|
+
return String(digest.readUInt32BE(0) % 1_000_000).padStart(6, "0");
|
|
82
|
+
}
|
|
83
|
+
/** One direction's key and counter. */
|
|
84
|
+
class Direction {
|
|
85
|
+
counter = 0n;
|
|
86
|
+
key;
|
|
87
|
+
constructor(key) {
|
|
88
|
+
this.key = key;
|
|
89
|
+
}
|
|
90
|
+
seal(plaintext) {
|
|
91
|
+
const counter = Buffer.alloc(8);
|
|
92
|
+
counter.writeBigUInt64BE(this.counter++);
|
|
93
|
+
const cipher = createCipheriv("aes-256-gcm", this.key, Buffer.concat([Buffer.alloc(4), counter]));
|
|
94
|
+
const body = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final(), cipher.getAuthTag()]);
|
|
95
|
+
return "s." + Buffer.concat([counter, body]).toString("base64url");
|
|
96
|
+
}
|
|
97
|
+
open(frame) {
|
|
98
|
+
if (!frame.startsWith("s."))
|
|
99
|
+
throw new Error("expected a sealed frame");
|
|
100
|
+
const bytes = Buffer.from(frame.slice(2), "base64url");
|
|
101
|
+
if (bytes.length < 8 + 16)
|
|
102
|
+
throw new Error("sealed frame too short");
|
|
103
|
+
const counter = bytes.readBigUInt64BE(0);
|
|
104
|
+
if (counter !== this.counter)
|
|
105
|
+
throw new Error("sealed frame out of order");
|
|
106
|
+
const decipher = createDecipheriv("aes-256-gcm", this.key, Buffer.concat([Buffer.alloc(4), bytes.subarray(0, 8)]));
|
|
107
|
+
decipher.setAuthTag(bytes.subarray(bytes.length - 16));
|
|
108
|
+
const plaintext = Buffer.concat([decipher.update(bytes.subarray(8, bytes.length - 16)), decipher.final()]).toString("utf8");
|
|
109
|
+
this.counter++;
|
|
110
|
+
return plaintext;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
export function readHello(message) {
|
|
114
|
+
if (message["hs"] !== "hello" || message["v"] !== 1)
|
|
115
|
+
throw new Error("expected a v1 hello");
|
|
116
|
+
const device = message["device"];
|
|
117
|
+
if (!device || typeof device.id !== "string" || !/^[A-Za-z0-9_-]{8,64}$/.test(device.id))
|
|
118
|
+
throw new Error("hello without a device id");
|
|
119
|
+
const name = typeof device.name === "string" && device.name.trim() ? device.name.trim().slice(0, 80) : device.id;
|
|
120
|
+
return { device: { id: device.id, name }, identity: unb64(message["identity"], 32), eph: unb64(message["eph"], 32) };
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* The Mac's side of one channel's handshake: answer the hello, then check the
|
|
124
|
+
* proof. `welcome()` is sent as plaintext; after `accept()` every frame is sealed.
|
|
125
|
+
*/
|
|
126
|
+
export class MacHandshake {
|
|
127
|
+
transcript;
|
|
128
|
+
code;
|
|
129
|
+
sendKey;
|
|
130
|
+
receiveKey;
|
|
131
|
+
welcomeFrame;
|
|
132
|
+
hello;
|
|
133
|
+
constructor(channel, hello, identity) {
|
|
134
|
+
this.hello = hello;
|
|
135
|
+
const { privateKey: ephPrivate, publicKey: ephPublic } = generateKeyPairSync("x25519");
|
|
136
|
+
const macEph = rawPublic(ephPublic);
|
|
137
|
+
this.transcript = transcript(channel, hello.identity, hello.eph, identity.publicRaw, macEph);
|
|
138
|
+
this.code = pairingCode(this.transcript);
|
|
139
|
+
const shared = diffieHellman({ privateKey: ephPrivate, publicKey: okpPublic(hello.eph, "X25519") });
|
|
140
|
+
this.receiveKey = Buffer.from(hkdfSync("sha256", shared, this.transcript, INFO_PHONE_TO_MAC, 32));
|
|
141
|
+
this.sendKey = Buffer.from(hkdfSync("sha256", shared, this.transcript, INFO_MAC_TO_PHONE, 32));
|
|
142
|
+
this.welcomeFrame = {
|
|
143
|
+
hs: "welcome",
|
|
144
|
+
identity: b64(identity.publicRaw),
|
|
145
|
+
eph: b64(macEph),
|
|
146
|
+
sig: b64(sign(null, this.transcript, identity.privateKey)),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
welcome() {
|
|
150
|
+
return this.welcomeFrame;
|
|
151
|
+
}
|
|
152
|
+
/** Checks the phone's proof; on success, the sealed session for this channel. */
|
|
153
|
+
accept(message) {
|
|
154
|
+
if (message["hs"] !== "proof")
|
|
155
|
+
throw new Error("expected the proof");
|
|
156
|
+
const ok = verify(null, this.transcript, okpPublic(this.hello.identity, "Ed25519"), unb64(message["sig"], 64));
|
|
157
|
+
if (!ok)
|
|
158
|
+
throw new Error("the phone's proof does not verify");
|
|
159
|
+
return new SealedSession(new Direction(this.sendKey), new Direction(this.receiveKey));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
export class SealedSession {
|
|
163
|
+
outgoing;
|
|
164
|
+
incoming;
|
|
165
|
+
constructor(outgoing, incoming) {
|
|
166
|
+
this.outgoing = outgoing;
|
|
167
|
+
this.incoming = incoming;
|
|
168
|
+
}
|
|
169
|
+
seal(message) {
|
|
170
|
+
return this.outgoing.seal(JSON.stringify(message));
|
|
171
|
+
}
|
|
172
|
+
open(frame) {
|
|
173
|
+
const value = JSON.parse(this.incoming.open(frame));
|
|
174
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
175
|
+
throw new Error("sealed frame is not an object");
|
|
176
|
+
return value;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// ---- The phone's half, in TypeScript: used by tests, and by anything that
|
|
180
|
+
// ---- wants to drive a Mac from Node. It mirrors RemoteCrypto.swift.
|
|
181
|
+
export class PhoneHandshake {
|
|
182
|
+
eph = generateKeyPairSync("x25519");
|
|
183
|
+
ephRaw = rawPublic(this.eph.publicKey);
|
|
184
|
+
channel;
|
|
185
|
+
device;
|
|
186
|
+
identity;
|
|
187
|
+
constructor(channel, device, identity) {
|
|
188
|
+
this.channel = channel;
|
|
189
|
+
this.device = device;
|
|
190
|
+
this.identity = identity;
|
|
191
|
+
}
|
|
192
|
+
hello() {
|
|
193
|
+
return { hs: "hello", v: 1, device: this.device, identity: b64(this.identity.publicRaw), eph: b64(this.ephRaw) };
|
|
194
|
+
}
|
|
195
|
+
/** Verifies the welcome and returns the proof to send, the code, and the sealed session. */
|
|
196
|
+
finish(welcome) {
|
|
197
|
+
if (welcome["hs"] !== "welcome")
|
|
198
|
+
throw new Error("expected the welcome");
|
|
199
|
+
const macIdentity = unb64(welcome["identity"], 32);
|
|
200
|
+
const macEph = unb64(welcome["eph"], 32);
|
|
201
|
+
const t = transcript(this.channel, this.identity.publicRaw, this.ephRaw, macIdentity, macEph);
|
|
202
|
+
if (!verify(null, t, okpPublic(macIdentity, "Ed25519"), unb64(welcome["sig"], 64))) {
|
|
203
|
+
throw new Error("the Mac's signature does not verify");
|
|
204
|
+
}
|
|
205
|
+
const shared = diffieHellman({ privateKey: this.eph.privateKey, publicKey: okpPublic(macEph, "X25519") });
|
|
206
|
+
const send = Buffer.from(hkdfSync("sha256", shared, t, INFO_PHONE_TO_MAC, 32));
|
|
207
|
+
const receive = Buffer.from(hkdfSync("sha256", shared, t, INFO_MAC_TO_PHONE, 32));
|
|
208
|
+
return {
|
|
209
|
+
proof: { hs: "proof", sig: b64(sign(null, t, this.identity.privateKey)) },
|
|
210
|
+
code: pairingCode(t),
|
|
211
|
+
macIdentity,
|
|
212
|
+
session: new SealedSession(new Direction(send), new Direction(receive)),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=remote-crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote-crypto.js","sourceRoot":"","sources":["../src/remote-crypto.ts"],"names":[],"mappings":"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"}
|