@gotcos/glasses-server 6.44.16 → 6.45.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.
Files changed (55) hide show
  1. package/CHANGELOG.md +69 -51
  2. package/README.md +9 -0
  3. package/bin/memory-setup.cjs +55 -0
  4. package/memory-runtime/cos-memory-runtime-0.1.0.tar.gz +0 -0
  5. package/memory-runtime/runtime.json +7 -0
  6. package/package.json +6 -3
  7. package/server/index.ts +4 -4
  8. package/server/lib/adaptive-playback-audio.ts +1 -1
  9. package/server/lib/agent-session-store.ts +139 -28
  10. package/server/lib/archive-search.ts +1 -1
  11. package/server/lib/attached-provider-adapter.ts +1 -1
  12. package/server/lib/attached-workspace.ts +3 -3
  13. package/server/lib/chunk-embedding-store.ts +1 -1
  14. package/server/lib/context-files.ts +1 -1
  15. package/server/lib/cos-context-browser.ts +17 -6
  16. package/server/lib/cos-operations-meetings.ts +1 -1
  17. package/server/lib/domains.ts +2 -2
  18. package/server/lib/maintenance-lifecycle.ts +1 -1
  19. package/server/lib/meeting-audio-archive.ts +3 -3
  20. package/server/lib/meeting-corrections.ts +3 -3
  21. package/server/lib/meeting-relabel-enrolment.ts +1 -1
  22. package/server/lib/meeting-relabel.ts +2 -2
  23. package/server/lib/meeting-scribe-content.ts +7 -7
  24. package/server/lib/meeting-speaker-review.ts +3 -3
  25. package/server/lib/meeting-summary.ts +1 -1
  26. package/server/lib/message-era-reset.ts +1 -1
  27. package/server/lib/message-era.ts +1 -1
  28. package/server/lib/morning-brief-config.ts +1 -1
  29. package/server/lib/morning-brief-coverage.ts +1 -1
  30. package/server/lib/occupancy-probes.ts +7 -4
  31. package/server/lib/ollama-tools.ts +1 -1
  32. package/server/lib/python-bridge.ts +6 -4
  33. package/server/lib/query-job-types.ts +1 -1
  34. package/server/lib/session-stream-events.ts +3 -3
  35. package/server/lib/session-transcript-watcher.ts +1 -1
  36. package/server/lib/speaker-calibration-log.ts +1 -1
  37. package/server/lib/speaker-name.ts +1 -1
  38. package/server/lib/thread-occupancy.ts +1 -1
  39. package/server/lib/thread-turn-queue-deliver.ts +1 -1
  40. package/server/lib/thread-turn-queue.ts +3 -3
  41. package/server/lib/video-upload-v2.ts +1 -1
  42. package/server/lib/voice-profile-store.ts +2 -2
  43. package/server/lib/whisper-metal-gate.ts +1 -1
  44. package/server/routes/agent-session-bindings.ts +2 -2
  45. package/server/routes/agent-session-stream.ts +1 -1
  46. package/server/routes/agent-sessions.ts +2 -2
  47. package/server/routes/claude-sessions.ts +1 -1
  48. package/server/routes/health.ts +1 -1
  49. package/server/routes/meeting.ts +8 -8
  50. package/server/routes/memory.ts +45 -7
  51. package/server/routes/prompt-drafts.ts +1 -1
  52. package/server/routes/session-index.ts +1 -1
  53. package/server/routes/thread-turn-queue.ts +10 -4
  54. package/server/routes/transcribe-stream.ts +1 -1
  55. package/server/routes/voice.ts +4 -4
package/CHANGELOG.md CHANGED
@@ -1,9 +1,27 @@
1
+ ## 6.45.0
2
+
3
+ Versioned local memory and explicit session identity for COS Control 0.5.207.
4
+
5
+ - Ship the standalone memory runtime with owner-scoped journal records,
6
+ revision checks, idempotent operations, deletion frontiers, source provenance,
7
+ review history, and bounded relationship paths with identity constraints.
8
+ - Expose memory workspace capabilities and installation diagnostics. Optional
9
+ private graph SDK integration remains in the configured local harness.
10
+ - Resolve Claude Desktop aliases using explicit CLI identifiers, preserve real
11
+ forks with identical titles, and reject ambiguous or missing transcript targets.
12
+ - Allow bounded descriptor scans on busy Macs while keeping attachment refusals
13
+ conservative. Reuse a refusal within one queue pass; check again before delivery.
14
+ - Learning evidence distinguishes retrieval from application and observed
15
+ outcomes. The release does not claim measured long-term error reduction.
16
+ - Refresh the tested query-parser dependency to qs 6.16.0, closing the
17
+ production dependency audit findings for array limits and isBuffer handling.
18
+
1
19
  ## 6.44.16
2
20
 
3
21
  A G2 recording keeps its session id when its sidecar only exists in the server's own recordings folder.
4
22
 
5
- - Chelsie and Queen, 2026-09-08: "Meetings to review is empty, and it says 3
6
- recent meetings have no session id." On Miles's Mac the same three-row case
23
+ - Casey and Sam, 2026-09-08: "Meetings to review is empty, and it says 3
24
+ recent meetings have no session id." On the user's Mac the same three-row case
7
25
  was three KC-week recordings whose markdown reached the operations tree
