@gotcos/glasses-server 6.94.4 → 6.98.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 (109) hide show
  1. package/CHANGELOG.md +147 -0
  2. package/README.md +52 -0
  3. package/managed-runtime-contract.json +13 -0
  4. package/package.json +3 -1
  5. package/server/index.ts +19 -1
  6. package/server/lib/attached-provider-adapter.ts +35 -1
  7. package/server/lib/claude-bridge.ts +47 -0
  8. package/server/lib/codex-bridge.ts +11 -1
  9. package/server/lib/codex-rollout-watermark.ts +42 -0
  10. package/server/lib/cursor-bridge.ts +2 -1
  11. package/server/lib/dictation-clean-models.ts +2 -0
  12. package/server/lib/dictation-clean.ts +2 -2
  13. package/server/lib/dictation-polish-pipeline.ts +22 -2
  14. package/server/lib/dictation-prewarm.ts +16 -0
  15. package/server/lib/direct-bridge.ts +14 -2
  16. package/server/lib/direct-sse.ts +6 -1
  17. package/server/lib/display-bus.ts +1 -1
  18. package/server/lib/fork-thread.ts +32 -1
  19. package/server/lib/held-naming-batches.ts +36 -0
  20. package/server/lib/job-audit-caller.ts +20 -0
  21. package/server/lib/lens-gist-engines.ts +17 -5
  22. package/server/lib/live-cos-ask.ts +29 -6
  23. package/server/lib/live-cue-verdicts.ts +43 -8
  24. package/server/lib/live-cues-engine.ts +4 -1
  25. package/server/lib/live-cues-filter.ts +50 -0
  26. package/server/lib/live-cues-general-prompts.ts +137 -0
  27. package/server/lib/live-cues-general-topic.ts +245 -0
  28. package/server/lib/live-cues-general.ts +715 -0
  29. package/server/lib/live-cues-v2-data.ts +453 -0
  30. package/server/lib/live-cues-v2-grounded.ts +262 -0
  31. package/server/lib/live-cues-v2-judge-b.ts +59 -0
  32. package/server/lib/live-cues-v2-names.ts +49 -0
  33. package/server/lib/live-cues-v2-notes.ts +8 -4
  34. package/server/lib/live-cues-v2-open-items.ts +132 -0
  35. package/server/lib/live-cues-v2-pacing.ts +45 -0
  36. package/server/lib/live-cues-v2-prompts-kinds.ts +9 -4
  37. package/server/lib/live-cues-v2-settings.ts +89 -10
  38. package/server/lib/live-cues-v2.ts +570 -47
  39. package/server/lib/mac-recording-asr.ts +6 -3
  40. package/server/lib/mac-speaker-call-human.ts +371 -0
  41. package/server/lib/mac-speaker-call-interval-human.ts +499 -0
  42. package/server/lib/mac-speaker-call-interval-projection.ts +233 -0
  43. package/server/lib/mac-speaker-call-original-view.ts +328 -0
  44. package/server/lib/mac-speaker-call-producer-worker.ts +615 -0
  45. package/server/lib/mac-speaker-call-producer.ts +539 -0
  46. package/server/lib/mac-speaker-call-store.ts +264 -0
  47. package/server/lib/mac-speaker-call-view.ts +373 -0
  48. package/server/lib/mac-speaker-live-compute.ts +72 -0
  49. package/server/lib/mac-speaker-live-memory.ts +414 -0
  50. package/server/lib/mac-speaker-live-projection.ts +126 -0
  51. package/server/lib/mac-speaker-live-save.ts +90 -0
  52. package/server/lib/mac-speaker-live-store.ts +71 -0
  53. package/server/lib/mac-speaker-live-worker.ts +58 -0
  54. package/server/lib/mac-speaker-live.ts +175 -0
  55. package/server/lib/mac-speaker-profile-extractor.ts +15 -10
  56. package/server/lib/mac-speaker-shadow-repair.ts +307 -0
  57. package/server/lib/mac-voice-assignment.ts +44 -26
  58. package/server/lib/mac-voice-display.ts +195 -0
  59. package/server/lib/mac-voice-naming-batch.ts +1067 -0
  60. package/server/lib/mac-voice-suggestions.ts +548 -0
  61. package/server/lib/maintenance-lifecycle.ts +2 -0
  62. package/server/lib/media-store.ts +2 -1
  63. package/server/lib/meeting-ask-pasted.ts +135 -0
  64. package/server/lib/meeting-ask-review.ts +8 -1
  65. package/server/lib/meeting-ask-runner.ts +4 -1
  66. package/server/lib/meeting-ask-runtime.ts +189 -17
  67. package/server/lib/meeting-ask-store.ts +2 -0
  68. package/server/lib/meeting-ask-web.ts +284 -13
  69. package/server/lib/meeting-batch-progress.ts +51 -5
  70. package/server/lib/meeting-batch-transcribe.ts +35 -2
  71. package/server/lib/meeting-fact-check.ts +3 -0
  72. package/server/lib/meeting-finalization-jobs.ts +69 -2
  73. package/server/lib/meeting-public-topic.ts +6 -1
  74. package/server/lib/meeting-speaker-review.ts +182 -17
  75. package/server/lib/meeting-store.ts +6 -1
  76. package/server/lib/parakeet.ts +51 -5
  77. package/server/lib/pending-batch-retention.ts +58 -0
  78. package/server/lib/private-reference.ts +38 -0
  79. package/server/lib/provider-usage.ts +561 -0
  80. package/server/lib/public-https-url.ts +32 -0
  81. package/server/lib/query-job-runtime.ts +3 -0
  82. package/server/lib/rich-media-safety.ts +23 -2
  83. package/server/lib/speaker-shadow-decide.ts +503 -0
  84. package/server/lib/speaker-shadow-models.ts +150 -0
  85. package/server/lib/speaker-shadow-numeric.ts +143 -0
  86. package/server/lib/speaker-shadow-pair-source.ts +91 -0
  87. package/server/lib/speaker-shadow-paired.ts +268 -0
  88. package/server/lib/speaker-shadow-report.ts +113 -0
  89. package/server/lib/speaker-shadow-timeline.ts +210 -0
  90. package/server/lib/speaker-shadow-worker.ts +312 -0
  91. package/server/lib/speaker-shadow.ts +788 -0
  92. package/server/lib/token-audit.ts +36 -6
  93. package/server/lib/transcript-cleanup.ts +3 -2
  94. package/server/lib/voice-directory.ts +8 -4
  95. package/server/lib/web-lookup-ledger.ts +151 -0
  96. package/server/lib/work-review-runtime.ts +2 -0
  97. package/server/lib/work-search.ts +3 -1
  98. package/server/lib/xlsx-text.ts +277 -0
  99. package/server/routes/health.ts +5 -0
  100. package/server/routes/live-cues.ts +36 -14
  101. package/server/routes/meeting.ts +506 -49
  102. package/server/routes/speaker-shadow.ts +79 -0
  103. package/server/routes/transcribe-stream.ts +114 -33
  104. package/server/routes/voice.ts +3 -0
  105. package/server/scripts/live-cues-v3-mutation-gate.mjs +311 -0
  106. package/server/scripts/mac-voice-assignment-6930-mutation-gate.mjs +5 -5
  107. package/shared/live-cues-v2.ts +38 -5
  108. package/shared/media-attachment.ts +2 -0
  109. package/shared/meeting-ask.ts +11 -0
