@gotcos/glasses-server 6.16.2 → 6.16.4

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 CHANGED
@@ -1,3 +1,27 @@
1
+ ## 6.16.4
2
+
3
+ - **Cursor Agent on legacy `/api/query`.** 6.16.3 only forwarded
4
+ `cursorExecutionMode` on durable jobs. Most installs still run with
5
+ `durableQueryJobs: false`, so the companion fell back to `/api/query` and
6
+ Cursor stayed Ask (Shell Rejected). Legacy route now accepts the field;
7
+ Cursor omit/unknown defaults to **agent** (Settings default). Explicit `ask`
8
+ still forces read-only. Durable runtime uses the same default.
9
+
10
+ ## 6.16.3
11
+
12
+ - **Cursor Agent mode on durable jobs.** Glasses Settings → Agent now reaches
13
+ the CLI (`--force` / no `--mode ask`). Public 6.16.1–6.16.2 accepted Cursor
14
+ models but dropped `cursorExecutionMode` before query-job execution, so every
15
+ turn stayed Ask and Shell was Rejected. Parse + forward `agent`|`ask`; omit
16
+ still defaults to ask for old clients.
17
+
18
+ ## 6.16.2
19
+
20
+ - **COS operations meetings library.** G2 Review Meetings can list markdown from
21
+ a configurable COS `operations/` tree via `COS_OPERATIONS_DIR` /
22
+ `COS_MEETINGS_ROOT`, with fallback to `COS_SCRIPTS_DIR/..`, then standalone
23
+ recordings. Opt-in per install — no hardcoded COS layout.
24
+
1
25
  ## 6.16.1
2
26
 