8
26
  through git while the `.g2-chunks.json` sidecar, which is gitignored there,
9
27
  did not; the row lost its session id and Speakers could not open it.
@@ -18,8 +36,8 @@ A G2 recording keeps its session id when its sidecar only exists in the server's
18
36
 
19
37
  Voice profiles named after a spoken sentence are repaired at load.
20
38
 
21
- - Chelsie 2026-09-08: her `voice-profiles.json` held two profiles whose name
22
- was the entire enrolment speech ("My Voice My Name Is Chelsie Hodgkiss And I
39
+ - Casey 2026-09-08: her `voice-profiles.json` held two profiles whose name
40
+ was the entire enrolment speech ("My Voice My Name Is Casey Example And I
23
41
  Am The Director…", ~600 characters), written by a client older than the
24
42
  8/25 guards. Speaker ID was "active" and could never match anything, and the
25
43
  file cannot be repaired by hand because the server rewrites it from memory.
@@ -38,17 +56,17 @@ Voice profiles named after a spoken sentence are repaired at load.
38
56
  The Manage sheet's merge, with a preview, a worker and a receipt, plus a
39
57
  duplicates scan that proposes and never merges.
40
58
 
41
- - Miles 2026-09-08: "Build the Manage merge path with the preview", and
42
- "address any of the obvious duplicates like the miels and queen example
43
- from above without clobbering entities. You did good in deflecting miles
44
- mallard vs the other miles profiles."
59
+ - the user 2026-09-08: "Build the Manage merge path with the preview", and
60
+ "address any of the obvious duplicates like the alxe and sam example
61
+ from above without clobbering entities. You did good in deflecting alex
62
+ mallard vs the other alex profiles."
45
63
  - `POST /api/context/graph/merge/preview` `{ source, target }`: both entities
46
64
  from this Mac's index, shared neighbors, the effect (relationships moved and
47
65
  collapsed, texts re-embedded, about how long), a name signal, warnings
48
66
  (types differ, larger into smaller, nothing links them, a large merge), and
49
67
  `blocked` with its reason for a pair the graph knows to be different people
50
- (Miles Ukaoma / Miles Mallard, Manoj Bisht / Manoj Kumar, the Kyles, the
51
- Jacobuses, and any pair the user kept apart).
68
+ (Alex Example / Alex Other, Jordan Example / Jordan Other, the Alexes, the
69
+ Jordans, and any pair the user kept apart).
52
70
  - `POST /api/context/graph/merge` `{ source, target, confirm: true, rule? }`:
53
71
  starts ONE detached worker on the ingestion owner and answers 202 with a
54
72
  ticket and the receipt. The worker takes the exclusive ingest lock, copies
@@ -66,7 +84,7 @@ duplicates scan that proposes and never merges.
66
84
  whole names within two letters, one name spelling out the other, a bare
67
85
  first name that matches exactly one full name), grouped under the full name
68
86
  with the most connections, with shared-neighbor counts and a confidence.
69
- Possessives ("Miles Ukaoma's Son") and ambiguous first names are left alone;
87
+ Possessives ("Alex Example's Son") and ambiguous first names are left alone;
70
88
  blocked pairs never share a group. Nothing here merges.
71
89
  - Four bridge commands: `graph-merge-preview`, `graph-merge`,
72
90
  `graph-merge-status`, `graph-duplicates` (28 in the parity set).
@@ -78,7 +96,7 @@ duplicates scan that proposes and never merges.
78
96
 
79
97
  Prune or accept a captured memory, and guardrails that prune nonsense for you.
80
98
 
81
- - Miles 2026-09-07, looking at a captured decision that read "AAAA...":
99
+ - the user 2026-09-07, looking at a captured decision that read "AAAA...":
82
100
  "we need the ability to either prune or accept the memory", and "an
83
101
  automated review ... another person could set their own guardrails that
84
102
  automatically just prune out stuff like this."
@@ -101,7 +119,7 @@ Prune or accept a captured memory, and guardrails that prune nonsense for you.
101
119
 
102
120
  The Knowledge down-select, and a fail-closed embedding gate.
103
121
 
104
- - Miles 2026-09-07: the local embeddings are the free path for people who
122
+ - the user 2026-09-07: the local embeddings are the free path for people who
105
123
  run COS without an OpenAI key, and the setup's job is to help each person
106
124
  down-select. The `embedding` block now carries `preference.local_only`
107
125
  (the one question the user answers: may text leave this Mac?),
@@ -474,7 +492,7 @@ learned the hard way: a source that cannot be read produces one honest
474
492
  decision, a date, a dollar figure, an owner) make the cut; the scribe's
475
493
  extracted action-item list is never pasted verbatim. Enable the "Workspace
476
494
  skill" source with `/good-morning` and that skill's output IS the brief —
477
- which is how Miles's own routine rides this without being rewritten.
495
+ which is how the user's own routine rides this without being rewritten.
478
496
 
479
497
  Surface:
480
498
 
@@ -970,7 +988,7 @@ topics, decisions and action items. Until now they got none of that, and the
970
988
  server compensated by returning the TRANSCRIPT in the summary slot -- which is
971
989
  why this was reported as "no proper summary and transcription."
972
990
 