@@ -3,11 +3,13 @@
3
3
  //
4
4
  // POST /live-cues/start { sessionId, kinds? } -> { armed, sessionId, pipelinesUsed } (v1) or the v2 arm answer
5
5
  // kinds (6.86.0, v2 only): 'legacy' (reinforce, challenge) or 'extended' (plus decision, promise, followUp). Absent: a
6
- // Mac recording (mac_ id) gets extended, every other meeting legacy, so an older companion never sees a kind it drops.
6
+ // Mac recording (mac_ id) gets extended, every other meeting legacy, so an older companion never sees a kind it drops. A G2 meeting armed 'extended' (6.97.9) gets the five kinds and
7
+ // nothing else of the Mac's: no general (web) cues, no cue mode `general` switching its focused cues off, no open-items fold.
7
8
  // POST /live-cues/stop { sessionId } -> { nudgesGenerated, nudges }
8
9
  // GET /live-cues/status -> engine snapshot + capability
9
10
  // GET /live-cues/v2/settings -> { enabled, source: env|setting|default, capability } (6.76.2)
10
11
  // POST /live-cues/v2/settings { enabled } -> same shape; 409 { error: 'env_forced' } when env forces v2 on
12
+ // ?v=2 / {v: 2}: the spend limits (6.79.2). ?v=3 / {v: 3}: the cue mode, grounded cues and the general-cue limits (live cues v3).
11
13
  // POST /live-cues/feedback { sessionId, cueId, verdict, note? } -> { ok, cueId, verdict, vote } (6.79.0)
