@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.
- package/CHANGELOG.md +69 -51
- package/README.md +9 -0
- package/bin/memory-setup.cjs +55 -0
- package/memory-runtime/cos-memory-runtime-0.1.0.tar.gz +0 -0
- package/memory-runtime/runtime.json +7 -0
- package/package.json +6 -3
- package/server/index.ts +4 -4
- package/server/lib/adaptive-playback-audio.ts +1 -1
- package/server/lib/agent-session-store.ts +139 -28
- package/server/lib/archive-search.ts +1 -1
- package/server/lib/attached-provider-adapter.ts +1 -1
- package/server/lib/attached-workspace.ts +3 -3
- package/server/lib/chunk-embedding-store.ts +1 -1
- package/server/lib/context-files.ts +1 -1
- package/server/lib/cos-context-browser.ts +17 -6
- package/server/lib/cos-operations-meetings.ts +1 -1
- package/server/lib/domains.ts +2 -2
- package/server/lib/maintenance-lifecycle.ts +1 -1
- package/server/lib/meeting-audio-archive.ts +3 -3
- package/server/lib/meeting-corrections.ts +3 -3
- package/server/lib/meeting-relabel-enrolment.ts +1 -1
- package/server/lib/meeting-relabel.ts +2 -2
- package/server/lib/meeting-scribe-content.ts +7 -7
- package/server/lib/meeting-speaker-review.ts +3 -3
- package/server/lib/meeting-summary.ts +1 -1
- package/server/lib/message-era-reset.ts +1 -1
- package/server/lib/message-era.ts +1 -1
- package/server/lib/morning-brief-config.ts +1 -1
- package/server/lib/morning-brief-coverage.ts +1 -1
- package/server/lib/occupancy-probes.ts +7 -4
- package/server/lib/ollama-tools.ts +1 -1
- package/server/lib/python-bridge.ts +6 -4
- package/server/lib/query-job-types.ts +1 -1
- package/server/lib/session-stream-events.ts +3 -3
- package/server/lib/session-transcript-watcher.ts +1 -1
- package/server/lib/speaker-calibration-log.ts +1 -1
- package/server/lib/speaker-name.ts +1 -1
- package/server/lib/thread-occupancy.ts +1 -1
- package/server/lib/thread-turn-queue-deliver.ts +1 -1
- package/server/lib/thread-turn-queue.ts +3 -3
- package/server/lib/video-upload-v2.ts +1 -1
- package/server/lib/voice-profile-store.ts +2 -2
- package/server/lib/whisper-metal-gate.ts +1 -1
- package/server/routes/agent-session-bindings.ts +2 -2
- package/server/routes/agent-session-stream.ts +1 -1
- package/server/routes/agent-sessions.ts +2 -2
- package/server/routes/claude-sessions.ts +1 -1
- package/server/routes/health.ts +1 -1
- package/server/routes/meeting.ts +8 -8
- package/server/routes/memory.ts +45 -7
- package/server/routes/prompt-drafts.ts +1 -1
- package/server/routes/session-index.ts +1 -1
- package/server/routes/thread-turn-queue.ts +10 -4
- package/server/routes/transcribe-stream.ts +1 -1
- 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
|
-
-
|
|
6
|
-
recent meetings have no session id." On
|
|
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
|
-
-
|
|
22
|
-
was the entire enrolment speech ("My Voice My Name Is
|
|
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
|
-
-
|
|
42
|
-
"address any of the obvious duplicates like the
|
|
43
|
-
from above without clobbering entities. You did good in deflecting
|
|
44
|
-
mallard vs the other
|
|
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
|
-
(
|
|
51
|
-
|
|
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 ("
|
|
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
|
-
-
|
|
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
|
-
-
|
|
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
|
|
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 (
|
|
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
|
-
|
|
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.**
|
|
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
|
|
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.**
|
|
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.**
|
|
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` →
|
|
2156
|
-
`
|
|
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.
|
|
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.
|
|
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-
|
|
2431
|
-
"
|
|
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: `.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
2850
|
-
only him and
|
|
2851
|
-
sites were rewritten correctly. The LLM summary still opened "
|
|
2852
|
-
|
|
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 "
|
|
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 "
|
|
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
|
-
|
|
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
|
|
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 (
|
|
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`.
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
- **
|
|
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
|
-
|
|
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 `
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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.**
|
|
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
|
|
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)
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gotcos/glasses-server",
|
|
3
|
-
"version": "6.
|
|
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
|
|
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.
|
|
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
|
|
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.
|
|
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 (
|
|
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'
|