@gotcos/glasses-server 6.44.15 → 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 +83 -49
- 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 +15 -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,43 @@
|
|
|
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
|
+
|
|
19
|
+
## 6.44.16
|
|
20
|
+
|
|
21
|
+
A G2 recording keeps its session id when its sidecar only exists in the server's own recordings folder.
|
|
22
|
+
|
|
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
|
|
25
|
+
was three KC-week recordings whose markdown reached the operations tree
|
|
26
|
+
through git while the `.g2-chunks.json` sidecar, which is gitignored there,
|
|
27
|
+
did not; the row lost its session id and Speakers could not open it.
|
|
28
|
+
- `listCosOperationsMeetings` now reads the sidecar from the server's own
|
|
29
|
+
recordings root by the same stem when the copy beside the markdown is
|
|
30
|
+
missing (`recordingsRoot` option, default the data dir). The review lookup
|
|
31
|
+
already resolves a session through the standalone store, so the row opens.
|
|
32
|
+
A meeting with no sidecar anywhere still omits the field rather than
|
|
33
|
+
inventing one.
|
|
34
|
+
|
|
1
35
|
## 6.44.15
|
|
2
36
|
|
|
3
37
|
Voice profiles named after a spoken sentence are repaired at load.
|
|
4
38
|
|
|
5
|
-
-
|
|
6
|
-
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
|
|
7
41
|
Am The Director…", ~600 characters), written by a client older than the
|
|
8
42
|
8/25 guards. Speaker ID was "active" and could never match anything, and the
|
|
9
43
|
file cannot be repaired by hand because the server rewrites it from memory.
|
|
@@ -22,17 +56,17 @@ Voice profiles named after a spoken sentence are repaired at load.
|
|
|
22
56
|
The Manage sheet's merge, with a preview, a worker and a receipt, plus a
|
|
23
57
|
duplicates scan that proposes and never merges.
|
|
24
58
|
|
|
25
|
-
-
|
|
26
|
-
"address any of the obvious duplicates like the
|
|
27
|
-
from above without clobbering entities. You did good in deflecting
|
|
28
|
-
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."
|
|
29
63
|
- `POST /api/context/graph/merge/preview` `{ source, target }`: both entities
|
|
30
64
|
from this Mac's index, shared neighbors, the effect (relationships moved and
|
|
31
65
|
collapsed, texts re-embedded, about how long), a name signal, warnings
|
|
32
66
|
(types differ, larger into smaller, nothing links them, a large merge), and
|
|
33
67
|
`blocked` with its reason for a pair the graph knows to be different people
|
|
34
|
-
(
|
|
35
|
-
|
|
68
|
+
(Alex Example / Alex Other, Jordan Example / Jordan Other, the Alexes, the
|
|
69
|
+
Jordans, and any pair the user kept apart).
|
|
36
70
|
- `POST /api/context/graph/merge` `{ source, target, confirm: true, rule? }`:
|
|
37
71
|
starts ONE detached worker on the ingestion owner and answers 202 with a
|
|
38
72
|
ticket and the receipt. The worker takes the exclusive ingest lock, copies
|
|
@@ -50,7 +84,7 @@ duplicates scan that proposes and never merges.
|
|
|
50
84
|
whole names within two letters, one name spelling out the other, a bare
|
|
51
85
|
first name that matches exactly one full name), grouped under the full name
|
|
52
86
|
with the most connections, with shared-neighbor counts and a confidence.
|
|
53
|
-
Possessives ("
|
|
87
|
+
Possessives ("Alex Example's Son") and ambiguous first names are left alone;
|
|
54
88
|
blocked pairs never share a group. Nothing here merges.
|
|
55
89
|
- Four bridge commands: `graph-merge-preview`, `graph-merge`,
|
|
56
90
|
`graph-merge-status`, `graph-duplicates` (28 in the parity set).
|
|
@@ -62,7 +96,7 @@ duplicates scan that proposes and never merges.
|
|
|
62
96
|
|
|
63
97
|
Prune or accept a captured memory, and guardrails that prune nonsense for you.
|
|
64
98
|
|
|
65
|
-
-
|
|
99
|
+
- the user 2026-09-07, looking at a captured decision that read "AAAA...":
|
|
66
100
|
"we need the ability to either prune or accept the memory", and "an
|
|
67
101
|
automated review ... another person could set their own guardrails that
|
|
68
102
|
automatically just prune out stuff like this."
|
|
@@ -85,7 +119,7 @@ Prune or accept a captured memory, and guardrails that prune nonsense for you.
|
|
|
85
119
|
|
|
86
120
|
The Knowledge down-select, and a fail-closed embedding gate.
|
|
87
121
|
|
|
88
|
-
-
|
|
122
|
+
- the user 2026-09-07: the local embeddings are the free path for people who
|
|
89
123
|
run COS without an OpenAI key, and the setup's job is to help each person
|
|
90
124
|
down-select. The `embedding` block now carries `preference.local_only`
|
|
91
125
|
(the one question the user answers: may text leave this Mac?),
|
|
@@ -458,7 +492,7 @@ learned the hard way: a source that cannot be read produces one honest
|
|
|
458
492
|
decision, a date, a dollar figure, an owner) make the cut; the scribe's
|
|
459
493
|
extracted action-item list is never pasted verbatim. Enable the "Workspace
|
|
460
494
|
skill" source with `/good-morning` and that skill's output IS the brief —
|
|
461
|
-
which is how
|
|
495
|
+
which is how the user's own routine rides this without being rewritten.
|
|
462
496
|
|
|
463
497
|
Surface:
|
|
464
498
|
|
|
@@ -954,7 +988,7 @@ topics, decisions and action items. Until now they got none of that, and the
|
|
|
954
988
|
server compensated by returning the TRANSCRIPT in the summary slot -- which is
|
|
955
989
|
why this was reported as "no proper summary and transcription."
|
|
956
990
|
|
|
957
|
-
FEATURE DEFAULTS NOW ON (
|
|
991
|
+
FEATURE DEFAULTS NOW ON (the user 2026-08-25)
|
|
958
992
|
|
|
959
993
|
Ship the capability active; users opt out of what they do not need. Each gate
|
|
960
994
|
stays strict in the other direction -- only a literal '0' disables, so a stray
|
|
@@ -1305,7 +1339,7 @@ the assertion written for them.
|
|
|
1305
1339
|
COS Control's "Show Claude sessions" checkbox sourced its state from
|
|
1306
1340
|
`GET /api/claude-sessions` -- the call that also lists every session -- and the
|
|
1307
1341
|
panel never made that call. The box rendered false while the setting was true, and
|
|
1308
|
-
|
|
1342
|
+
the user enabled it four times against a control that could only ever show him one
|
|
1309
1343
|
value. Health is what every other toggle on that panel already reads, and this is
|
|
1310
1344
|
a pure env read, so it costs nothing on a poll.
|
|
1311
1345
|
|
|
@@ -1745,7 +1779,7 @@ bring the leftover cards back.
|
|
|
1745
1779
|
|
|
1746
1780
|
|
|
1747
1781
|
## 6.36.7
|
|
1748
|
-
- **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
|
|
1749
1783
|
there's a session that's still running, that would just put it into the queue the same
|
|
1750
1784
|
way that the user has the ability to do so." The thread was never stuck — measured at
|
|
1751
1785
|
the moment he asked, its transcript mtime was 3s old against a 30s window, so the gate
|
|
@@ -1762,7 +1796,7 @@ bring the leftover cards back.
|
|
|
1762
1796
|
attach and turn routes. Those carry the gate, the target fence, the per-target claim,
|
|
1763
1797
|
the watermark, the idempotency ledger and the child-pid accounting; a second copy in a
|
|
1764
1798
|
background worker would be a second place for the gate to drift.
|
|
1765
|
-
- **The watermark exemption, approved explicitly by
|
|
1799
|
+
- **The watermark exemption, approved explicitly by the user.** A queued turn drains after
|
|
1766
1800
|
the thread has moved on — that is what it waited for — so its binding is minted fresh
|
|
1767
1801
|
at delivery. Checked as normal, a queue would fail 100% of the time. An interactive
|
|
1768
1802
|
turn still gets the full divergence check.
|
|
@@ -1777,7 +1811,7 @@ bring the leftover cards back.
|
|
|
1777
1811
|
|
|
1778
1812
|
|
|
1779
1813
|
## 6.36.6
|
|
1780
|
-
- **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
|
|
1781
1815
|
lens: "It's currently showing a legacy session that I had over a day ago... The
|
|
1782
1816
|
discussion should show the questions that we're asking and a summary of those most
|
|
1783
1817
|
recent things, not something that's the 'first' message." The whole budget now goes
|
|
@@ -2001,7 +2035,7 @@ bring the leftover cards back.
|
|
|
2001
2035
|
- **Session bodies get a real digest.** `GET /api/agent-sessions/:provider/:id` adds
|
|
2002
2036
|
`discussion_digest`: up to **2000 chars** of what actually happened — the opening
|
|
2003
2037
|
ask, the most recent user turns in order, and where the assistant left off.
|
|
2004
|
-
- **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
|
|
2005
2039
|
title, the row should be no more than the 180 characters." `discussion_summary`
|
|
2006
2040
|
keeps its 180-char budget for the single-line row; the digest is a separate field
|
|
2007
2041
|
the detail page reads. One shared field could not serve both — a 2000-char gist
|
|
@@ -2136,8 +2170,8 @@ bring the leftover cards back.
|
|
|
2136
2170
|
|
|
2137
2171
|
**Measured reach, so callers do not assume more than it delivers.** The distance
|
|
2138
2172
|
budget is 1 edit for 5-8 character words, so it catches single-edit misses
|
|
2139
|
-
(`Austen` → Austin, `Nyala` →
|
|
2140
|
-
`
|
|
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
|
|
2141
2175
|
`whisper_corrections` entries on multi-edit misses; the new test asserts both
|
|
2142
2176
|
directions so that is not re-derived later.
|
|
2143
2177
|
|
|
@@ -2228,7 +2262,7 @@ four defects, since the writer was correct in every case. 8 mutations, all caugh
|
|
|
2228
2262
|
|
|
2229
2263
|
A video attachment is summarized from stills. The old rule was one still per 15
|
|
2230
2264
|
seconds, floored at 1 and capped at 8, which gave a 12 second clip **one** frame
|
|
2231
|
-
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,
|
|
2232
2266
|
on a fridge sweep: "it only selects three chunks from the video."
|
|
2233
2267
|
|
|
2234
2268
|
- Frame count is now `clamp(round(seconds / 6), 8, 16)`. A 12s clip and a 44s
|
|
@@ -2338,7 +2372,7 @@ Proof: 460 suites / 1,515 tests, isolated runtime directory, plus clean TypeScri
|
|
|
2338
2372
|
|
|
2339
2373
|
## 6.24.3
|
|
2340
2374
|
|
|
2341
|
-
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
|
|
2342
2376
|
for three turns: "1 recoverable" that opening the phone app could not clear.
|
|
2343
2377
|
|
|
2344
2378
|
- **My call sat inside a bare `catch {}`.** `autoRecoverOneQuarantinedCapture()` was one
|
|
@@ -2411,8 +2445,8 @@ sidebar does.
|
|
|
2411
2445
|
- `project` comes from the `cwd` on the session records, not from decoding the
|
|
2412
2446
|
directory name. Claude Code replaces path separators with dashes and a real dash is
|
|
2413
2447
|
indistinguishable from a separator afterwards, so
|
|
2414
|
-
`-Users-
|
|
2415
|
-
"
|
|
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".
|
|
2416
2450
|
|
|
2417
2451
|
## 6.24.0
|
|
2418
2452
|
|
|
@@ -2438,7 +2472,7 @@ sessions on this Mac arrives behind a flag.
|
|
|
2438
2472
|
31.7 MB was parsed synchronously per request, the detail endpoint included, on a
|
|
2439
2473
|
process that also streams live audio; now async and cached against file identity
|
|
2440
2474
|
(161ms cold, 15ms warm). And the filename filter matched iCloud sync-conflict
|
|
2441
|
-
duplicates: `.
|
|
2475
|
+
duplicates: `.session_index_cache_Example-Mac-Studio 3.json` shared 543 of its 602
|
|
2442
2476
|
rows with the canonical file, so the merged list served 543 duplicates. Verified on
|
|
2443
2477
|
real data: 37,700 naive becomes 37,157 served, exactly 543 removed. Filtering ` N`
|
|
2444
2478
|
filenames would have been wrong in the other direction, since ` 2.json` holds 245
|
|
@@ -2538,7 +2572,7 @@ hardcoded. 14 new tests here, full suite 1425 serially.
|
|
|
2538
2572
|
|
|
2539
2573
|
## 6.23.0
|
|
2540
2574
|
|
|
2541
|
-
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
|
|
2542
2576
|
up with a meeting that is orphaned that we have no ability to keep."
|
|
2543
2577
|
|
|
2544
2578
|
Found live while writing this: two sessions stranded for 184 and 24 minutes, holding
|
|
@@ -2593,7 +2627,7 @@ flake under file parallelism, which is a pre-existing isolation bug.
|
|
|
2593
2627
|
## 6.22.1
|
|
2594
2628
|
|
|
2595
2629
|
Notes attached from somewhere else by a symlink are now read properly. Found by
|
|
2596
|
-
|
|
2630
|
+
Sam within hours of 6.22.0, on the very first real setup.
|
|
2597
2631
|
|
|
2598
2632
|
- **A symlinked subfolder or file was silently skipped.** `readdirSync` reports a
|
|
2599
2633
|
symlink as `isSymbolicLink()`, never as `isDirectory()` or `isFile()`, so the walk
|
|
@@ -2830,15 +2864,15 @@ nothing she could name would work.
|
|
|
2830
2864
|
correction row has recorded `proseStale: true` for exactly this since the feature
|
|
2831
2865
|
shipped — and NOTHING read it.
|
|
2832
2866
|
|
|
2833
|
-
|
|
2834
|
-
only him and
|
|
2835
|
-
sites were rewritten correctly. The LLM summary still opened "
|
|
2836
|
-
|
|
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
|
|
2837
2871
|
it only as "not confirmed", which is far too weak: he did not fail to confirm
|
|
2838
2872
|
that person, he explicitly said they were not in the room.
|
|
2839
2873
|
|
|
2840
2874
|
The payload now carries `removedNames` and states it above the write-up: *"You
|
|
2841
|
-
removed "
|
|
2875
|
+
removed "Morgan Example" from this meeting. The write-up below was written before
|
|
2842
2876
|
that and still uses the name: treat every mention of it as a capture error, not
|
|
2843
2877
|
a participant."* The prose is left intact — the record stays, the correction
|
|
2844
2878
|
travels beside it.
|
|
@@ -2881,7 +2915,7 @@ without the floor.
|
|
|
2881
2915
|
person: `"MU" by wearing the device; "Gina Obert" by voice match; "Luke Henry"
|
|
2882
2916
|
because a human named that voice`. Labels are quoted, so a typed "Smith, John"
|
|
2883
2917
|
cannot read as two people, and the caveat now covers different SPELLINGS of a
|
|
2884
|
-
confirmed name (labels are `MU` while the prose says "
|
|
2918
|
+
confirmed name (labels are `MU` while the prose says "the user").
|
|
2885
2919
|
|
|
2886
2920
|
- **A lone named voice no longer gets a share.** "100% of identified speech" is
|
|
2887
2921
|
always true with one name and reads as "he did all the talking" — on 23 real
|
|
@@ -3119,7 +3153,7 @@ without the floor.
|
|
|
3119
3153
|
- Review playback falls back to ext-audio. The 7-day archive introduced in
|
|
3120
3154
|
6.21.18 is FORWARD-ONLY — it starts filling when a meeting is saved under that
|
|
3121
3155
|
version — so on upgrade day the panel had no play buttons at all, which is what
|
|
3122
|
-
|
|
3156
|
+
the user hit. ext-audio already holds 72 hours of unrecognised-speaker audio keyed
|
|
3123
3157
|
by the same raw capture index; measured across 14 real meetings, 90-100% of
|
|
3124
3158
|
those files correspond to a chunk the sidecar labels `Ext`. That is exactly the
|
|
3125
3159
|
set a reviewer most needs to hear.
|
|
@@ -3133,7 +3167,7 @@ without the floor.
|
|
|
3133
3167
|
## 6.21.18
|
|
3134
3168
|
|
|
3135
3169
|
Everything a human needs to correct who spoke, and to hear the voice before
|
|
3136
|
-
deciding. Four changes that landed together after
|
|
3170
|
+
deciding. Four changes that landed together after the user reviewed the 2026-08-06
|
|
3137
3171
|
Ditto meeting and found eleven attributed voices, most of them wrong.
|
|
3138
3172
|
|
|
3139
3173
|
- A NAME MUST BE EARNED. `identifySpeaker` accepts a match at 0.55, so one
|
|
@@ -3154,7 +3188,7 @@ Ditto meeting and found eleven attributed voices, most of them wrong.
|
|
|
3154
3188
|
discarding which meeting each sample came from, and now stamps
|
|
3155
3189
|
`g2-training:<sessionId>`. Samples written before this are relabellable but not
|
|
3156
3190
|
retractable.
|
|
3157
|
-
- 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
|
|
3158
3192
|
a weekend). Chunk WAVs previously died with the batch pipeline —
|
|
3159
3193
|
`session-audio` held 0 files. Hard-linked at the single choke point before the
|
|
3160
3194
|
rename, so it costs no extra disk and outlives the pipeline's cleanup. Sized on
|
|
@@ -3185,7 +3219,7 @@ FIXES FOUND BY QA BEFORE PUBLISH (nothing above ever shipped):
|
|
|
3185
3219
|
read "Unidentified voice" in 4 of 9 meetings, once with 285 of their own
|
|
3186
3220
|
segments. `thrashesWith` still renders, so a mixed row is still visible.
|
|
3187
3221
|
- DE-ATTRIBUTION NUMBERS ITS LABELS. `Unidentified 1`, `Unidentified 2`, … rather
|
|
3188
|
-
than one shared `Ext`.
|
|
3222
|
+
than one shared `Ext`. the user found five wrong attributions in one meeting;
|
|
3189
3223
|
collapsing them into a single row would have destroyed his ability to tell
|
|
3190
3224
|
those voices apart, which is exactly what playback is for next.
|
|
3191
3225
|
- DE-ATTRIBUTION DELETES THE ATTENDEE BULLET instead of renaming it. Renaming
|
|
@@ -3240,7 +3274,7 @@ Requires COS Control 0.5.0+ to use the scoped correction and playback surfaces.
|
|
|
3240
3274
|
|
|
3241
3275
|
- `POST /api/meeting/:sessionId/relabel` — correct who a voice was in ONE
|
|
3242
3276
|
meeting. Body `{ from, to, chunks?, confirm | dryRun, force? }`.
|
|
3243
|
-
- Per-meeting by design, not a global merge.
|
|
3277
|
+
- Per-meeting by design, not a global merge. the user: "changing it doesn't mean
|
|
3244
3278
|
that all previous chunks should also be moved. It should be meeting by
|
|
3245
3279
|
meeting, with the goal of hardening or refining the voice profiles." The
|
|
3246
3280
|
identifier mishearing a voice in one room is not evidence that every past
|
|
@@ -3260,7 +3294,7 @@ Requires COS Control 0.5.0+ to use the scoped correction and playback surfaces.
|
|
|
3260
3294
|
human never selected. The response says why rather than staying silent.
|
|
3261
3295
|
- Narrative prose is NEVER rewritten — only reported as `proseStale` with the
|
|
3262
3296
|
forms found. Verified on a real scribe: 6 of 12 speakers are referred to by
|
|
3263
|
-
bare first name in the summary, and with two
|
|
3297
|
+
bare first name in the summary, and with two Alexes, two Jordans and two
|
|
3264
3298
|
Chrises in this org a first-name substitution would rewrite sentences about
|
|
3265
3299
|
someone else. The confirmation message says this before a human commits.
|
|
3266
3300
|
- `/api/health` reports `speaker_corrections` (sessions, applied, pending,
|
|
@@ -3280,7 +3314,7 @@ Requires COS Control 0.5.0+ to use the scoped correction and playback surfaces.
|
|
|
3280
3314
|
- `Ext` is deliberately included. An unidentified voice is the one case with no
|
|
3281
3315
|
other route to being trained at all.
|
|
3282
3316
|
- RETENTION IS 14 DAYS, not the 8 hours used for audio snippets
|
|
3283
|
-
(`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
|
|
3284
3318
|
overriding if he disagrees: 8 hours cannot survive a weekend, so a Friday
|
|
3285
3319
|
meeting could never be corrected on Monday; and an embedding is not audio — it
|
|
3286
3320
|
is a non-invertible timbre vector that cannot be played back, so the privacy
|
|
@@ -3580,7 +3614,7 @@ unsaved capture, and makes batch status stop lying about finished work.
|
|
|
3580
3614
|
- **Unsaved captures are visible.** `/api/health` gains `unsaved_captures`
|
|
3581
3615
|
(count + compact items, same exposure level as `meeting_sync`). The
|
|
3582
3616
|
authenticated `GET /api/meeting/orphans` returns full detail.
|
|
3583
|
-
- **
|
|
3617
|
+
- **the user-triggered recovery, surface-only by decision (2026-08-02).**
|
|
3584
3618
|
`POST /api/meeting/orphans/:sessionId/recover` batch-transcribes the
|
|
3585
3619
|
quarantined WAVs (same segment/enhance/Metal-preempt contract as HQ polish,
|
|
3586
3620
|
under a new `orphan_recovery` maintenance lease), writes a durable scribe,
|
|
@@ -4050,9 +4084,9 @@ unsaved capture, and makes batch status stop lying about finished work.
|
|
|
4050
4084
|
|
|
4051
4085
|
### A cloned Codex conversation gets its own identity
|
|
4052
4086
|
|
|
4053
|
-
|
|
4087
|
+
the user forked "Example project 2.0 build" into "Example project 3.0 build" and the fork never
|
|
4054
4088
|
appeared in the sessions list. It had not failed to index -- it was indexed AS ITS
|
|
4055
|
-
PARENT. The list showed one `
|
|
4089
|
+
PARENT. The list showed one `Example project 2.0 build` row whose modified time was the
|
|
4056
4090
|
fork's activity: two conversations, one identity, and the newer one invisible.
|
|
4057
4091
|
|
|
4058
4092
|
Cloning copies the parent's `session_meta` record wholesale, so the new rollout carries
|
|
@@ -4078,7 +4112,7 @@ and a clone of a clone doubles again.
|
|
|
4078
4112
|
|
|
4079
4113
|
### The seeded query was being crowded out by the steps
|
|
4080
4114
|
|
|
4081
|
-
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
|
|
4082
4116
|
real session seeded 8 events -- 6 tool calls, one prose, one status -- and **no
|
|
4083
4117
|
prompt**. The seed took "the last 7 events of any kind", and in a busy run the
|
|
4084
4118
|
user's question is twenty or thirty steps back, so the activity you opened the page
|
|
@@ -4095,12 +4129,12 @@ scrolling window.
|
|
|
4095
4129
|
|
|
4096
4130
|
### The live view stops being a blank slate
|
|
4097
4131
|
|
|
4098
|
-
Three changes, all from
|
|
4132
|
+
Three changes, all from the user watching a real session on hardware.
|
|
4099
4133
|
|
|
4100
4134
|
- **The user's query is now an event.** A `user` record used to be dropped whole,
|
|
4101
4135
|
on the reasoning that "the prompt came from this device" -- true of a Continue
|
|
4102
4136
|
turn and false of the case that matters most, a session running in a Mac window
|
|
4103
|
-
where that record is the question
|
|
4137
|
+
where that record is the question the user typed there and the glasses have never
|
|
4104
4138
|
seen it. Dropping it is why the lens said WORKING and gave no clue what it was
|
|
4105
4139
|
working ON. Tool results stay dropped; harness wrappers
|
|
4106
4140
|
(`<system-reminder>`, `<cos-alarms>`, the memory and bulletin blocks) are
|
|
@@ -4129,7 +4163,7 @@ Needs COS Glasses 6.8.374 to render any of it.
|
|
|
4129
4163
|
|
|
4130
4164
|
### A reply keeps its line structure
|
|
4131
4165
|
|
|
4132
|
-
|
|
4166
|
+
the user, from a G2 screenshot: a session reply arrived on the lens as one unbroken
|
|
4133
4167
|
paragraph carrying three headings and six bullets, none of them visible.
|
|
4134
4168
|
|
|
4135
4169
|
`proseBody` collapsed ALL whitespace, and both the one-line list gist and the
|
|
@@ -4197,7 +4231,7 @@ Needs COS Glasses 6.8.372 to be visible. An older app never calls the route.
|
|
|
4197
4231
|
|
|
4198
4232
|
### The newest assistant reply arrives whole instead of at 160 characters
|
|
4199
4233
|
|
|
4200
|
-
- **The defect.**
|
|
4234
|
+
- **The defect.** the user opened a session on the glasses and the newest reply was cut
|
|
4201
4235
|
off mid-sentence. The session detail payload had NO full-text field: it carried
|
|
4202
4236
|
`discussion_summary` (180 chars) and `discussion_digest` (2000), and the newest
|
|
4203
4237
|
reply appeared only as the `Latest:` line inside the digest, produced by
|
|
@@ -4267,7 +4301,7 @@ Needs COS Glasses 6.8.372 to be visible. An older app never calls the route.
|
|
|
4267
4301
|
### A continued turn now runs with the session's own permissions
|
|
4268
4302
|
|
|
4269
4303
|
- **This widens what Continue can do.** A prompt spoken into the glasses can run
|
|
4270
|
-
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
|
|
4271
4305
|
after his first real continued turn came back reporting that every tool was
|
|
4272
4306
|
disabled, which is not the point of the feature.
|
|
4273
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'
|