12
14
  // GET /live-cues/history?days=7&sessionId=a,b&unrated=1&limit=200 -> { v: 1, cues, counts, truncated, skipped, maxCuesPerMeeting, meetings? } (6.79.0)
13
15
 
@@ -20,8 +22,11 @@ import {
20
22
  LiveCuesArmError,
21
23
  } from '../lib/live-cues-engine.js'
22
24
  import { liveCuesCapability } from '../lib/live-cues-capability.js'
23
- import { applyLiveCuesV2Settings, liveCuesV2SettingsViewV2 } from '../lib/live-cues-v2.js'
24
- import { LIVE_CUES_V2_LIMIT_BOUNDS, LIVE_CUES_V2_LIMIT_NAMES, limitInBounds, type LiveCuesV2StoredLimits } from '../lib/live-cues-v2-settings.js'
25
+ import { applyLiveCuesV2Settings, liveCuesV2SettingsViewV2, liveCuesV2SettingsViewV3 } from '../lib/live-cues-v2.js'
26
+ import {
27
+ LIVE_CUES_GENERAL_LIMIT_BOUNDS, LIVE_CUES_GENERAL_LIMIT_NAMES, LIVE_CUES_V2_LIMIT_BOUNDS, LIVE_CUES_V2_LIMIT_NAMES, generalLimitInBounds, isCueMode, isGrounding, limitInBounds,
28
+ type LiveCuesGeneralStoredLimits, type LiveCuesV2StoredLimits,
29
+ } from '../lib/live-cues-v2-settings.js'
25
30
  import { LIVE_CUES_V2_LIMITS, LiveCuesV2ArmError, liveCuesV2, liveCuesV2Advertised, liveCuesV2Enabled, liveCuesV2MeetingCounters, liveCuesV2SettingsView, peekLiveCuesV2, setLiveCuesV2Enabled } from '../lib/live-cues-v2.js'
26
31
  import { LIVE_CUE_VERDICTS_PROTOCOL, LIVE_CUE_VERDICT_LIMITS, VerdictsUnreadableError, isCueVerdict, liveCueVerdicts } from '../lib/live-cue-verdicts.js'
27
32
 