973
- FEATURE DEFAULTS NOW ON (Miles 2026-08-25)
991
+ FEATURE DEFAULTS NOW ON (the user 2026-08-25)
974
992
 
975
993
  Ship the capability active; users opt out of what they do not need. Each gate
976
994
  stays strict in the other direction -- only a literal '0' disables, so a stray
@@ -1321,7 +1339,7 @@ the assertion written for them.
1321
1339
  COS Control's "Show Claude sessions" checkbox sourced its state from
1322
1340
  `GET /api/claude-sessions` -- the call that also lists every session -- and the
1323
1341
  panel never made that call. The box rendered false while the setting was true, and
1324
- Miles enabled it four times against a control that could only ever show him one
1342
+ the user enabled it four times against a control that could only ever show him one
1325
1343
  value. Health is what every other toggle on that panel already reads, and this is
1326
1344
  a pure env read, so it costs nothing on a poll.
1327
1345
 
@@ -1761,7 +1779,7 @@ bring the leftover cards back.
1761
1779
 
1762
1780
 
1763
1781
  ## 6.36.7
1764
- - **A turn spoken at a busy thread is now queued instead of refused.** Miles: "if
1782
+ - **A turn spoken at a busy thread is now queued instead of refused.** the user: "if
1765
1783
  there's a session that's still running, that would just put it into the queue the same
1766
1784
  way that the user has the ability to do so." The thread was never stuck — measured at
1767
1785
  the moment he asked, its transcript mtime was 3s old against a 30s window, so the gate
@@ -1778,7 +1796,7 @@ bring the leftover cards back.
1778
1796
  attach and turn routes. Those carry the gate, the target fence, the per-target claim,
1779
1797
  the watermark, the idempotency ledger and the child-pid accounting; a second copy in a
1780
1798
  background worker would be a second place for the gate to drift.
1781
- - **The watermark exemption, approved explicitly by Miles.** A queued turn drains after
1799
+ - **The watermark exemption, approved explicitly by the user.** A queued turn drains after
1782
1800
  the thread has moved on — that is what it waited for — so its binding is minted fresh
1783
1801
  at delivery. Checked as normal, a queue would fail 100% of the time. An interactive
1784
1802
  turn still gets the full divergence check.
@@ -1793,7 +1811,7 @@ bring the leftover cards back.
1793
1811
 
1794
1812
 
1795
1813
  ## 6.36.6
1796
- - **The session digest follows the thread instead of its opening.** Miles, from the
1814
+ - **The session digest follows the thread instead of its opening.** the user, from the
1797
1815
  lens: "It's currently showing a legacy session that I had over a day ago... The
1798
1816
  discussion should show the questions that we're asking and a summary of those most
1799
1817
  recent things, not something that's the 'first' message." The whole budget now goes
@@ -2017,7 +2035,7 @@ bring the leftover cards back.
2017
2035
  - **Session bodies get a real digest.** `GET /api/agent-sessions/:provider/:id` adds
2018
2036
  `discussion_digest`: up to **2000 chars** of what actually happened — the opening
2019
2037
  ask, the most recent user turns in order, and where the assistant left off.
2020
- - **The list row is untouched at 180.** Miles: "it should be in the body not the
2038
+ - **The list row is untouched at 180.** the user: "it should be in the body not the
2021
2039
  title, the row should be no more than the 180 characters." `discussion_summary`
2022
2040
  keeps its 180-char budget for the single-line row; the digest is a separate field
2023
2041
  the detail page reads. One shared field could not serve both — a 2000-char gist
@@ -2152,8 +2170,8 @@ bring the leftover cards back.
2152
2170
 
2153
2171
  **Measured reach, so callers do not assume more than it delivers.** The distance
2154
2172
  budget is 1 edit for 5-8 character words, so it catches single-edit misses
2155
- (`Austen` → Austin, `Nyala` → Niala) but NOT `Miyala` → Niala (2 edits) or
2156
- `Yukoma` → Ukaoma (3). Wiring it does **not** remove the need for explicit
2173
+ (`Austen` → Austin, `Nyala` → Riley) but NOT `Rileyy` → Riley (2 edits) or
2174
+ `Exampel` → Example (3). Wiring it does **not** remove the need for explicit
2157
2175
  `whisper_corrections` entries on multi-edit misses; the new test asserts both
2158
2176
  directions so that is not re-derived later.
2159
2177
 
@@ -2244,7 +2262,7 @@ four defects, since the writer was correct in every case. 8 mutations, all caugh
2244
2262
 
2245
2263
  A video attachment is summarized from stills. The old rule was one still per 15
2246
2264
  seconds, floored at 1 and capped at 8, which gave a 12 second clip **one** frame
2247
- and a 44 second clip **three** - not enough to tell what a video contains. Miles,
2265
+ and a 44 second clip **three** - not enough to tell what a video contains. the user,
2248
2266
  on a fridge sweep: "it only selects three chunks from the video."
2249
2267
 
2250
2268
  - Frame count is now `clamp(round(seconds / 6), 8, 16)`. A 12s clip and a 44s
@@ -2354,7 +2372,7 @@ Proof: 460 suites / 1,515 tests, isolated runtime directory, plus clean TypeScri
2354
2372
 
2355
2373
  ## 6.24.3
