@gotcos/glasses-server 7.0.7 → 7.0.18
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/.env.example +19 -0
- package/CHANGELOG.md +170 -0
- package/docs/web-key-verifier-contract.md +378 -0
- package/managed-runtime-contract.json +9 -1
- package/package.json +10 -3
- package/server/bootstrap.ts +10 -0
- package/server/index.ts +126 -23
- package/server/lib/agent-session-recent.ts +321 -0
- package/server/lib/agent-session-store.ts +3 -3
- package/server/lib/api-auth.ts +37 -1
- package/server/lib/calendar-meetings.ts +70 -0
- package/server/lib/calendar-source.ts +54 -9
- package/server/lib/claude-hooks-installer.ts +111 -12
- package/server/lib/conversation.ts +56 -28
- package/server/lib/cors-reject-log.ts +51 -0
- package/server/lib/disk-io-meter.ts +202 -0
- package/server/lib/drop-service.ts +47 -12
- package/server/lib/drop-store.ts +21 -1
- package/server/lib/event-loop-stall.ts +62 -0
- package/server/lib/full-hold-engine.ts +114 -0
- package/server/lib/full-hold.ts +124 -0
- package/server/lib/g2-turn-provenance.ts +128 -9
- package/server/lib/listener-startup.ts +18 -0
- package/server/lib/meeting-batch-transcribe.ts +32 -5
- package/server/lib/permission-broker.ts +443 -11
- package/server/lib/secret-path-guard.ts +4 -1
- package/server/lib/session-cache-writer.ts +8 -1
- package/server/lib/session-hook-events.ts +23 -1
- package/server/lib/session-hooks-runtime.ts +34 -0
- package/server/lib/session-log.ts +313 -4
- package/server/lib/session-state-derive.ts +36 -0
- package/server/lib/session-stream-events.ts +25 -1
- package/server/lib/today-brief.ts +522 -58
- package/server/lib/turn-end-ask.ts +320 -0
- package/server/lib/turn-footer.ts +3 -3
- package/server/lib/web-control-integrity.ts +160 -0
- package/server/lib/web-control-offnet-page.ts +58 -0
- package/server/lib/web-control-static.ts +53 -9
- package/server/lib/web-key-authority.ts +372 -0
- package/server/lib/web-key-envelope.ts +98 -0
- package/server/lib/web-key-handoff.ts +135 -0
- package/server/lib/web-key-origin.ts +21 -0
- package/server/lib/web-key-passkey.ts +155 -0
- package/server/lib/web-key-registry.ts +825 -0
- package/server/lib/web-key-signer-app.ts +152 -0
- package/server/lib/web-session-auth.ts +133 -15
- package/server/lib/whisper-local.ts +93 -7
- package/server/lib/whisper-preview.ts +5 -3
- package/server/lib/work-orchestrator/snapshot.ts +17 -3
- package/server/lib/work-review-runtime.ts +17 -4
- package/server/routes/agent-session-bindings.ts +16 -1
- package/server/routes/agent-session-stream.ts +7 -0
- package/server/routes/drops.ts +7 -2
- package/server/routes/g2-turns.ts +35 -0
- package/server/routes/health.ts +11 -1
- package/server/routes/live-events.ts +6 -1
- package/server/routes/permission-broker.ts +26 -0
- package/server/routes/query-jobs.ts +3 -0
- package/server/routes/sessions.ts +15 -24
- package/server/routes/thread-turn-queue.ts +16 -9
- package/server/routes/today-brief.ts +91 -36
- package/server/routes/web-control.ts +37 -4
- package/server/routes/web-key.ts +284 -0
- package/server/routes/welcome-context.ts +6 -2
- package/server/routes/work-orchestrator.ts +12 -7
- package/server/scripts/write-web-control-manifest.mjs +43 -0
- package/server/web-control/.manifest.json +44 -0
- package/server/web-control/app.css +36 -0
- package/server/web-control/app.js +953 -57
- package/server/web-control/apple-touch-icon.png +0 -0
- package/server/web-control/index.html +14 -1
- package/server/web-control/panes/cos-chat.css +52 -6
- package/server/web-control/panes/cos-chat.js +364 -32
- package/server/web-control/panes/questions.js +135 -14
- package/server/web-control/panes/settings.js +1 -1
- package/server/web-control/panes/today-actions.css +35 -0
- package/server/web-control/panes/today-actions.js +75 -6
- package/server/web-control/panes/work.css +3 -0
- package/server/web-control/panes/work.js +178 -35
- package/server/web-signer/.manifest.json +11 -0
- package/server/web-signer/index.html +74 -0
- package/server/web-signer/signer-proof.js +348 -0
- package/server/web-signer/signer-store.js +39 -0
- package/server/web-signer/signer.css +23 -0
- package/server/web-signer/signer.js +341 -0
- package/shared/web-approval-packets.golden.json +124 -0
- package/shared/web-turn-envelope.ts +271 -0
|
Binary file
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
<meta name="apple-mobile-web-app-title" content="COS">
|
|
12
12
|
<title>COS Control</title>
|
|
13
13
|
<link rel="icon" href="/control/mark.svg" type="image/svg+xml">
|
|
14
|
+
<!-- iOS "Add to Home Screen" ignores SVG icons: without this, a saved Control Web shortcut is a grey letter. -->
|
|
15
|
+
<link rel="apple-touch-icon" href="/control/apple-touch-icon.png">
|
|
14
16
|
<link rel="stylesheet" href="/control/app.css">
|
|
15
17
|
<link rel="stylesheet" href="/control/control.css">
|
|
16
18
|
<link rel="stylesheet" href="/control/panes/speakers.css">
|
|
@@ -55,7 +57,11 @@
|
|
|
55
57
|
<div class="auth-card">
|
|
56
58
|
<svg class="mark" aria-hidden="true"><use href="#i-mark"/></svg>
|
|
57
59
|
<h1 id="auth-title">Connect this browser</h1>
|
|
58
|
-
<p>COS runs on your Mac. Sign in once
|
|
60
|
+
<p id="auth-intro">COS runs on your Mac. Sign in once. You stay signed in while you use COS here, for up to 30 days.</p>
|
|
61
|
+
<div id="auth-offline" class="auth-offline hidden" role="status">
|
|
62
|
+
<p id="auth-offline-text">Your Mac may be asleep, or this device may be offline or off Tailscale. This page checks again every 30 seconds.</p>
|
|
63
|
+
<button type="button" class="btn primary block" id="auth-retry">Try again</button>
|
|
64
|
+
</div>
|
|
59
65
|
<form id="auth-form">
|
|
60
66
|
<div id="auth-code-block">
|
|
61
67
|
<label for="auth-code">Sign-in code</label>
|
|
@@ -114,6 +120,8 @@
|
|
|
114
120
|
</header>
|
|
115
121
|
|
|
116
122
|
<main class="workspace" id="workspace">
|
|
123
|
+
<!-- W1: the Mac not answering, and the sign-in ending soon (app.js "Mac reachability and sign-in lifetime") -->
|
|
124
|
+
<div id="conn-notice" class="conn-notice" hidden></div>
|
|
117
125
|
<!-- SESSION QUESTIONS (panes/questions.js, 6.99.12): over every pane while one waits -->
|
|
118
126
|
<div id="sq-host" class="sq-host" aria-live="polite" hidden></div>
|
|
119
127
|
<!-- TODAY -->
|
|
@@ -136,6 +144,10 @@
|
|
|
136
144
|
<div class="today-cols">
|
|
137
145
|
<div class="today-main">
|
|
138
146
|
<div id="today-story" class="story-skel" aria-live="polite"><div class="skeleton"></div><div class="skeleton" style="width:82%"></div><div class="skeleton" style="width:58%"></div></div>
|
|
147
|
+
<form id="today-ask" class="cc-composer today-ask hidden" autocomplete="off" aria-label="Ask about this summary">
|
|
148
|
+
<textarea class="field cc-input" id="today-ask-input" rows="1" maxlength="2000" placeholder="Ask about this or steer a session" aria-label="Ask about this summary"></textarea>
|
|
149
|
+
<div class="cc-buttons"><button type="submit" class="cx-btn primary cc-ask">Send</button></div>
|
|
150
|
+
</form>
|
|
139
151
|
<section class="run-panel" aria-labelledby="run-title">
|
|
140
152
|
<div class="panel-head">
|
|
141
153
|
<h2 id="run-title" class="panel-title">Running<span id="run-count" class="count"></span></h2>
|
|
@@ -162,6 +174,7 @@
|
|
|
162
174
|
<div class="panel-head"><h2 id="next-title" class="panel-title">Next up</h2></div>
|
|
163
175
|
<div id="next-body" class="next-up"></div>
|
|
164
176
|
<div id="next-actions" class="next-actions"></div>
|
|
177
|
+
<div id="next-first-prep" class="next-first-prep hidden"></div>
|
|
165
178
|
<div id="next-later" class="next-later hidden" aria-label="Later today"></div>
|
|
166
179
|
</section>
|
|
167
180
|
</div>
|
|
@@ -56,10 +56,12 @@
|
|
|
56
56
|
/* ── the chat ─────────────────────────────────────────── */
|
|
57
57
|
.cc { --cc-you: color-mix(in srgb, var(--gold) 22%, var(--panel)); }
|
|
58
58
|
.cc-head { display: flex; align-items: center; gap: 12px; padding: 14px 0 12px; border-bottom: 1px solid var(--hairline); flex-wrap: wrap; }
|
|
59
|
-
.cc-head-text { min-width: 0; flex: 1; }
|
|
59
|
+
.cc-head-text { min-width: 0; flex: 1 1 16rem; }
|
|
60
|
+
/* W1 (open Duo, narrow chat column): the description was squeezed to four short lines beside All messages, Mark all read
|
|
61
|
+
and New thread. Below 16rem for the words, the links wrap beneath them. */
|
|
60
62
|
.cc-title { font: 500 24px/1.1 var(--display); color: var(--ink); margin: 0; }
|
|
61
63
|
.cc-sub { margin: 3px 0 0; font-size: 13px; line-height: 1.35; color: var(--sub); }
|
|
62
|
-
.cc-head-acts { display: flex; gap: 14px; }
|
|
64
|
+
.cc-head-acts { display: flex; flex-wrap: wrap; gap: 4px 14px; }
|
|
63
65
|
.cc-head-acts .link-btn { min-height: 36px; font-size: 14px; font-weight: 500; }
|
|
64
66
|
.cc-avatar { flex: none; width: 30px; height: 30px; border-radius: 8px; background: #2b211a; color: var(--gold); display: grid; place-items: center; }
|
|
65
67
|
.cc-avatar .icon { width: 17px; height: 17px; }
|
|
@@ -99,12 +101,45 @@
|
|
|
99
101
|
.cc-move .cc-choice { font-weight: 500; }
|
|
100
102
|
.cc-fine { margin: 8px 0 0; font-size: 12.5px; color: var(--tertiary); }
|
|
101
103
|
.cc-fine.warn { color: var(--hot); }
|
|
104
|
+
/* 7.0.9: a running answer's steps (its trail), newest last; once it ends, a quiet disclosure. A relayed message names the
|
|
105
|
+
session it went to. Every line wraps inside the card: the Duo folded is 382 px wide. */
|
|
106
|
+
.cc-steps-slot:empty { display: none; }
|
|
107
|
+
.cc-steps { list-style: none; margin: 8px 0 0; padding: 0 0 0 10px; border-left: 2px solid var(--hairline); display: grid; gap: 3px; min-width: 0; }
|
|
108
|
+
.cc-step { font-size: 13px; line-height: 1.4; color: var(--sub); overflow-wrap: anywhere; min-width: 0; }
|
|
109
|
+
.cc-step.prose { color: var(--ink); }
|
|
110
|
+
.cc-step.more { color: var(--tertiary); }
|
|
111
|
+
.cc-steps.live .cc-step:last-child { color: var(--ink); }
|
|
112
|
+
.cc-steps-done { margin-top: 8px; min-width: 0; }
|
|
113
|
+
.cc-steps-done > summary { cursor: pointer; min-height: 32px; display: flex; align-items: center; font-size: 13px; color: var(--tertiary); }
|
|
114
|
+
.cc-steps-done > summary::-webkit-details-marker { display: none; }
|
|
115
|
+
.cc-steps-done > summary::before { content: ''; width: 0; height: 0; margin-right: 8px; border-style: solid; border-width: 4px 0 4px 6px; border-color: transparent transparent transparent currentColor; transition: transform 160ms ease; }
|
|
116
|
+
.cc-steps-done[open] > summary::before { transform: rotate(90deg); }
|
|
117
|
+
@media (prefers-reduced-motion: reduce) { .cc-steps-done > summary::before { transition: none; } }
|
|
118
|
+
.cc-relay { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--hairline); min-width: 0; }
|
|
119
|
+
.cc-relay-line { margin: 0; font-size: 14px; line-height: 1.45; color: var(--ink); overflow-wrap: anywhere; }
|
|
120
|
+
.cc-relay-reply { margin: 6px 0 0; font-size: 14px; line-height: 1.45; color: var(--ink); overflow-wrap: anywhere; white-space: pre-wrap; }
|
|
121
|
+
/* 7.0.9: older questions, closed until opened, above the chat. */
|
|
122
|
+
.cc-archive { margin: 0 0 14px; padding: 0 0 10px; border-bottom: 1px solid var(--hairline); min-width: 0; }
|
|
123
|
+
.cc-archive > summary { cursor: pointer; min-height: 36px; display: flex; align-items: center; font-size: 13.5px; color: var(--sub); }
|
|
124
|
+
.cc-archive > summary::-webkit-details-marker { display: none; }
|
|
125
|
+
.cc-archive > summary::before { content: ''; width: 0; height: 0; margin-right: 8px; border-style: solid; border-width: 4px 0 4px 6px; border-color: transparent transparent transparent currentColor; transition: transform 160ms ease; }
|
|
126
|
+
.cc-archive[open] > summary::before { transform: rotate(90deg); }
|
|
127
|
+
@media (prefers-reduced-motion: reduce) { .cc-archive > summary::before { transition: none; } }
|
|
128
|
+
.cc-archive > .cc-fine { margin: 0 0 10px; }
|
|
129
|
+
.cc-relay-who { display: block; font-size: 12.5px; color: var(--tertiary); margin-bottom: 2px; }
|
|
102
130
|
.cc-steer { display: flex; gap: 8px; margin-top: 10px; }
|
|
103
131
|
.cc-steer .field { flex: 1; min-width: 0; height: 36px; }
|
|
104
132
|
|
|
105
133
|
/* ── the composer: two visible buttons, no key needed ─── */
|
|
106
134
|
.cc-composer { position: sticky; bottom: 0; z-index: 5; background: var(--page); border-top: 1px solid var(--hairline); padding: 10px 0 calc(10px + var(--safe-bottom, env(safe-area-inset-bottom, 0px)));
|
|
107
|
-
display:
|
|
135
|
+
display: flex; flex-wrap: wrap; gap: 8px 10px; align-items: flex-end; }
|
|
136
|
+
/* W1 (Miles 2026-11-09, open Duo: "Ask COS, or drop a thought, a task, a ..." wrapped and clipped beside the camera,
|
|
137
|
+
clip, Ask and Drop in the three-column split). The row follows the composer's own width, not the screen: the words need
|
|
138
|
+
19rem (every composer placeholder is 36 characters or fewer), and when the buttons do not fit beside that they move to
|
|
139
|
+
the row below, at its right. Panes are resizable, so no breakpoint can know this. Same rule as the reader's box. */
|
|
140
|
+
.cc-composer > .cc-input { flex: 1 1 19rem; min-width: 0; }
|
|
141
|
+
.cc-composer > .cc-buttons { flex: none; margin-left: auto; }
|
|
142
|
+
.cc-composer > .cc-chips, .cc-composer > .cc-foot, .cc-composer > .cc-note { flex: 1 1 100%; min-width: 0; }
|
|
108
143
|
.cc-input { min-height: 44px; max-height: 140px; padding: 11px 12px; font-size: 16px; border-radius: 12px; }
|
|
109
144
|
.cc-buttons { display: flex; gap: 8px; }
|
|
110
145
|
.cc-buttons .cx-btn { height: 44px; padding: 0 16px; font-size: 15px; border-radius: 12px; }
|
|
@@ -119,8 +154,8 @@
|
|
|
119
154
|
.cc-note { grid-column: 1 / -1; margin: 0; font-size: 13px; color: var(--hot); }
|
|
120
155
|
/* A phone at 390 px: the box on its own row, the buttons under it, the menus under those. */
|
|
121
156
|
@media (max-width: 480px) {
|
|
122
|
-
.cc-composer {
|
|
123
|
-
.cc-buttons { justify-content: flex-end; }
|
|
157
|
+
.cc-composer > .cc-input { flex-basis: 100%; }
|
|
158
|
+
.cc-composer > .cc-buttons { flex: 1 1 100%; justify-content: flex-end; }
|
|
124
159
|
.cc-buttons .cx-btn { flex: 1; justify-content: center; }
|
|
125
160
|
.cc-buttons .cc-attach { flex: none; }
|
|
126
161
|
}
|
|
@@ -249,13 +284,24 @@ html.kb-up .cc-kb .cc-model .field { width: 100%; }
|
|
|
249
284
|
their own above the words, Take photo and the clip beside Fork and Send, and the limits in plain words under the chips. */
|
|
250
285
|
.att-composer { flex-wrap: wrap; }
|
|
251
286
|
.att-composer .att-files { flex: 1 1 100%; padding: 2px 0 4px; }
|
|
287
|
+
/* W1 (Miles 2026-11-09 21:24, closed Duo screenshot: "Continue this session" wrapped onto two lines, the second
|
|
288
|
+
clipped). The phone's real width did not trip the 430 px rule below, so the row now follows the space the box itself
|
|
289
|
+
has: the words need at least 19rem (the longest placeholder, "Message this session (not an answer)", is about 277 px
|
|
290
|
+
in the kit font), and when the buttons do not fit beside that they move to the row below, at its right. Wide panes
|
|
291
|
+
keep the one-row layout. Measured in WebKit at 382, 440, 520 and 951 px: lanes/W1_evidence/duo_layout_*. */
|
|
292
|
+
.att-composer > textarea { flex: 1 1 19rem; min-width: 0; }
|
|
293
|
+
.att-composer > .composer-actions { margin-left: auto; }
|
|
252
294
|
/* 6.99.30 (canary): the folded Sessions reader squeezed the box to about 101 px beside Fork, the clip and Send. Under
|
|
253
295
|
430 px the words get their own full row and the buttons sit on the row below, at its right. */
|
|
254
296
|
@media (max-width: 429px) {
|
|
255
297
|
.att-composer > textarea { flex: 1 1 100%; }
|
|
256
|
-
.att-composer > .composer-actions { margin-left: auto; }
|
|
257
298
|
}
|
|
258
299
|
.att-composer .att-files.hidden { display: none; }
|
|
300
|
+
.phone-approval-packet { flex: 1 1 100%; min-width: 0; }
|
|
301
|
+
.phone-approval-packet label { display: block; font-size: 13px; margin-bottom: 4px; }
|
|
302
|
+
.phone-approval-packet select { width: 100%; max-width: 100%; font: inherit; color: inherit; background: var(--card, transparent); }
|
|
303
|
+
.phone-approval-packet pre { white-space: pre-wrap; overflow-wrap: anywhere; font: 12px/1.4 ui-monospace, monospace; max-height: 11rem; overflow-y: auto; margin: 6px 0; }
|
|
304
|
+
.composer-actions:has([data-phone-offer]) { flex-wrap: wrap; }
|
|
259
305
|
.att-clip, .ta-clip { display: inline-flex; gap: 6px; }
|
|
260
306
|
.att-clip:empty { display: none; }
|
|
261
307
|
.att-clip .cc-attach { height: 38px; width: 42px; border-radius: var(--radius-sm); }
|