@gotcos/glasses-server 6.42.1 → 6.43.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/CHANGELOG.md CHANGED
@@ -1,3 +1,72 @@
1
+ ## 6.43.0
2
+
3
+ The brief is waiting before you ask for it.
4
+
5
+ A start-of-day brief now runs on a schedule inside the server and lands in
6
+ the inbox as an ordinary numbered reply — no prompt, no "run the good-morning
7
+ skill", no phone awake at 07:00. Jun Kiat Lee's first-week note said it
8
+ plainly: he deployed COS to his G2 expecting a push at the start of the day and
9
+ nothing came, because until now the only thing that could start a brief was a
10
+ person typing. The server is the one process awake at that hour, so it owns
11
+ the schedule.
12
+
13
+ What you get, by default: weekdays at 07:00 in the Mac's own timezone, four
14
+ sections any COS brain can fill — Calendar, From recent meetings (decisions,
15
+ deadlines, owed items), Due (tasks inside a seven-day horizon), and Waiting on
16
+ you (unanswered mentions and asks across whatever channels the brain can
17
+ read). Everything else in the catalog — Knowledge graph, Reflection, Health,
18
+ an Opening reading, a Metrics pulse, a workspace skill, a custom section — is
19
+ off until you turn it on. The brief is composed from the sources you choose,
20
+ in the order you choose, with the windows you choose, so it is yours rather
21
+ than a template with your name on it.
22
+
23
+ How it works, so the cost is legible:
24
+
25
+ - One durable query job per local calendar day, submitted to the same
26
+ coordinator every phone prompt uses. It survives the phone being asleep and
27
+ is projected into the conversation store with a reserved message number when
28
+ it completes, so the companion's history hydration surfaces it like any
29
+ reply.
30
+ - The fire is remembered in a ledger written BEFORE admission. A crash between
31
+ that write and the 202 is resumed by a per-day client identity, never re-run.
32
+ A failed admission (store degraded, server draining) retries at most three
33
+ times, two minutes apart, then gives the day up.
34
+ - A Mac asleep through the slot still fires inside a catch-up window (three
35
+ hours by default, up to twelve). Past that, the day is skipped rather than
36
+ delivered at lunch.
37
+ - "Run now" is capped at five a day and refused while a brief is live.
38
+ - The whole thing is inert when COS Control's "Background jobs" switch is off
39
+ or maintenance admissions are closed. The prompt is read-only by contract:
40
+ it forbids sending, creating, or editing anything.
41
+
42
+ The prompt itself carries the evidence discipline the good-morning routine
43
+ learned the hard way: a source that cannot be read produces one honest
44
+ "unavailable" line; nothing is invented; only items with a hard edge (a
45
+ decision, a date, a dollar figure, an owner) make the cut; the scribe's
46
+ extracted action-item list is never pasted verbatim. Enable the "Workspace
47
+ skill" source with `/good-morning` and that skill's output IS the brief —
48
+ which is how Miles's own routine rides this without being rewritten.
49
+
50
+ Surface:
51
+
52
+ - `GET /api/morning-brief` — config, the source catalog (labels, descriptions,
53
+ option schemas a settings screen can render), status with `nextRunAt`, and
54
+ recent runs with live job status and the message number each produced.
55
+ - `PUT /api/morning-brief` — patch any field; a bad time, zone, model, or
56
+ skill name is a 400 with a named code, never a silent keep.
57
+ - `POST /api/morning-brief/run` — fire one now (202; 409 while one runs; 429
58
+ past the daily cap).
59
+ - `GET /api/morning-brief/preview` — the exact prompt today's brief would send.
60
+ - `/api/health` advertises `features.morningBrief` and
61
+ `capabilities.morningBrief` (`enabled`, `time`, `timezone`, `nextRunAt`,
62
+ `lastRunAt`, `lastRunStatus`, `gate`) — times and gate only, no prompt, no
63
+ ids.
64
+
65
+ Config lives at `~/.cos-glasses/data/morning-brief/config.json` (0600), the
66
+ ledger beside it. `COS_MORNING_BRIEF_DIR` relocates both. Schedule arithmetic
67
+ uses Node's Intl in the configured IANA zone, and is covered across both US DST
68
+ transitions and a zone east of UTC.
69
+
1
70
  ## 6.42.1
2
71
 
3
72
  Hardening of the 6.42.0 display-stream ticket, from a four-validator QA pass
package/README.md CHANGED
@@ -208,6 +208,29 @@ Telegram activity export is disabled by default even when a private COS
208
208
  pipeline contains `.telegram_config.json`; enable it only with the explicit
209
209
  `COS_TELEGRAM_NOTIFICATIONS=1` opt-in.