2356
2374
 
2357
- Auto-recovery of quarantined audio has never run in production. Miles saw the symptom
2375
+ Auto-recovery of quarantined audio has never run in production. the user saw the symptom
2358
2376
  for three turns: "1 recoverable" that opening the phone app could not clear.
2359
2377
 
2360
2378
  - **My call sat inside a bare `catch {}`.** `autoRecoverOneQuarantinedCapture()` was one
@@ -2427,8 +2445,8 @@ sidebar does.
2427
2445
  - `project` comes from the `cwd` on the session records, not from decoding the
2428
2446
  directory name. Claude Code replaces path separators with dashes and a real dash is
2429
2447
  indistinguishable from a separator afterwards, so
2430
- `-Users-ukaoma-Documents-GitHub-Ukaoma-Chief-Of-Staff-MU-Chief-Staff` decoded to
2431
- "Ukaoma-Chief-Of-Staff-MU-Chief-Staff" where the sidebar says "MU-Chief-Staff".
2448
+ `-Users-example-Documents-GitHub-Example-Chief-Of-Staff-MU-Chief-Staff` decoded to
2449
+ "Example-Chief-Of-Staff-MU-Chief-Staff" where the sidebar says "MU-Chief-Staff".
2432
2450
 
2433
2451
  ## 6.24.0
2434
2452
 
@@ -2454,7 +2472,7 @@ sessions on this Mac arrives behind a flag.
2454
2472
  31.7 MB was parsed synchronously per request, the detail endpoint included, on a
2455
2473
  process that also streams live audio; now async and cached against file identity
2456
2474
  (161ms cold, 15ms warm). And the filename filter matched iCloud sync-conflict
2457
- duplicates: `.session_index_cache_Ukaoma-Mac-Studio 3.json` shared 543 of its 602
2475
+ duplicates: `.session_index_cache_Example-Mac-Studio 3.json` shared 543 of its 602
2458
2476
  rows with the canonical file, so the merged list served 543 duplicates. Verified on
2459
2477
  real data: 37,700 naive becomes 37,157 served, exactly 543 removed. Filtering ` N`
2460
2478
  filenames would have been wrong in the other direction, since ` 2.json` holds 245
@@ -2554,7 +2572,7 @@ hardcoded. 14 new tests here, full suite 1425 serially.
2554
2572
 
2555
2573
  ## 6.23.0
2556
2574
 
2557
- A recording whose phone goes away now becomes a meeting on its own. Miles: "we end
2575
+ A recording whose phone goes away now becomes a meeting on its own. the user: "we end
2558
2576
  up with a meeting that is orphaned that we have no ability to keep."
2559
2577
 
2560
2578
  Found live while writing this: two sessions stranded for 184 and 24 minutes, holding
@@ -2609,7 +2627,7 @@ flake under file parallelism, which is a pre-existing isolation bug.
2609
2627
  ## 6.22.1
2610
2628
 
2611
2629
  Notes attached from somewhere else by a symlink are now read properly. Found by
2612
- Queen within hours of 6.22.0, on the very first real setup.
2630
+ Sam within hours of 6.22.0, on the very first real setup.
2613
2631
 
2614
2632
  - **A symlinked subfolder or file was silently skipped.** `readdirSync` reports a
2615
2633
  symlink as `isSymbolicLink()`, never as `isDirectory()` or `isFile()`, so the walk
@@ -2846,15 +2864,15 @@ nothing she could name would work.
2846
2864
  correction row has recorded `proseStale: true` for exactly this since the feature
2847
2865
  shipped — and NOTHING read it.
2848
2866
 
