@gotcos/glasses-server 6.36.0 → 6.36.1
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 +25 -0
- package/package.json +1 -1
- package/server/lib/agent-session-store.ts +55 -7
package/CHANGELOG.md
CHANGED
|
@@ -2219,6 +2219,31 @@ unsaved capture, and makes batch status stop lying about finished work.
|
|
|
2219
2219
|
|
|
2220
2220
|
# Changelog
|
|
2221
2221
|
|
|
2222
|
+
## [6.36.1] - 2026-08-17
|
|
2223
|
+
|
|
2224
|
+
### A reply keeps its line structure
|
|
2225
|
+
|
|
2226
|
+
Miles, from a G2 screenshot: a session reply arrived on the lens as one unbroken
|
|
2227
|
+
paragraph carrying three headings and six bullets, none of them visible.
|
|
2228
|
+
|
|
2229
|
+
`proseBody` collapsed ALL whitespace, and both the one-line list gist and the
|
|
2230
|
+
`latest_reply` BODY went through it. Collapsing is right for a row and destroys a
|
|
2231
|
+
body: the client cannot restore structure the server already flattened. Two
|
|
2232
|
+
fields, two jobs, and now two paths — `latestAssistantReply` preserves newlines
|
|
2233
|
+
while `proseSnippet` still returns exactly one line.
|
|
2234
|
+
|
|
2235
|
+
### The tag strip ate prose
|
|
2236
|
+
|
|
2237
|
+
`/<[^>]+>/` deleted anything between angle brackets, so `read <file>` reached the
|
|
2238
|
+
lens as `read ,`. Every `<path>`, `<PORT>` and `<name>` a technical reply uses
|
|
2239
|
+
died the same way, mid-sentence and unreportably. Replaced with an allowlist built
|
|
2240
|
+
from the tags actually present in transcripts on this machine (measured over 3,001
|
|
2241
|
+
records: HTML from rendered output, plus the COS wrapper blocks). A name not on
|
|
2242
|
+
the list is treated as the prose it almost always is; adding one later is a
|
|
2243
|
+
one-line change, whereas a placeholder eaten out of a sentence is invisible.
|
|
2244
|
+
|
|
2245
|
+
9 execution tests on the shared prose path.
|
|
2246
|
+
|
|
2222
2247
|
## [6.36.0] - 2026-08-17
|
|
2223
2248
|
|
|
2224
2249
|
### Sessions push instead of being polled
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gotcos/glasses-server",
|
|
3
|
-
"version": "6.36.
|
|
3
|
+
"version": "6.36.1",
|
|
4
4
|
"description": "COS Glasses \u2014 self-hosted AI heads-up-display server for Even G2 smart glasses, powered by Claude Code, Codex, or Cursor Agent CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -122,12 +122,57 @@ export function firstLineTitle(text: string): string {
|
|
|
122
122
|
return line.slice(0, 80)
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
/**
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
125
|
+
/**
|
|
126
|
+
* Tags worth deleting, as opposed to any pair of angle brackets.
|
|
127
|
+
*
|
|
128
|
+
* WHY A LIST AND NOT `/<[^>]+>/`. That pattern deleted PROSE. `read <file>` in an
|
|
129
|
+
* assistant reply rendered on the lens as `read ,` because `<file>` looks exactly like
|
|
130
|
+
* a tag; `<path>`, `<PORT>`, `<name>` and every other placeholder a technical answer
|
|
131
|
+
* uses died the same way, silently, mid-sentence.
|
|
132
|
+
*
|
|
133
|
+
* These are the names actually present in transcripts on this machine (measured over
|
|
134
|
+
* 3,001 records: HTML from rendered output, plus the COS wrapper blocks the harness
|
|
135
|
+
* injects). Anything not named here is treated as the prose it almost always is.
|
|
136
|
+
* A name that shows up later and should be stripped is a one-line addition; a
|
|
137
|
+
* placeholder eaten out of a sentence is invisible and unreportable.
|
|
138
|
+
*/
|
|
139
|
+
const STRIPPABLE_TAGS = [
|
|
140
|
+
// HTML that reaches a transcript through rendered or pasted output
|
|
141
|
+
'div', 'p', 'span', 'strong', 'em', 'b', 'i', 'ul', 'ol', 'li', 'br', 'hr',
|
|
142
|
+
'code', 'pre', 'blockquote', 'table', 'thead', 'tbody', 'tr', 'td', 'th',
|
|
143
|
+
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'a', 'img', 'summary', 'details',
|
|
144
|
+
// COS / harness wrapper blocks
|
|
145
|
+
'now', 'relevant-memories', 'cache-health', 'daily-bulletin', 'cos-alarms',
|
|
146
|
+
'device-handoff', 'system-reminder', 'memory-stored', 'user_query',
|
|
147
|
+
'task-notification', 'task-id', 'tool-use-id', 'output-file', 'status',
|
|
148
|
+
'result', 'usage', 'subagent_tokens', 'tool_uses', 'duration_ms',
|
|
149
|
+
'example', 'commentary', 'string', 'functions', 'function', 'command-name',
|
|
150
|
+
'local-command-stdout', 'local-command-stderr', 'thinking',
|
|
151
|
+
]
|
|
152
|
+
|
|
153
|
+
const STRIPPABLE_TAG_RE = new RegExp(`</?(?:${STRIPPABLE_TAGS.join('|')})(?:\\s[^>]*)?/?>`, 'gi')
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Fenced code and known tags out. Shared so `proseSnippet` and `latestAssistantReply`
|
|
157
|
+
* can never disagree about what the prose of a record IS.
|
|
158
|
+
*
|
|
159
|
+
* `keepLines` is the whole difference between them, and it was the bug. A LIST ROW is
|
|
160
|
+
* one line and must collapse; a BODY is what the reader paginates and its line
|
|
161
|
+
* structure IS the formatting. Collapsing both through one path turned every heading,
|
|
162
|
+
* bullet and paragraph break in a reply into a space, and delivered a wall of prose to
|
|
163
|
+
* a 576x288 lens with no structure left for the client to lay out.
|
|
164
|
+
*/
|
|
165
|
+
function proseBody(text: string, keepLines = false): string {
|
|
166
|
+
const body = text.replace(/```[\s\S]*?```/g, ' ').replace(STRIPPABLE_TAG_RE, ' ')
|
|
167
|
+
if (!keepLines) return body.replace(/\s+/g, ' ').trim()
|
|
168
|
+
return body
|
|
169
|
+
// Spaces and tabs collapse; newlines do not.
|
|
170
|
+
.replace(/[^\S\n]+/g, ' ')
|
|
171
|
+
// Trailing space before a break would render as a hanging indent on the lens.
|
|
172
|
+
.replace(/ *\n/g, '\n')
|
|
173
|
+
// Three or more breaks is never meaningful and costs a reader page.
|
|
174
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
175
|
+
.trim()
|
|
131
176
|
}
|
|
132
177
|
|
|
133
178
|
export function proseSnippet(text: string, max = 160): string {
|
|
@@ -166,7 +211,10 @@ export const LATEST_REPLY_MAX = 4000
|
|
|
166
211
|
* to say so.
|
|
167
212
|
*/
|
|
168
213
|
export function latestAssistantReply(text: string, max = LATEST_REPLY_MAX): string {
|
|
169
|
-
|
|
214
|
+
// LINE STRUCTURE PRESERVED. This is the field the reader renders, so its headings,
|
|
215
|
+
// bullets and paragraph breaks have to survive the trip; the client cannot restore
|
|
216
|
+
// structure the server already flattened.
|
|
217
|
+
const body = proseBody(text, true)
|
|
170
218
|
if (!body || isWrapperPrompt(body)) return ''
|
|
171
219
|
return body.length <= max ? body : `${body.slice(0, max - 1)}…`
|
|
172
220
|
}
|