210
210
 
211
+ ## Morning brief (6.43.0)
212
+
213
+ A start-of-day brief runs on a schedule inside the server and waits in the
214
+ inbox as a numbered reply. Default: weekdays at 07:00 in the Mac's timezone,
215
+ with Calendar, recent-meeting decisions, tasks due this week, and what is
216
+ waiting on you. Turn on more sources (knowledge graph, reflection, health, an
217
+ opening reading, a metrics pulse, one of your own skills such as
218
+ `/good-morning`, a custom section), reorder them, and set their windows from
219
+ COS Control or the companion, or directly:
220
+
221
+ ```bash
222
+ curl -H "X-COS-Token: $COS_TOKEN" http://127.0.0.1:3141/api/morning-brief
223
+ curl -H "X-COS-Token: $COS_TOKEN" -X PUT -H 'Content-Type: application/json' \
224
+ -d '{"time":"06:30","sources":[{"id":"skill","enabled":true,"options":{"name":"/good-morning"}}]}' \
225
+ http://127.0.0.1:3141/api/morning-brief
226
+ curl -H "X-COS-Token: $COS_TOKEN" -X POST http://127.0.0.1:3141/api/morning-brief/run
227
+ ```
228
+
229
+ One provider run per local day, remembered in a ledger so a restart never
230
+ doubles it; a Mac asleep at the slot still fires inside a three-hour catch-up
231
+ window; "Run now" is capped at five a day. Off entirely when Background jobs
232
+ are off. The brief is read-only by contract.
233
+
211
234
  ## Speaker diarization (opt-in)
212
235
 
213
236
  Without a voiceprint model this server does not classify speakers at all — it
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gotcos/glasses-server",
3
- "version": "6.42.1",
3
+ "version": "6.43.0",
4
4
  "description": "COS Glasses \u2014 self-hosted AI heads-up-display server for Even G2 smart glasses, powered by Claude Code, Codex, Cursor Agent CLI, or local Ollama",
5
5
  "type": "module",
6
6
  "bin": {
package/server/index.ts CHANGED
@@ -83,6 +83,8 @@ import { initializeServerInstanceId } from './lib/server-instance-id.js'
83
83
  import { appendPrivateEnvBlock, UnsafeUserConfigPathError } from './lib/secure-user-config.js'
84
84
  import { getTranscriptionProfileStatus } from './lib/profile.js'
85
85
  import { createQueryJobsRouter } from './routes/query-jobs.js'
86
+ import { createMorningBriefRouter } from './routes/morning-brief.js'
87
+ import { getMorningBriefScheduler, startMorningBriefScheduler, stopMorningBriefScheduler } from './lib/morning-brief-runtime.js'
86
88
  import {
87
89
  initQueryJobRuntime,
88
90
  preparePublicDurableQueryAdmission,
@@ -488,6 +490,9 @@ app.use('/api', createQueryJobsRouter(queryJobCoordinator, {
488
490
  prepareAdmission: preparePublicDurableQueryAdmission,
489
491
  }))
490
492
  app.use('/api', queryRouter)
493
+ // The scheduled start-of-day brief: settings, status, run-now. Same auth as
494
+ // every other settings route; the brief itself is an ordinary durable job.
495
+ app.use('/api', createMorningBriefRouter(getMorningBriefScheduler))
491
496
  app.use('/api', providerProofRouter)
492
497
  app.use('/api', transcribeRouter)
493
498
  // Ported from cos-glasses-app in 6.24.0. The companion's Sessions tab has been
@@ -713,6 +718,7 @@ async function gracefulShutdown(): Promise<void> {
713
718
  gracefulShutdownStarted = true
714
719
  const forceExit = setTimeout(() => process.exit(1), 8_000)
715
720
  forceExit.unref?.()
721
+ stopMorningBriefScheduler()
716
722
  try {
717
723
  await shutdownQueryJobRuntime('server_shutdown')
718
724
  } catch (error) {
@@ -909,6 +915,10 @@ listenRequiredServers(listeners).then(() => {
909
915
  } else {
910
916
  console.log('[COS API] Durable query jobs: disabled by COS_DURABLE_QUERY_JOBS=0')
911
917
  }
918
+ // The morning brief rides the durable coordinator, so it starts only once
919
+ // that store is ready. Its own tick checks the durable-jobs switch and the
920
+ // maintenance gate, so starting it here is safe when either is off.
921
+ startMorningBriefScheduler()
912
922
  }).catch(error => {
913
923
  // The store remains degraded and rejects admission. Legacy /api/query is
914
924
  // still mounted, so the kill switch is an immediate rollback.