2849
- Real case, 2026-08-07: Miles removed "Clem Ukaoma" from a personal call that was
2850
- only him and Queen (his father's voice matched a similar profile). All 8 label
2851
- sites were rewritten correctly. The LLM summary still opened "Miles, Queen, and
2852
- Clem talk through..." and the payload said nothing at all. The allowlist covered
2867
+ Regression example (synthetic names): the user removed "Morgan Example" from a personal call that was
2868
+ only him and Sam (a third participant's voice matched a similar profile). All 8 label
2869
+ sites were rewritten correctly. The LLM summary still opened "the user, Sam, and
2870
+ Morgan talk through..." and the payload said nothing at all. The allowlist covered
2853
2871
  it only as "not confirmed", which is far too weak: he did not fail to confirm
2854
2872
  that person, he explicitly said they were not in the room.
2855
2873
 
2856
2874
  The payload now carries `removedNames` and states it above the write-up: *"You
2857
- removed "Clem Ukaoma" from this meeting. The write-up below was written before
2875
+ removed "Morgan Example" from this meeting. The write-up below was written before
2858
2876
  that and still uses the name: treat every mention of it as a capture error, not
2859
2877
  a participant."* The prose is left intact — the record stays, the correction
2860
2878
  travels beside it.
@@ -2897,7 +2915,7 @@ without the floor.
2897
2915
  person: `"MU" by wearing the device; "Gina Obert" by voice match; "Luke Henry"
2898
2916
  because a human named that voice`. Labels are quoted, so a typed "Smith, John"
2899
2917
  cannot read as two people, and the caveat now covers different SPELLINGS of a
2900
- confirmed name (labels are `MU` while the prose says "Miles").
2918
+ confirmed name (labels are `MU` while the prose says "the user").
2901
2919
 
2902
2920
  - **A lone named voice no longer gets a share.** "100% of identified speech" is
2903
2921
  always true with one name and reads as "he did all the talking" — on 23 real
@@ -3135,7 +3153,7 @@ without the floor.
3135
3153
  - Review playback falls back to ext-audio. The 7-day archive introduced in
3136
3154
  6.21.18 is FORWARD-ONLY — it starts filling when a meeting is saved under that
3137
3155
  version — so on upgrade day the panel had no play buttons at all, which is what
3138
- Miles hit. ext-audio already holds 72 hours of unrecognised-speaker audio keyed
3156
+ the user hit. ext-audio already holds 72 hours of unrecognised-speaker audio keyed
3139
3157
  by the same raw capture index; measured across 14 real meetings, 90-100% of
3140
3158
  those files correspond to a chunk the sidecar labels `Ext`. That is exactly the
3141
3159
  set a reviewer most needs to hear.
@@ -3149,7 +3167,7 @@ without the floor.
3149
3167
  ## 6.21.18
3150
3168
 
3151
3169
  Everything a human needs to correct who spoke, and to hear the voice before
3152
- deciding. Four changes that landed together after Miles reviewed the 2026-08-06
3170
+ deciding. Four changes that landed together after the user reviewed the 2026-08-06
3153
3171
  Ditto meeting and found eleven attributed voices, most of them wrong.
3154
3172
 
3155
3173
  - A NAME MUST BE EARNED. `identifySpeaker` accepts a match at 0.55, so one
@@ -3170,7 +3188,7 @@ Ditto meeting and found eleven attributed voices, most of them wrong.
3170
3188
  discarding which meeting each sample came from, and now stamps
3171
3189
  `g2-training:<sessionId>`. Samples written before this are relabellable but not
3172
3190
  retractable.
3173
- - MEETING AUDIO KEPT 7 DAYS, 8 GB budget (Miles's call: review should survive to
3191
+ - MEETING AUDIO KEPT 7 DAYS, 8 GB budget (the user's call: review should survive to
3174
3192
  a weekend). Chunk WAVs previously died with the batch pipeline —
3175
3193
  `session-audio` held 0 files. Hard-linked at the single choke point before the
3176
3194
  rename, so it costs no extra disk and outlives the pipeline's cleanup. Sized on
@@ -3201,7 +3219,7 @@ FIXES FOUND BY QA BEFORE PUBLISH (nothing above ever shipped):
3201
3219
  read "Unidentified voice" in 4 of 9 meetings, once with 285 of their own
3202
3220
  segments. `thrashesWith` still renders, so a mixed row is still visible.
3203
3221
  - DE-ATTRIBUTION NUMBERS ITS LABELS. `Unidentified 1`, `Unidentified 2`, … rather
3204
- than one shared `Ext`. Miles found five wrong attributions in one meeting;
3222
+ than one shared `Ext`. the user found five wrong attributions in one meeting;
3205
3223
  collapsing them into a single row would have destroyed his ability to tell
3206
3224
  those voices apart, which is exactly what playback is for next.
3207
3225
  - DE-ATTRIBUTION DELETES THE ATTENDEE BULLET instead of renaming it. Renaming
@@ -3256,7 +3274,7 @@ Requires COS Control 0.5.0+ to use the scoped correction and playback surfaces.
3256
3274
 
3257
3275
  - `POST /api/meeting/:sessionId/relabel` — correct who a voice was in ONE
3258
3276
  meeting. Body `{ from, to, chunks?, confirm | dryRun, force? }`.
3259
- - Per-meeting by design, not a global merge. Miles: "changing it doesn't mean
3277
+ - Per-meeting by design, not a global merge. the user: "changing it doesn't mean
3260
3278
  that all previous chunks should also be moved. It should be meeting by
3261
3279
  meeting, with the goal of hardening or refining the voice profiles." The
3262
3280
  identifier mishearing a voice in one room is not evidence that every past
@@ -3276,7 +3294,7 @@ Requires COS Control 0.5.0+ to use the scoped correction and playback surfaces.
3276
3294
  human never selected. The response says why rather than staying silent.
3277
3295
  - Narrative prose is NEVER rewritten — only reported as `proseStale` with the
3278
3296
  forms found. Verified on a real scribe: 6 of 12 speakers are referred to by
3279
- bare first name in the summary, and with two Kyles, two Jacobuses and two
3297
+ bare first name in the summary, and with two Alexes, two Jordans and two
3280
3298
  Chrises in this org a first-name substitution would rewrite sentences about
3281
3299
  someone else. The confirmation message says this before a human commits.
3282
3300
  - `/api/health` reports `speaker_corrections` (sessions, applied, pending,
@@ -3296,7 +3314,7 @@ Requires COS Control 0.5.0+ to use the scoped correction and playback surfaces.
3296
3314
  - `Ext` is deliberately included. An unidentified voice is the one case with no
3297
3315
  other route to being trained at all.
3298
3316
  - RETENTION IS 14 DAYS, not the 8 hours used for audio snippets
3299
- (`COS_CHUNK_EMBEDDING_TTL_DAYS` to change it). Two reasons, both worth Miles
3317
+ (`COS_CHUNK_EMBEDDING_TTL_DAYS` to change it). Two reasons, both worth the user
3300
3318
  overriding if he disagrees: 8 hours cannot survive a weekend, so a Friday
3301
3319
  meeting could never be corrected on Monday; and an embedding is not audio — it
3302
3320
  is a non-invertible timbre vector that cannot be played back, so the privacy
@@ -3596,7 +3614,7 @@ unsaved capture, and makes batch status stop lying about finished work.
3596
3614
  - **Unsaved captures are visible.** `/api/health` gains `unsaved_captures`
3597
3615
  (count + compact items, same exposure level as `meeting_sync`). The
3598
3616
  authenticated `GET /api/meeting/orphans` returns full detail.
3599
- - **Miles-triggered recovery, surface-only by decision (2026-08-02).**
3617
+ - **the user-triggered recovery, surface-only by decision (2026-08-02).**
3600
3618
  `POST /api/meeting/orphans/:sessionId/recover` batch-transcribes the
3601
3619
  quarantined WAVs (same segment/enhance/Metal-preempt contract as HQ polish,
3602
3620
  under a new `orphan_recovery` maintenance lease), writes a durable scribe,
@@ -4066,9 +4084,9 @@ unsaved capture, and makes batch status stop lying about finished work.
4066
4084
 
4067
4085
  ### A cloned Codex conversation gets its own identity
4068
4086
 
4069
- Miles forked "Markt POS 2.0 build" into "POS Nation 3.0 build" and the fork never
4087
+ the user forked "Example project 2.0 build" into "Example project 3.0 build" and the fork never
4070
4088
  appeared in the sessions list. It had not failed to index -- it was indexed AS ITS
4071
- PARENT. The list showed one `Markt POS 2.0 build` row whose modified time was the
4089
+ PARENT. The list showed one `Example project 2.0 build` row whose modified time was the
4072
4090
  fork's activity: two conversations, one identity, and the newer one invisible.
4073
4091
 
4074
4092
  Cloning copies the parent's `session_meta` record wholesale, so the new rollout carries
@@ -4094,7 +4112,7 @@ and a clone of a clone doubles again.
4094
4112
 
4095
4113
  ### The seeded query was being crowded out by the steps
4096
4114
 
4097
- Caught by probing the live stream after shipping 6.36.2, before Miles tested it: a
4115
+ Caught by probing the live stream after shipping 6.36.2, before the user tested it: a
4098
4116
  real session seeded 8 events -- 6 tool calls, one prose, one status -- and **no
4099
4117
  prompt**. The seed took "the last 7 events of any kind", and in a busy run the
4100
4118
  user's question is twenty or thirty steps back, so the activity you opened the page
@@ -4111,12 +4129,12 @@ scrolling window.
4111
4129
 
4112
4130
  ### The live view stops being a blank slate
4113
4131
 
4114
- Three changes, all from Miles watching a real session on hardware.
4132
+ Three changes, all from the user watching a real session on hardware.
4115
4133
 
4116
4134
  - **The user's query is now an event.** A `user` record used to be dropped whole,
4117
4135
  on the reasoning that "the prompt came from this device" -- true of a Continue
4118
4136
  turn and false of the case that matters most, a session running in a Mac window
4119
- where that record is the question Miles typed there and the glasses have never
4137
+ where that record is the question the user typed there and the glasses have never
4120
4138
  seen it. Dropping it is why the lens said WORKING and gave no clue what it was
4121
4139
  working ON. Tool results stay dropped; harness wrappers
4122
4140
  (`<system-reminder>`, `<cos-alarms>`, the memory and bulletin blocks) are
@@ -4145,7 +4163,7 @@ Needs COS Glasses 6.8.374 to render any of it.
4145
4163
 
4146
4164
  ### A reply keeps its line structure
4147
4165
 
4148
- Miles, from a G2 screenshot: a session reply arrived on the lens as one unbroken
4166
+ the user, from a G2 screenshot: a session reply arrived on the lens as one unbroken
4149
4167
  paragraph carrying three headings and six bullets, none of them visible.
4150
4168
 
4151
4169
  `proseBody` collapsed ALL whitespace, and both the one-line list gist and the
@@ -4213,7 +4231,7 @@ Needs COS Glasses 6.8.372 to be visible. An older app never calls the route.
4213
4231
 
4214
4232
  ### The newest assistant reply arrives whole instead of at 160 characters
4215
4233
 
4216
- - **The defect.** Miles opened a session on the glasses and the newest reply was cut
4234
+ - **The defect.** the user opened a session on the glasses and the newest reply was cut
4217
4235
  off mid-sentence. The session detail payload had NO full-text field: it carried
4218
4236
  `discussion_summary` (180 chars) and `discussion_digest` (2000), and the newest
4219
4237
  reply appeared only as the `Latest:` line inside the digest, produced by
@@ -4283,7 +4301,7 @@ Needs COS Glasses 6.8.372 to be visible. An older app never calls the route.
4283
4301
  ### A continued turn now runs with the session's own permissions
4284
4302
 
4285
4303
  - **This widens what Continue can do.** A prompt spoken into the glasses can run
4286
- tools on the Mac with nobody at the keyboard. Authorized explicitly by Miles
4304
+ tools on the Mac with nobody at the keyboard. Authorized explicitly by the user
4287
4305
  after his first real continued turn came back reporting that every tool was
4288
4306
  disabled, which is not the point of the feature.
4289
4307
  - Claude drops `--permission-mode plan` and the empty `--tools`/`--allowedTools`
package/README.md CHANGED
@@ -520,3 +520,12 @@ BIND_HOST=0.0.0.0 npm run start:server
520
520
  ## License
521
521
 
522
522
  MIT. Learn more at [gotcos.com](https://www.gotcos.com).
523
+
524
+
525
+ ### Optional owner-local memory runtime
526
+
527
+ The package includes a checksummed public Python runtime. It uses a unique owner, separate data root, reviewed memory states, current source snapshots, explicit document-link graph paths and saved explorations. Initial memory search is keyword based; semantic embeddings and inferred extraction are separate optional integrations. No private COS checkout or corpus is included. Existing plain-file setup remains available.
528
+
529
+ Run `glasses-memory-setup --runtime-dir /absolute/path/to/cos-memory-runtime --data-root /absolute/path/to/private-memory` with Python 3.11+ installed. Set `COS_SCRIPTS_DIR` to the runtime directory in your server configuration, then restart the server. Add an explicitly granted Markdown/text source using `venv/bin/python3 manage.py grant /path/to/notes.md --title "Project"` from that runtime directory. The bundled README documents captures, reviews, document links, source refresh, upgrade and staged restore. Keep the latest independent deletion checkpoint separately from restorable snapshots.
530
+
531
+ This is a local owner instance, separate from app.gotcos.com tenants and hosted Sessions. Installing the package does not upload your corpus or enable household sharing. A source build or local setup test is not proof of a published registry version; use the release ledger for actual availability.
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+ 'use strict'
3
+ const { resolve, dirname } = require('node:path')
4
+ const { readFileSync } = require('node:fs')
5
+ const { createHash } = require('node:crypto')
6
+ const { spawnSync } = require('node:child_process')
7
+ const args = process.argv.slice(2)
8
+ function option(name) { const i = args.indexOf(name); return i >= 0 ? args[i + 1] : null }
9
+ const runtime = option('--runtime-dir'), data = option('--data-root')
10
+ if (!runtime || !data || args.some((x, i) => i % 2 === 0 && !['--runtime-dir', '--data-root', '--python'].includes(x))) {
11
+ console.error('Usage: glasses-memory-setup --runtime-dir /path/to/runtime --data-root /path/to/private-data [--python python3]')
12
+ process.exit(2)
13
+ }
14
+ const root = resolve(__dirname, '..')
15
+ const manifest = JSON.parse(readFileSync(resolve(root, 'memory-runtime/runtime.json'), 'utf8'))
16
+ if (manifest.protocol !== 1 || !/^[a-zA-Z0-9.-]+\.tar\.gz$/.test(manifest.file)) throw new Error('Invalid runtime manifest')
17
+ const archive = resolve(root, 'memory-runtime', manifest.file)
18
+ if (createHash('sha256').update(readFileSync(archive)).digest('hex') !== manifest.sha256) throw new Error('Runtime bundle checksum mismatch')
19
+ const program = String.raw`
20
+ import json,os,shutil,sys,tarfile,tempfile
21
+ from pathlib import Path
22
+ archive,destination,data=map(Path,sys.argv[1:])
23
+ if sys.version_info<(3,11):raise SystemExit('Python 3.11 or newer is required')
24
+ if destination.resolve()==data.resolve() or destination.resolve() in data.resolve().parents or data.resolve() in destination.resolve().parents:raise SystemExit('Keep runtime code and private data in separate directories')
25
+ destination.mkdir(parents=True,exist_ok=True)
26
+ with tempfile.TemporaryDirectory(prefix='cos-runtime-install-',dir=destination.parent) as staging:
27
+ with tarfile.open(archive,'r:gz') as bundle:
28
+ members=bundle.getmembers()
29
+ if sum(item.size for item in members)>10*1024*1024:raise SystemExit('Runtime bundle is too large')
30
+ for item in members:
31
+ relative=Path(item.name)
32
+ if relative.is_absolute() or '..' in relative.parts or not (item.isfile() or item.isdir()):raise SystemExit('Unsafe runtime member')
33
+ target=Path(staging)/relative
34
+ if item.isdir():target.mkdir(parents=True,exist_ok=True)
35
+ else:
36
+ target.parent.mkdir(parents=True,exist_ok=True)
37
+ with bundle.extractfile(item) as source,target.open('wb') as output:shutil.copyfileobj(source,output)
38
+ roots=list(Path(staging).iterdir())
39
+ if len(roots)!=1 or not roots[0].is_dir():raise SystemExit('Invalid runtime layout')
40
+ for source in roots[0].iterdir():
41
+ if source.name in {'instance.json','venv'} or not source.is_file():raise SystemExit('Unexpected runtime member')
42
+ target=destination/source.name
43
+ if target.is_symlink():raise SystemExit('Refusing to replace symlinked runtime code')
44
+ fd,temp=tempfile.mkstemp(prefix='.'+target.name+'-',dir=destination)
45
+ try:
46
+ with os.fdopen(fd,'wb') as output,source.open('rb') as input:shutil.copyfileobj(input,output);output.flush();os.fsync(output.fileno())
47
+ os.replace(temp,target)
48
+ finally:Path(temp).unlink(missing_ok=True)
49
+ `
50
+ let result = spawnSync(option('--python') || 'python3', ['-c', program, archive, resolve(runtime), resolve(data)], { stdio: 'inherit' })
51
+ if (result.error) throw result.error
52
+ if (result.status !== 0) process.exit(result.status || 1)
53
+ result = spawnSync(option('--python') || 'python3', [resolve(runtime, 'install.py'), '--data-root', resolve(data)], { stdio: 'inherit' })
54
+ if (result.error) throw result.error
55
+ process.exit(result.status || 0)
@@ -0,0 +1,7 @@
1
+ {
2
+ "schema": 1,
3
+ "protocol": 1,
4
+ "version": "0.1.0",
5
+ "file": "cos-memory-runtime-0.1.0.tar.gz",
6
+ "sha256": "1f03e8d3bcc878709bae7580a8c685c1c5494839cebd7f2c79248dbc17e4d512"
7
+ }
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@gotcos/glasses-server",
3
- "version": "6.44.16",
3
+ "version": "6.45.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": {
7
7
  "glasses-server": "bin/cli.cjs",
8
- "glasses-server-managed": "bin/managed-server.cjs"
8
+ "glasses-server-managed": "bin/managed-server.cjs",
9
+ "glasses-memory-setup": "bin/memory-setup.cjs"
9
10
  },
10
11
  "scripts": {
11
12
  "start": "node bin/cli.cjs",
@@ -41,7 +42,9 @@
41
42
  "README.md",
42
43
  "LICENSE",
43
44
  "CHANGELOG.md",
44
- "SECURITY.md"
45
+ "SECURITY.md",
46
+ "bin/memory-setup.cjs",
47
+ "memory-runtime"
45
48
  ],
46
49
  "author": "COS Contributors",
47
50
  "license": "MIT",
package/server/index.ts CHANGED
@@ -334,7 +334,7 @@ const attachedWorkspaceDeps = realAttachedWorkspaceDeps(nativeHeadDeps)
334
334
  * that also registers the write routes (6.33.0).
335
335
  *
336
336
  * Without the clock, a foreign holder is terminal and Continue is refused for
337
- * any thread with a Claude Code window open on it — including the ones Miles
337
+ * any thread with a Claude Code window open on it — including the ones the user
338
338
  * actually works in, because he leaves those windows open. With it, a holder
339
339
  * measured idle is continuable and only a holder measured WRITING is refused.
340
340
  *
@@ -518,7 +518,7 @@ app.use('/api', claudeSessionsRouter)
518
518
  // QUEUED THREAD TURNS
519
519
  // ---------------------------------------------------------------------------
520
520
  // A turn spoken at a thread that is busy right now is PARKED instead of refused, and
521
- // delivered when the thread frees. Miles, 2026-08-17: "if there's a session that's
521
+ // delivered when the thread frees. the user, 2026-08-17: "if there's a session that's
522
522
  // still running, that would just put it into the queue the same way that the user has
523
523
  // the ability to do so."
524
524
  //
@@ -550,7 +550,7 @@ if (threadAttachEnabled()) {
550
550
  // `OccupancyReason` has no `native_target_busy` member, because that refusal is
551
551
  // produced only by the binding registry inside `bindings.create`.
552
552
  //
553
- // That gap is what trapped Miles on 2026-08-18. Continue refused
553
+ // That gap is what trapped the user on 2026-08-18. Continue refused
554
554
  // `native_target_busy` (a live COS binding held the thread), the client armed the
555
555
  // queue, he dictated -- and this gate, asking occupancy alone, answered
556
556
  // `attachable: true`, so the route replied `409 thread_free` ("Pick Continue again
@@ -623,7 +623,7 @@ app.use('/api', createAgentSessionBindingsRouter({
623
623
  // without a reachable release is a REGRESSION, not a fix: today "Restart
624
624
  // Server" in COS Control clears a fence, and making it survive restarts with
625
625
  // no operator surface in Control turns an 8-second annoyance into a
626
- // permanently dead thread that needs a terminal to clear. Miles, 2026-08-12:
626
+ // permanently dead thread that needs a terminal to clear. the user, 2026-08-12:
627
627
  // "we couldn't do anything without bash, that shouldn't be the case."
628
628
  //
629
629
  // So the storage ships inert. GET /agent-sessions/fences and
@@ -159,7 +159,7 @@ export function analyzePlaybackWav(buffer: Buffer): AudioSignalProfile | null {
159
159
 
160
160
  export function adaptivePlaybackEnabled(): boolean {
161
161
  // Private canary: explicit opt-in, explicit 0 rollback through COS Control.
162
- // Default ON since 6.37.0 (Miles 2026-08-25). Absent key = on; only a
162
+ // Default ON since 6.37.0 (the user 2026-08-25). Absent key = on; only a
163
163
  // literal '0' disables. Raw WAV is untouched either way — this affects
164
164
  // review playback only, never the transcript, attribution, save or sync.
165
165
  return process.env.COS_MEETING_AUDIO_ADAPTIVE_PLAYBACK !== '0'