3
27
  - **Cursor Agent models (Composer 2.5 / Grok 4.5).** Managed installs now ship
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gotcos/glasses-server",
3
- "version": "6.16.2",
3
+ "version": "6.16.4",
4
4
  "description": "COS Glasses — 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": {
@@ -13,6 +13,7 @@ import {
13
13
  isCursorModel,
14
14
  normalizeEffortPreference,
15
15
  normalizeModelPreference,
16
+ type CursorExecutionMode,
16
17
  type ModelPreference,
17
18
  } from '../../shared/model-preference.js'
18
19
  import { mergeMediaAttachmentRefs } from '../../shared/media-attachment.js'
@@ -238,6 +239,15 @@ const runner: QueryJobRunner = async ({ jobId, turnId, request, signal, callback
238
239
  {
239
240
  abortSignal: signal,
240
241
  effort: validEffort,
242
+ // Glasses Settings default is Agent. Explicit ask stays ask; omit → agent
243
+ // for Cursor so legacy clients aren't stuck in Ask when durable is off.
244
+ ...(validModel && isCursorModel(validModel)
245
+ ? {
246
+ cursorExecutionMode: (
247
+ request.cursorExecutionMode === 'ask' ? 'ask' : 'agent'
248
+ ) as CursorExecutionMode,
249
+ }
250
+ : {}),
241
251
  clientJobId: request.clientJobId,
242
252
  generation: request.generation,
243
253
  sessionLockHeld: true,
@@ -455,6 +455,7 @@ export class QueryJobStore {
455
455
  sessionId: request.sessionId,
456
456
  ...(request.model ? { requestedModel: request.model } : {}),
457
457
  ...(request.effort ? { effort: request.effort } : {}),
458
+ ...(request.cursorExecutionMode ? { cursorExecutionMode: request.cursorExecutionMode } : {}),
458
459
  ...(request.messageEra ? { messageEra: request.messageEra } : {}),
459
460
  ...(request.globalMsgNum ? { globalMsgNum: request.globalMsgNum } : {}),
460
461
  ...(request.handoffCode ? { handoffCode: request.handoffCode } : {}),
@@ -61,6 +61,8 @@ export interface QueryJobRequest {
61
61
  sessionId: string
62
62
  model?: string
63
63
  effort?: string
64
+ /** Cursor ask|agent. Omitted means ask on the server (old clients). */
65
+ cursorExecutionMode?: string
64
66
  messageEra?: string
65
67
  globalMsgNum?: number
66
68
  reference?: QueryJobPromptReference
@@ -119,6 +121,7 @@ export interface QueryJobSnapshot extends QueryJobProviderLinkage {
119
121
  sessionId: string
120
122
  requestedModel?: string
121
123
  effort?: string
124
+ cursorExecutionMode?: string
122
125
  messageEra?: string
123
126
  globalMsgNum?: number
124
127
  handoffCode?: string
@@ -239,6 +242,10 @@ export function parseQueryJobRequest(raw: unknown): QueryJobRequest {
239
242
 
240
243
  const model = optionalString(input.model, 'model', 64)
241
244
  const effort = optionalString(input.effort, 'effort', 32)
245
+ const cursorExecutionModeRaw = optionalString(input.cursorExecutionMode, 'cursor_execution_mode', 16)
246
+ const cursorExecutionMode = cursorExecutionModeRaw === 'agent' || cursorExecutionModeRaw === 'ask'
247
+ ? cursorExecutionModeRaw
248
+ : undefined
242
249
  const messageEra = optionalString(input.messageEra, 'message_era', 80)
243
250
  const handoffCode = optionalString(input.handoffCode, 'handoff_code', 128)
244
251
  const clientQueueItemId = optionalString(input.clientQueueItemId, 'client_queue_item_id', 120)
@@ -277,6 +284,7 @@ export function parseQueryJobRequest(raw: unknown): QueryJobRequest {
277
284
  sessionId,
278
285
  ...(model ? { model } : {}),
279
286
  ...(effort ? { effort } : {}),
287
+ ...(cursorExecutionMode ? { cursorExecutionMode } : {}),
280
288
  ...(messageEra ? { messageEra } : {}),
281
289
  ...(globalMsgNum ? { globalMsgNum } : {}),
282
290
  ...(reference ? { reference } : {}),
@@ -5,7 +5,11 @@ import { Router } from 'express'
5
5
  import { callModelStreaming } from '../lib/model-router.js'
6
6
  import { emitDisplay } from '../lib/display-bus.js'
7
7
  import { errMsg } from '../lib/utils.js'
8
- import { normalizeEffortPreference, normalizeModelPreference } from '../../shared/model-preference.js'
8
+ import {
9
+ isCursorModel,
10
+ normalizeEffortPreference,
11
+ normalizeModelPreference,
12
+ } from '../../shared/model-preference.js'
9
13
  import { QueryAttachmentError, resolveQueryAttachments } from '../lib/query-attachments.js'
10
14
  import { getMediaStore } from '../lib/media-store.js'
11
15
  import { mergeMediaAttachmentRefs } from '../../shared/media-attachment.js'
@@ -38,6 +42,9 @@ queryRouter.post('/query', async (req, res) => {
38
42
  const activityToolMode = req.body.activityToolMode === 'off' || req.body.activityToolMode === 'preview'
39
43
  ? req.body.activityToolMode
40
44
  : 'status'
45
+ // Glasses Settings default is Agent. Only an explicit "ask" stays read-only —
46
+ // omit/unknown must not silently force Ask (6.16.3 durable-only gap).
47
+ const cursorExecutionMode = req.body.cursorExecutionMode === 'ask' ? 'ask' as const : 'agent' as const
41
48
 
42
49
  // Resolve durable attachment ids and legacy base64 images through one
43
50
  // validation/normalization path before opening SSE.
@@ -170,7 +177,11 @@ queryRouter.post('/query', async (req, res) => {
170
177
  ? { query: String(reference.query), response: String(reference.response) }
171
178
  : undefined,
172
179
  validGlobalMsgNum,
173
- { abortSignal: abortController.signal, effort: validEffort },
180
+ {
181
+ abortSignal: abortController.signal,
182
+ effort: validEffort,
183
+ ...(validModel && isCursorModel(validModel) ? { cursorExecutionMode } : {}),
184
+ },
174
185
  )
175
186
  } catch (err: unknown) {
176
187
  maintenanceLease.release()