@@ -202,15 +207,15 @@ liveCuesRouter.get('/live-cues/history', (req, res) => {
202
207
  liveCuesRouter.get('/live-cues/v2/settings', (req, res) => {
203
208
  res.set('Cache-Control', 'private, no-store')
204
209
  const v = req.query.v
205
- if (v !== undefined && v !== '2') return res.status(400).json({ error: 'invalid_request', reason: 'unsupported_version' })
206
- try { return res.json(v === '2' ? liveCuesV2SettingsViewV2() : liveCuesV2SettingsView()) } catch { return res.status(503).json({ error: 'settings_unavailable' }) }
210
+ if (v !== undefined && v !== '2' && v !== '3') return res.status(400).json({ error: 'invalid_request', reason: 'unsupported_version' })
211
+ try { return res.json(v === '3' ? liveCuesV2SettingsViewV3() : v === '2' ? liveCuesV2SettingsViewV2() : liveCuesV2SettingsView()) } catch { return res.status(503).json({ error: 'settings_unavailable' }) }
207
212
  })
208
213
 
209
214
  const V2_SETTINGS_KEYS = new Set<string>(['v', 'enabled', ...LIVE_CUES_V2_LIMIT_NAMES])
210
215
  liveCuesRouter.post('/live-cues/v2/settings', (req, res) => {
211
216
  res.set('Cache-Control', 'private, no-store')
212
217
  const body = req.body as { enabled?: unknown; v?: unknown } | undefined
213
- if (body && typeof body === 'object' && !Array.isArray(body) && body.v !== undefined) return postSettingsV2(body as Record<string, unknown>, res)
218
+ if (body && typeof body === 'object' && !Array.isArray(body) && body.v !== undefined) return postSettingsVersioned(body as Record<string, unknown>, res)
214
219
  if (!body || typeof body !== 'object' || Array.isArray(body) || typeof body.enabled !== 'boolean') {
215
220
  return res.status(400).json({ error: 'invalid_request' })
216
221
  }
@@ -223,12 +228,19 @@ liveCuesRouter.post('/live-cues/v2/settings', (req, res) => {
223
228
  }
224
229
  })
225
230
 
226
- /** POST {v: 2, ...}: every field is checked before anything is saved, so a refused request changes nothing. */
227
- function postSettingsV2(body: Record<string, unknown>, res: import('express').Response) {
228
- if (body.v !== 2) return res.status(400).json({ error: 'invalid_request', reason: 'unsupported_version' })
229
- const unknown = Object.keys(body).find(k => !V2_SETTINGS_KEYS.has(k))
231
+ const V3_SETTINGS_KEYS = new Set<string>([...V2_SETTINGS_KEYS, 'cueMode', 'grounding', ...LIVE_CUES_GENERAL_LIMIT_NAMES.map(name => LIVE_CUES_GENERAL_LIMIT_BOUNDS[name].field)])
232
+
233
+ /** POST {v: 2, ...} (the spend limits, 6.79.2) and POST {v: 3, ...} (live cues v3: the same plus cueMode, grounding and the six
234
+ * general limits). Every field is checked before anything is saved, so a refused request changes nothing. v=2 takes none of
235
+ * the v3 fields (unknown_field), exactly as before. A bad enum is invalid_value; a number out of bounds names the wire field. */
236
+ function postSettingsVersioned(body: Record<string, unknown>, res: import('express').Response) {
237
+ if (body.v !== 2 && body.v !== 3) return res.status(400).json({ error: 'invalid_request', reason: 'unsupported_version' })
238
+ const v3 = body.v === 3
239
+ const unknown = Object.keys(body).find(k => !(v3 ? V3_SETTINGS_KEYS : V2_SETTINGS_KEYS).has(k))
230
240
  if (unknown) return res.status(400).json({ error: 'invalid_request', reason: 'unknown_field', field: unknown })
231
241
  if (body.enabled !== undefined && typeof body.enabled !== 'boolean') return res.status(400).json({ error: 'invalid_request', reason: 'invalid_enabled', field: 'enabled' })
242
+ if (v3 && body.cueMode !== undefined && !isCueMode(body.cueMode)) return res.status(400).json({ error: 'invalid_request', reason: 'invalid_value', field: 'cueMode' })
243
+ if (v3 && body.grounding !== undefined && !isGrounding(body.grounding)) return res.status(400).json({ error: 'invalid_request', reason: 'invalid_value', field: 'grounding' })
232
244
  const limits: LiveCuesV2StoredLimits = {}
233
245
  for (const name of LIVE_CUES_V2_LIMIT_NAMES) {
234
246
  if (body[name] === undefined) continue
@@ -238,11 +250,21 @@ function postSettingsV2(body: Record<string, unknown>, res: import('express').Re
238
250
  }
239
251
  limits[name] = body[name] as number
240
252
  }
241
- if (body.enabled === undefined && Object.keys(limits).length === 0) return res.status(400).json({ error: 'invalid_request', reason: 'empty' })
253
+ const general: LiveCuesGeneralStoredLimits = {}
254
+ for (const name of LIVE_CUES_GENERAL_LIMIT_NAMES) {
255
+ const b = LIVE_CUES_GENERAL_LIMIT_BOUNDS[name]
256
+ if (body[b.field] === undefined) continue
257
+ if (!generalLimitInBounds(name, body[b.field])) return res.status(400).json({ error: 'invalid_request', reason: 'out_of_bounds', field: b.field, min: b.min, max: b.max, integer: b.integer })
258
+ general[name] = body[b.field] as number
259
+ }
260
+ const v3Fields = body.cueMode !== undefined || body.grounding !== undefined || Object.keys(general).length > 0
261
+ if (body.enabled === undefined && Object.keys(limits).length === 0 && !v3Fields) return res.status(400).json({ error: 'invalid_request', reason: 'empty' })
242
262
  try {
243
- const result = applyLiveCuesV2Settings({ ...(typeof body.enabled === 'boolean' ? { enabled: body.enabled } : {}), limits })
244
- if (!result.ok) return res.status(409).json(result.error === 'env_locked' ? { error: 'env_locked', fields: result.fields } : { error: result.error })
245
- return res.json(liveCuesV2SettingsViewV2())
263
+ const result = applyLiveCuesV2Settings({ ...(typeof body.enabled === 'boolean' ? { enabled: body.enabled } : {}), limits,
264
+ ...(isCueMode(body.cueMode) ? { cueMode: body.cueMode } : {}), ...(isGrounding(body.grounding) ? { grounding: body.grounding } : {}),
265
+ ...(Object.keys(general).length ? { general } : {}) })
266
+ if (!result.ok) return res.status(409).json(result.error === 'env_locked' ? { error: 'env_locked', fields: result.fields } : result.fields ? { error: 'env_forced', fields: result.fields } : { error: result.error })
267
+ return res.json(v3 ? liveCuesV2SettingsViewV3() : liveCuesV2SettingsViewV2())
246
268
  } catch {
247
269
  return res.status(500).json({ error: 'settings_write_failed' })
248
270
  }