@extentos/mcp-server 0.10.1 → 0.11.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/README.md +1 -1
- package/dist/tools/data/capabilities.js +1 -1
- package/dist/tools/data/capabilities.js.map +1 -1
- package/dist/tools/data/capabilityPatterns.d.ts.map +1 -1
- package/dist/tools/data/capabilityPatterns.js +152 -53
- package/dist/tools/data/capabilityPatterns.js.map +1 -1
- package/dist/tools/data/codeExamples.d.ts.map +1 -1
- package/dist/tools/data/codeExamples.js +206 -49
- package/dist/tools/data/codeExamples.js.map +1 -1
- package/dist/tools/data/version.js +6 -6
- package/dist/tools/data/version.js.map +1 -1
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/definitions.js +61 -19
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/docs/index.d.ts.map +1 -1
- package/dist/tools/docs/index.js +51 -22
- package/dist/tools/docs/index.js.map +1 -1
- package/dist/tools/handlers/generateConnectionModule.d.ts.map +1 -1
- package/dist/tools/handlers/generateConnectionModule.js +36 -4
- package/dist/tools/handlers/generateConnectionModule.js.map +1 -1
- package/dist/tools/handlers/getEventLog.d.ts.map +1 -1
- package/dist/tools/handlers/getEventLog.js +38 -2
- package/dist/tools/handlers/getEventLog.js.map +1 -1
- package/dist/tools/handlers/validateIntegration.d.ts.map +1 -1
- package/dist/tools/handlers/validateIntegration.js +89 -31
- package/dist/tools/handlers/validateIntegration.js.map +1 -1
- package/dist/tools/templates/androidBootstrap.d.ts.map +1 -1
- package/dist/tools/templates/androidBootstrap.js +10 -0
- package/dist/tools/templates/androidBootstrap.js.map +1 -1
- package/dist/tools/util/dependency.d.ts.map +1 -1
- package/dist/tools/util/dependency.js +64 -13
- package/dist/tools/util/dependency.js.map +1 -1
- package/dist/tools/util/manifest.d.ts.map +1 -1
- package/dist/tools/util/manifest.js +7 -3
- package/dist/tools/util/manifest.js.map +1 -1
- package/dist/tools/util/permissions.d.ts.map +1 -1
- package/dist/tools/util/permissions.js +3 -1
- package/dist/tools/util/permissions.js.map +1 -1
- package/package.json +68 -66
|
@@ -330,7 +330,8 @@ class VisionHandler(
|
|
|
330
330
|
// click-to-fire panel. Same shape as Android.
|
|
331
331
|
registration = glasses.voice.onPhrase(
|
|
332
332
|
phrase: "describe what you see",
|
|
333
|
-
label: "Describe scene"
|
|
333
|
+
label: "Describe scene",
|
|
334
|
+
stops: []
|
|
334
335
|
) { [glasses, vision] in
|
|
335
336
|
let captureResult = await glasses.camera.capturePhoto(
|
|
336
337
|
config: PhotoConfig(resolution: .medium, format: .jpeg)
|
|
@@ -340,7 +341,7 @@ class VisionHandler(
|
|
|
340
341
|
return
|
|
341
342
|
}
|
|
342
343
|
|
|
343
|
-
// Photo.
|
|
344
|
+
// Photo.uri is a String? whose scheme varies by transport
|
|
344
345
|
// (file:// on RealMeta / LocalSim, data: on BrowserSim).
|
|
345
346
|
// Decode via the bundled extension; pass the bytes to
|
|
346
347
|
// your vision LLM however it expects them (base64, Data).
|
|
@@ -511,7 +512,8 @@ class NotesHandler(
|
|
|
511
512
|
// connection page + simulator panel. Same shape as Android.
|
|
512
513
|
registration = glasses.voice.onPhrase(
|
|
513
514
|
phrase: "take a note",
|
|
514
|
-
label: "Take a note"
|
|
515
|
+
label: "Take a note",
|
|
516
|
+
stops: []
|
|
515
517
|
) { [glasses, notes] in
|
|
516
518
|
_ = await glasses.audio.speak("Recording.")
|
|
517
519
|
let result = await glasses.audio.recordDiscrete(
|
|
@@ -1376,7 +1378,7 @@ class CoachHandler(
|
|
|
1376
1378
|
}`,
|
|
1377
1379
|
swift: `// HANDLER UNDER TEST — the agent writes this against the SDK.
|
|
1378
1380
|
// Three assertion-relevant points marked **ASSERT** in comments below.
|
|
1379
|
-
import
|
|
1381
|
+
import GlassesCore
|
|
1380
1382
|
import GRDB // or Core Data; this example uses GRDB for sqlite-readable schema
|
|
1381
1383
|
|
|
1382
1384
|
struct CoachingTurn: Codable, FetchableRecord, PersistableRecord {
|
|
@@ -1388,7 +1390,7 @@ struct CoachingTurn: Codable, FetchableRecord, PersistableRecord {
|
|
|
1388
1390
|
}
|
|
1389
1391
|
|
|
1390
1392
|
actor CoachHandler {
|
|
1391
|
-
let glasses:
|
|
1393
|
+
let glasses: any ExtentosGlasses
|
|
1392
1394
|
let anthropic: AnthropicClient
|
|
1393
1395
|
let db: DatabaseQueue
|
|
1394
1396
|
private var registration: VoiceRegistration?
|
|
@@ -1399,7 +1401,8 @@ actor CoachHandler {
|
|
|
1399
1401
|
func start() {
|
|
1400
1402
|
registration = glasses.voice.onPhrase(
|
|
1401
1403
|
phrase: "ask my coach",
|
|
1402
|
-
label: "Ask"
|
|
1404
|
+
label: "Ask",
|
|
1405
|
+
stops: []
|
|
1403
1406
|
) { [weak self] in
|
|
1404
1407
|
await self?.handleWake()
|
|
1405
1408
|
}
|
|
@@ -1416,7 +1419,7 @@ actor CoachHandler {
|
|
|
1416
1419
|
// **ASSERT POINT 1** — handler enters recordDiscrete; agent's
|
|
1417
1420
|
// injectTranscript satisfies this via the F-R5-03 race fix on iOS.
|
|
1418
1421
|
guard case .success(let rec) = await glasses.audio.recordDiscrete(
|
|
1419
|
-
config: AudioRecordConfig(silenceTimeoutSeconds: 2
|
|
1422
|
+
config: AudioRecordConfig(silenceTimeoutSeconds: 2) // Int seconds on iOS
|
|
1420
1423
|
), !rec.transcript.isEmpty else { return }
|
|
1421
1424
|
|
|
1422
1425
|
// **ASSERT POINT 2** — user turn persisted BEFORE the LLM call.
|
|
@@ -1945,7 +1948,7 @@ import com.extentos.glasses.core.assistant.AssistantProvider
|
|
|
1945
1948
|
import com.extentos.glasses.core.assistant.AssistantSession
|
|
1946
1949
|
import com.extentos.glasses.core.assistant.ToolResult
|
|
1947
1950
|
import com.extentos.glasses.core.assistant.tool
|
|
1948
|
-
import com.extentos.glasses.core.
|
|
1951
|
+
import com.extentos.glasses.core.assistant.orToolError
|
|
1949
1952
|
import kotlinx.coroutines.CoroutineScope
|
|
1950
1953
|
import kotlinx.coroutines.Deferred
|
|
1951
1954
|
import kotlinx.coroutines.Dispatchers
|
|
@@ -2095,7 +2098,7 @@ class StravaAssistantHandler(
|
|
|
2095
2098
|
if (capture == null) return@tool ToolResult.Err("nothing was recording")
|
|
2096
2099
|
glasses.camera.stopVideo()
|
|
2097
2100
|
val result = capture.await()
|
|
2098
|
-
val clip = result.
|
|
2101
|
+
val clip = result.orToolError { return@tool it }
|
|
2099
2102
|
library.add(clip)
|
|
2100
2103
|
ToolResult.Ok("video saved")
|
|
2101
2104
|
}
|
|
@@ -2134,8 +2137,11 @@ class StravaAssistantHandler(
|
|
|
2134
2137
|
// matchers to disambiguate. See getCapabilityGuide(feature:"assistant_vision")
|
|
2135
2138
|
// gotcha about describe-vs-save.
|
|
2136
2139
|
tool("describe_scene", "Describe what the runner is currently looking at without saving the photo. Call for 'what do you see' / 'describe this' / 'tell me about this'.") {
|
|
2137
|
-
|
|
2138
|
-
|
|
2140
|
+
// orToolError: on failure the tool returns the core's canonical,
|
|
2141
|
+
// user-actionable message (e.g. paused → "Tap the right temple…"),
|
|
2142
|
+
// so the assistant can tell the user what to DO — never a bare
|
|
2143
|
+
// "camera failed" the model can't act on.
|
|
2144
|
+
val photo = glasses.camera.capturePhoto().orToolError { return@tool it }
|
|
2139
2145
|
val uri = photo.uri
|
|
2140
2146
|
?: return@tool ToolResult.Err("photo had no uri")
|
|
2141
2147
|
// session is the AssistantSession returned by start();
|
|
@@ -2146,8 +2152,11 @@ class StravaAssistantHandler(
|
|
|
2146
2152
|
ToolResult.Ok("looking")
|
|
2147
2153
|
}
|
|
2148
2154
|
tool("save_photo", "Save a photo to the runner's library WITHOUT describing it. Call for 'save this' / 'capture this' / 'take a picture' / 'remember this view'.") {
|
|
2149
|
-
|
|
2150
|
-
|
|
2155
|
+
// orToolError: on failure the tool returns the core's canonical,
|
|
2156
|
+
// user-actionable message (e.g. paused → "Tap the right temple…"),
|
|
2157
|
+
// so the assistant can tell the user what to DO — never a bare
|
|
2158
|
+
// "camera failed" the model can't act on.
|
|
2159
|
+
val photo = glasses.camera.capturePhoto().orToolError { return@tool it }
|
|
2151
2160
|
val uri = photo.uri
|
|
2152
2161
|
?: return@tool ToolResult.Err("photo had no uri")
|
|
2153
2162
|
val ext = when (Photos.mediaTypeFromUri(uri)) {
|
|
@@ -2172,7 +2181,10 @@ class StravaAssistantHandler(
|
|
|
2172
2181
|
// active conversation. Swap this line for a button onClick,
|
|
2173
2182
|
// a gesture handler, or any other trigger that calls
|
|
2174
2183
|
// session?.wake() — the library doesn't dictate the
|
|
2175
|
-
// mechanism, only the lifecycle.
|
|
2184
|
+
// mechanism, only the lifecycle. NOTE: wake() is a suspend
|
|
2185
|
+
// function. onPhrase's handler block is already a suspend
|
|
2186
|
+
// context, but a plain call site (Compose onClick, a View
|
|
2187
|
+
// listener) must launch it: scope.launch { session?.wake() }.
|
|
2176
2188
|
glasses.voice.onPhrase("hey strava") { session?.wake() }
|
|
2177
2189
|
}
|
|
2178
2190
|
}
|
|
@@ -2247,10 +2259,10 @@ final class StravaAssistantHandler: @unchecked Sendable {
|
|
|
2247
2259
|
}
|
|
2248
2260
|
|
|
2249
2261
|
func start() async throws {
|
|
2250
|
-
// Sugar form (trailing-closure builder). Returns
|
|
2251
|
-
//
|
|
2252
|
-
// requires an explicit \`schema:\`
|
|
2253
|
-
// types — see assistant_tool
|
|
2262
|
+
// Sugar form (trailing-closure builder). Returns with the session
|
|
2263
|
+
// set up Dormant — wake() below opens the connection. Q3 asymmetry:
|
|
2264
|
+
// Swift's typed-args overload requires an explicit \`schema:\`
|
|
2265
|
+
// parameter (no Mirror walk on types — see assistant_tool guide).
|
|
2254
2266
|
let session = try await glasses.assistant.start(
|
|
2255
2267
|
provider: .openAI() // model + voice from your dashboard Agent settings
|
|
2256
2268
|
) { config in
|
|
@@ -2279,7 +2291,7 @@ final class StravaAssistantHandler: @unchecked Sendable {
|
|
|
2279
2291
|
config.tool("take_video", description: "Start recording a video clip of the runner's view.") {
|
|
2280
2292
|
self.activeVideo = Task {
|
|
2281
2293
|
let result = await self.glasses.camera.captureVideo(
|
|
2282
|
-
VideoConfig(maxDurationSeconds: 30)
|
|
2294
|
+
config: VideoConfig(maxDurationSeconds: 30)
|
|
2283
2295
|
)
|
|
2284
2296
|
return result.success
|
|
2285
2297
|
}
|
|
@@ -2305,8 +2317,13 @@ final class StravaAssistantHandler: @unchecked Sendable {
|
|
|
2305
2317
|
// Wake mechanism — canonical pattern uses glasses.voice.onPhrase; the
|
|
2306
2318
|
// session is Dormant until the phrase fires session.wake(). Swap for a
|
|
2307
2319
|
// button tap, gesture, or any trigger that calls session.wake().
|
|
2308
|
-
|
|
2309
|
-
|
|
2320
|
+
// NOTE: wake() is async. onPhrase's closure is already an async
|
|
2321
|
+
// context, but a plain call site (a SwiftUI Button action) must
|
|
2322
|
+
// wrap it: Task { try? await session.wake() }.
|
|
2323
|
+
// (Strong capture is correct: AssistantSession is not class-bound so
|
|
2324
|
+
// 'weak' won't compile, and the closure holds no 'self' — no cycle.)
|
|
2325
|
+
self.wakeRegistration = glasses.voice.onPhrase(phrase: "hey strava") { [session] in
|
|
2326
|
+
try? await session.wake()
|
|
2310
2327
|
}
|
|
2311
2328
|
}
|
|
2312
2329
|
}
|
|
@@ -2463,7 +2480,7 @@ side with this agent loop and watch the panel react.`,
|
|
|
2463
2480
|
"**Tool body runs on Dispatchers.IO (Kotlin) / Swift Task (Swift); suspending camera/storage/HTTP calls are fine.** Per-tool blocking opt-out via `tool(name, desc, blocking = true) { ... }` per synthesis #9 — when true, the model waits silently for the result before speaking. Default is non-blocking (model says \"let me check...\" while the tool runs). Use blocking=true for sub-100ms tools where the filler would be awkward (\"what time is it\" returning in 10 ms).",
|
|
2464
2481
|
"**Managed gateway by default; BYOK via dashboard Credentials.** No OpenAI key in the app — zero config. `start()` opens the realtime WebSocket against the Extentos managed gateway, which holds the key and meters usage. There is no `glasses.assistant.setOpenaiApiKey` on the SDK (it was removed when the assistant moved to gateway-only). To use your own OpenAI key, add it in the dashboard Credentials section; the gateway swaps it in server-side — still metered, still through Extentos. See `getCredentialGuide(service: \"openai\")`.",
|
|
2465
2482
|
"**`glasses.ai.complete` is deprecated in v1.4.0 and removed in v2.0.0.** Use the OpenAI SDK directly for non-voice LLM calls (image description, summarization, etc.). Migration: see `searchDocs(topic:'assistant_runtime')` → migration section walkthrough C.",
|
|
2466
|
-
"**Vision via `session.includeImage(uri, prompt = null)` (v1.4 addition).** Capture a photo, hand the URI to the assistant inside a tool body — the model sees it + speaks about it in its configured voice. URI accepts data: / http(s): / file:// / content://. The image persists in conversation history at the provider, so follow-up questions in the same session work without re-sending. Active-only (throws NotReady otherwise — safe inside a tool body where the session is always Active). Canonical pattern: `tool(\"describe_scene\", \"...\") { val photo = glasses.camera.capturePhoto().
|
|
2483
|
+
"**Vision via `session.includeImage(uri, prompt = null)` (v1.4 addition).** Capture a photo, hand the URI to the assistant inside a tool body — the model sees it + speaks about it in its configured voice. URI accepts data: / http(s): / file:// / content://. The image persists in conversation history at the provider, so follow-up questions in the same session work without re-sending. Active-only (throws NotReady otherwise — safe inside a tool body where the session is always Active). Canonical pattern: `tool(\"describe_scene\", \"...\") { val photo = glasses.camera.capturePhoto().orToolError { return@tool it }; session.includeImage(photo.uri); ToolResult.Ok(\"looking\") }` — `orToolError` (Kotlin `com.extentos.glasses.core.assistant.orToolError`; Swift `try ….orToolError()`) short-circuits the tool with the core's canonical user-actionable message (paused → \"Tap the right temple…\") so the assistant can tell the user what to do; never map capture failures to a bare \"camera failed\". See getCapabilityGuide(feature:\"assistant_vision\") for the prompt-parameter pattern + URI-type gotchas.",
|
|
2467
2484
|
"**Mid-session primitives (iter5 addition).** Four building blocks on `AssistantSession`: `setReasoningEffort(level)` for dynamic effort routing, `updateInstructions(text)` for persona/mode swaps, `cancelSpeak()` for tool-driven interrupts, `conversationHistory(limit)` for forwarding context to a stronger model. All composable with the existing tool surface — write tools that call them in their bodies. Canonical escalation pattern: a `ask_smart_model` tool body reads `session.conversationHistory()`, formats it as context, calls the customer's own GPT-5 (or Anthropic Claude, or Gemini) client, returns the response as `ToolResult.Ok(answer)` — the realtime model then speaks the answer in its configured voice. Active-only (except conversationHistory which is always safe). See getCapabilityGuide(feature:\"assistant_session_runtime\") for the canonical snippet of each.",
|
|
2468
2485
|
],
|
|
2469
2486
|
relatedFeatures: ["assistant_runtime", "assistant_start", "assistant_tool", "assistant_provider_openai", "assistant_vision", "assistant_session_runtime", "audio_chunks", "speak", "capture_photo"],
|
|
@@ -2503,7 +2520,7 @@ import com.extentos.glasses.core.assistant.AssistantProvider
|
|
|
2503
2520
|
import com.extentos.glasses.core.assistant.AssistantSession
|
|
2504
2521
|
import com.extentos.glasses.core.assistant.ToolResult
|
|
2505
2522
|
import com.extentos.glasses.core.assistant.tool
|
|
2506
|
-
import com.extentos.glasses.core.
|
|
2523
|
+
import com.extentos.glasses.core.assistant.orToolError
|
|
2507
2524
|
import android.util.Log
|
|
2508
2525
|
import kotlinx.coroutines.CoroutineScope
|
|
2509
2526
|
import kotlinx.coroutines.Dispatchers
|
|
@@ -2552,8 +2569,11 @@ class NotesAssistant(
|
|
|
2552
2569
|
}
|
|
2553
2570
|
|
|
2554
2571
|
tool("save_photo", "Take a photo and save it to the user's library. Call when the user says 'save this' or 'take a picture'.") {
|
|
2555
|
-
|
|
2556
|
-
|
|
2572
|
+
// orToolError: on failure the tool returns the core's canonical,
|
|
2573
|
+
// user-actionable message (e.g. paused → "Tap the right temple…"),
|
|
2574
|
+
// so the assistant can tell the user what to DO — never a bare
|
|
2575
|
+
// "camera failed" the model can't act on.
|
|
2576
|
+
val photo = glasses.camera.capturePhoto().orToolError { return@tool it }
|
|
2557
2577
|
val uri = photo.uri ?: return@tool ToolResult.Err("no uri")
|
|
2558
2578
|
Log.i(TAG, "save_photo: uri=\${uri.take(60)} \${photo.width}x\${photo.height}")
|
|
2559
2579
|
val dst = File(library.photosDir, "photo-\${System.currentTimeMillis()}.jpg")
|
|
@@ -2564,8 +2584,11 @@ class NotesAssistant(
|
|
|
2564
2584
|
}
|
|
2565
2585
|
|
|
2566
2586
|
tool("describe_scene", "Describe what the user is currently looking at WITHOUT saving the photo. Call for 'what do you see' / 'describe this' / 'tell me about this'.") {
|
|
2567
|
-
|
|
2568
|
-
|
|
2587
|
+
// orToolError: on failure the tool returns the core's canonical,
|
|
2588
|
+
// user-actionable message (e.g. paused → "Tap the right temple…"),
|
|
2589
|
+
// so the assistant can tell the user what to DO — never a bare
|
|
2590
|
+
// "camera failed" the model can't act on.
|
|
2591
|
+
val photo = glasses.camera.capturePhoto().orToolError { return@tool it }
|
|
2569
2592
|
val uri = photo.uri ?: return@tool ToolResult.Err("no uri")
|
|
2570
2593
|
Log.i(TAG, "describe_scene: handing uri to session.includeImage")
|
|
2571
2594
|
session?.includeImage(uri)
|
|
@@ -2616,7 +2639,7 @@ final class NotesAssistant: @unchecked Sendable {
|
|
|
2616
2639
|
provider: .openAI()
|
|
2617
2640
|
) { config in
|
|
2618
2641
|
config.instructions = "You are a voice-notes assistant on glasses. Speak briefly."
|
|
2619
|
-
|
|
2642
|
+
config.sleepAfterSilence(30) // TimeInterval seconds — auto-sleep on silence
|
|
2620
2643
|
|
|
2621
2644
|
config.tool("start_notes", description: "Start capturing the user's speech as a note. Call when the user says 'start notes' / 'take notes'.") {
|
|
2622
2645
|
NSLog("NotesAssistant start_notes: notesActive=\\(self.notesActive)")
|
|
@@ -2636,9 +2659,9 @@ final class NotesAssistant: @unchecked Sendable {
|
|
|
2636
2659
|
}
|
|
2637
2660
|
|
|
2638
2661
|
config.tool("save_photo", description: "Take a photo and save it to the library. Call when the user says 'save this' / 'take a picture'.") {
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2662
|
+
// orToolError(): on failure the tool short-circuits with the core's
|
|
2663
|
+
// canonical, user-actionable message (paused → "Tap the right temple…").
|
|
2664
|
+
let photo = try (await self.glasses.camera.capturePhoto()).orToolError()
|
|
2642
2665
|
NSLog("NotesAssistant save_photo: width=\\(photo.width)")
|
|
2643
2666
|
self.library.addPhoto(photo)
|
|
2644
2667
|
return .ok("photo saved")
|
|
@@ -2647,8 +2670,8 @@ final class NotesAssistant: @unchecked Sendable {
|
|
|
2647
2670
|
// Wake phrase wiring — same path the agent test loop drives via
|
|
2648
2671
|
// injectTranscript("hey notes"). Real users say it; the agent
|
|
2649
2672
|
// simulates it.
|
|
2650
|
-
_ = glasses.voice.onPhrase("hey notes") { [weak self] in
|
|
2651
|
-
await self?.session?.wake()
|
|
2673
|
+
_ = glasses.voice.onPhrase(phrase: "hey notes") { [weak self] in
|
|
2674
|
+
try? await self?.session?.wake()
|
|
2652
2675
|
}
|
|
2653
2676
|
}
|
|
2654
2677
|
}`,
|
|
@@ -3024,12 +3047,95 @@ class NotesDisplayHandler(
|
|
|
3024
3047
|
}
|
|
3025
3048
|
}
|
|
3026
3049
|
}`,
|
|
3027
|
-
swift: `//
|
|
3028
|
-
//
|
|
3029
|
-
//
|
|
3030
|
-
//
|
|
3031
|
-
//
|
|
3032
|
-
|
|
3050
|
+
swift: `// Two-view display navigation — browse ⇄ detail — same state machine as
|
|
3051
|
+
// the Kotlin side. iOS notes: the builder is closure-based (flexBox is the
|
|
3052
|
+
// container; no column/row sugar), and tappable ids AUTO-ASSIGN (no id:
|
|
3053
|
+
// parameter) — read them back via getDisplayState.interactiveIds when
|
|
3054
|
+
// driving from an agent.
|
|
3055
|
+
|
|
3056
|
+
import GlassesCore
|
|
3057
|
+
|
|
3058
|
+
struct Note { let id: Int64; let title: String; let body: String }
|
|
3059
|
+
|
|
3060
|
+
final class NotesDisplayHandler: @unchecked Sendable {
|
|
3061
|
+
private let glasses: any ExtentosGlasses
|
|
3062
|
+
private let notes: @Sendable () -> [Note] // app-internal source of truth
|
|
3063
|
+
private var session: (any AssistantSession)?
|
|
3064
|
+
|
|
3065
|
+
init(glasses: any ExtentosGlasses, notes: @escaping @Sendable () -> [Note]) {
|
|
3066
|
+
self.glasses = glasses
|
|
3067
|
+
self.notes = notes
|
|
3068
|
+
}
|
|
3069
|
+
|
|
3070
|
+
func start() async throws {
|
|
3071
|
+
session = try await glasses.assistant.start(
|
|
3072
|
+
provider: .openAI() // model + voice from your dashboard
|
|
3073
|
+
) { config in
|
|
3074
|
+
config.instructions =
|
|
3075
|
+
"You can use the glasses display. Call show_notes for the browsable " +
|
|
3076
|
+
"list (also to go back to it); clear_display to wipe the screen. If a " +
|
|
3077
|
+
"tool says there is no display, say so and offer to read aloud instead."
|
|
3078
|
+
|
|
3079
|
+
config.tool("show_notes", description: "Show the browsable list of the user's notes on the glasses display. Also call to go back to the list from an open note.") {
|
|
3080
|
+
guard self.glasses.display.isAvailable else {
|
|
3081
|
+
return .err("These glasses have no display. Offer to read the notes aloud instead.")
|
|
3082
|
+
}
|
|
3083
|
+
await self.showBrowse()
|
|
3084
|
+
return .ok("Notes are on the display — slide between them, pinch one to open it.")
|
|
3085
|
+
}
|
|
3086
|
+
|
|
3087
|
+
config.tool("clear_display", description: "Clear the glasses display when the user asks to hide or dismiss it.") {
|
|
3088
|
+
await self.glasses.display.clear()
|
|
3089
|
+
return .ok("Display cleared.")
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
3092
|
+
// Wake mechanism — same onPhrase wiring as every Phase 4 assistant.
|
|
3093
|
+
_ = glasses.voice.onPhrase(phrase: "hey notes") { [weak self] in
|
|
3094
|
+
try? await self?.session?.wake()
|
|
3095
|
+
}
|
|
3096
|
+
}
|
|
3097
|
+
|
|
3098
|
+
/// BROWSE — every note is a pinchable CARD container (ids auto-assign on iOS).
|
|
3099
|
+
private func showBrowse() async {
|
|
3100
|
+
let all = notes()
|
|
3101
|
+
// Mid-pinch on the root view dismisses the display.
|
|
3102
|
+
await glasses.display.show(onBack: { Task { await self.glasses.display.clear() } }) { root in
|
|
3103
|
+
root.flexBox(direction: .column, gap: 6, padding: EdgeInsets(top: 10, right: 10, bottom: 10, left: 10)) { col in
|
|
3104
|
+
col.text("My notes", style: .heading)
|
|
3105
|
+
for note in all.prefix(5) {
|
|
3106
|
+
col.flexBox(
|
|
3107
|
+
direction: .column,
|
|
3108
|
+
gap: 2,
|
|
3109
|
+
padding: EdgeInsets(top: 8, right: 8, bottom: 8, left: 8),
|
|
3110
|
+
background: .card,
|
|
3111
|
+
onClick: { Task { await self.showDetail(note) } }
|
|
3112
|
+
) { card in
|
|
3113
|
+
card.text(note.title, style: .body)
|
|
3114
|
+
card.text(String(note.body.prefix(40)), style: .caption, color: .secondary)
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
3117
|
+
if all.count > 5 {
|
|
3118
|
+
col.text("+\\(all.count - 5) more — ask me to open one", style: .caption, color: .secondary)
|
|
3119
|
+
}
|
|
3120
|
+
}
|
|
3121
|
+
}
|
|
3122
|
+
}
|
|
3123
|
+
|
|
3124
|
+
/// DETAIL — one note full-screen; mid-pinch (onBack) or the button goes back.
|
|
3125
|
+
private func showDetail(_ note: Note) async {
|
|
3126
|
+
await glasses.display.show(onBack: { Task { await self.showBrowse() } }) { root in
|
|
3127
|
+
root.flexBox(direction: .column, gap: 8, padding: EdgeInsets(top: 12, right: 12, bottom: 12, left: 12)) { col in
|
|
3128
|
+
col.text(note.title, style: .heading)
|
|
3129
|
+
col.text(note.body, style: .body)
|
|
3130
|
+
// The explicit button pairs with the mid-pinch (onBack above) —
|
|
3131
|
+
// same transition, discoverable on screen.
|
|
3132
|
+
col.button("Back to notes", style: .outline) {
|
|
3133
|
+
Task { await self.showBrowse() }
|
|
3134
|
+
}
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
3137
|
+
}
|
|
3138
|
+
}`,
|
|
3033
3139
|
},
|
|
3034
3140
|
explanation: `THE AGENT-SIDE VERIFICATION LOOP — run from the same MCP session
|
|
3035
3141
|
|
|
@@ -3085,7 +3191,7 @@ VERIFICATION NOTES
|
|
|
3085
3191
|
"**Gate on `isAvailable`, never the model name** — and return the reason in the tool Err (\"These glasses have no display...\") so the model explains it accurately instead of improvising. The gate flips LIVE when the sim device changes; the same running session can see true then false.",
|
|
3086
3192
|
"**`show {}` replaces the whole display** — own the view state app-side (browse vs detail) and re-render complete views on every transition. There are no incremental updates.",
|
|
3087
3193
|
"**Register `onBack` on EVERY show — back is view-contextual.** Detail's onBack re-renders browse; browse's onBack clears the display; voice 'go back' asks wire to the same transition (show_notes). A show without onBack ignores the gesture, and clear() drops the current handlers so a stale onBack can't fire later. Sim-verified; the real-hardware mid-pinch wiring lands with the DAT display validation pass.",
|
|
3088
|
-
"**Give every clickable node a stable id** — buttons via `id = \"back-to-notes\"`, cards via `column(onClick = ..., id = \"note-\" + note.id)`. Without one, containers fall back to positional box-N ids that shift on reorder, coupling agents/tests to render order instead of identity.",
|
|
3194
|
+
"**Give every clickable node a stable id (Android)** — buttons via `id = \"back-to-notes\"`, cards via `column(onClick = ..., id = \"note-\" + note.id)`. Without one, containers fall back to positional box-N ids that shift on reorder, coupling agents/tests to render order instead of identity. iOS has no `id:` parameter yet — ids always auto-assign; read them back via getDisplayState.interactiveIds.",
|
|
3089
3195
|
"**onClick is a plain () -> Unit** — launch a coroutine inside it for the suspend show()/clear() calls.",
|
|
3090
3196
|
"**A fresh sim session defaults to rayban_meta (no display)** — setSimDevice('rayban_display') before driving any display flow, or every show is a silent no-op and getDisplayState stays empty.",
|
|
3091
3197
|
],
|
|
@@ -3141,13 +3247,19 @@ actor SceneScanner {
|
|
|
3141
3247
|
|
|
3142
3248
|
func start() {
|
|
3143
3249
|
task = Task { [glasses, detector] in
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3250
|
+
// videoFrames is a THROWING stream — CameraStreamPaused if
|
|
3251
|
+
// started while the wearer has paused the camera (temple tap).
|
|
3252
|
+
do {
|
|
3253
|
+
for try await frame in glasses.camera.videoFrames(
|
|
3254
|
+
config: VideoFrameConfig(resolution: .low, frameRate: 2)
|
|
3255
|
+
) {
|
|
3256
|
+
// frame.buffer / frame.width / frame.height / frame.presentationTimeUs
|
|
3257
|
+
if let label = detector.classify(frame) {
|
|
3258
|
+
_ = await glasses.audio.speak("I see a " + label)
|
|
3259
|
+
}
|
|
3150
3260
|
}
|
|
3261
|
+
} catch {
|
|
3262
|
+
// stream refused to start (camera paused) — prompt the wearer
|
|
3151
3263
|
}
|
|
3152
3264
|
}
|
|
3153
3265
|
}
|
|
@@ -3225,9 +3337,54 @@ class GalleryDisplay(
|
|
|
3225
3337
|
showList()
|
|
3226
3338
|
}
|
|
3227
3339
|
}`,
|
|
3228
|
-
swift: `// iOS DisplayClient
|
|
3229
|
-
//
|
|
3230
|
-
//
|
|
3340
|
+
swift: `// iOS DisplayClient note: the list ⇄ detail navigation below works today
|
|
3341
|
+
// (URL-based media). The LOCAL-media roots — image(photo:) / video(clip:)
|
|
3342
|
+
// auto-hosting + forgetHostedImage/-Video — are still Android-only (land
|
|
3343
|
+
// with D5b), so the detail view renders an already-hosted URL; keep
|
|
3344
|
+
// freshly-captured photos on the phone UI until the hosting port lands.
|
|
3345
|
+
|
|
3346
|
+
import GlassesCore
|
|
3347
|
+
|
|
3348
|
+
struct SavedPhoto { let id: Int64; let label: String; let hostedUrl: String }
|
|
3349
|
+
|
|
3350
|
+
final class GalleryDisplay: @unchecked Sendable {
|
|
3351
|
+
private let glasses: any ExtentosGlasses
|
|
3352
|
+
private let store: PhotoStore // YOUR persisted gallery
|
|
3353
|
+
|
|
3354
|
+
init(glasses: any ExtentosGlasses, store: PhotoStore) {
|
|
3355
|
+
self.glasses = glasses
|
|
3356
|
+
self.store = store
|
|
3357
|
+
}
|
|
3358
|
+
|
|
3359
|
+
// Root view: one card per saved photo. Display is per-DEVICE — gate on isAvailable.
|
|
3360
|
+
func showList() async {
|
|
3361
|
+
guard glasses.display.isAvailable else { return }
|
|
3362
|
+
let items = store.all().prefix(5)
|
|
3363
|
+
await glasses.display.show(onBack: { Task { await self.glasses.display.clear() } }) { root in
|
|
3364
|
+
root.flexBox(direction: .column, gap: 8, padding: EdgeInsets(top: 12, right: 12, bottom: 12, left: 12)) { col in
|
|
3365
|
+
col.text("Photos (\\(self.store.all().count))", style: .heading)
|
|
3366
|
+
for p in items {
|
|
3367
|
+
// Tappable card — ids auto-assign on iOS (no id: parameter);
|
|
3368
|
+
// read them back via getDisplayState.interactiveIds.
|
|
3369
|
+
col.flexBox(
|
|
3370
|
+
direction: .column,
|
|
3371
|
+
background: .card,
|
|
3372
|
+
onClick: { Task { await self.showDetail(p) } }
|
|
3373
|
+
) { card in
|
|
3374
|
+
card.text(p.label, style: .body)
|
|
3375
|
+
}
|
|
3376
|
+
}
|
|
3377
|
+
}
|
|
3378
|
+
}
|
|
3379
|
+
}
|
|
3380
|
+
|
|
3381
|
+
// Detail view: the hosted photo full-surface; back returns to the list.
|
|
3382
|
+
private func showDetail(_ p: SavedPhoto) async {
|
|
3383
|
+
await glasses.display.show(onBack: { Task { await self.showList() } }) { root in
|
|
3384
|
+
root.image(url: p.hostedUrl) // glasses fetch http(s) themselves
|
|
3385
|
+
}
|
|
3386
|
+
}
|
|
3387
|
+
}`,
|
|
3231
3388
|
},
|
|
3232
3389
|
explanation: "No assistant, no LLM — just capturePhoto + your store + the display DSL. show {} replaces the entire surface each call, so re-render the whole view on every transition and own your nav state app-side (here: list vs detail). Each show registers its own onBack: the detail view's onBack re-renders the list; the root's clears. image(photo) / video(clip) auto-host the local capture at show() time (near-instant for a photo, a few seconds for a clip) — call forgetHostedImage / forgetHostedVideo when the user deletes the item so the hosted copy is torn down.",
|
|
3233
3390
|
gotchas: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codeExamples.js","sourceRoot":"","sources":["../../../src/tools/data/codeExamples.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,sEAAsE;AACtE,sEAAsE;AACtE,uDAAuD;AACvD,sCAAsC;AACtC,EAAE;AACF,qEAAqE;AACrE,uDAAuD;AACvD,wEAAwE;AACxE,kEAAkE;AAClE,oEAAoE;AACpE,2DAA2D;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAuE5C,MAAM,kBAAkB,GAAgB;IACtC,OAAO,EAAE,oBAAoB;IAC7B,KAAK,EAAE,yFAAyF;IAChG,WAAW,EACT,0zBAA0zB;IAC5zB,IAAI,EAAE;QACJ,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwEV;QACE,KAAK,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgET;KACC;IACD,WAAW,EACT,ggCAAggC;IAClgC,OAAO,EAAE;QACP,yXAAyX;QACzX,gbAAgb;QAChb,qXAAqX;QACrX,mSAAmS;QACnS,oSAAoS;QACpS,+SAA+S;QAC/S,msBAAmsB;QACnsB,sIAAsI;QACtI,+HAA+H;QAC/H,yKAAyK;QACzK,kyBAAkyB;QAClyB,0UAA0U;KAC3U;IACD,eAAe,EAAE,CAAC,eAAe,EAAE,2BAA2B,EAAE,cAAc,CAAC;CAChF,CAAC;AAEF,MAAM,cAAc,GAAgB;IAClC,OAAO,EAAE,gBAAgB;IACzB,KAAK,EAAE,gDAAgD;IACvD,WAAW,EACT,2bAA2b;IAC7b,IAAI,EAAE;QACJ,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BV;QACE,KAAK,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgCT;KACC;IACD,WAAW,EACT,+ZAA+Z;IACja,OAAO,EAAE;QACP,8IAA8I;QAC9I,6PAA6P;QAC7P,kLAAkL;KACnL;IACD,eAAe,EAAE,CAAC,2BAA2B,CAAC;CAC/C,CAAC;AAEF,MAAM,oBAAoB,GAAgB;IACxC,OAAO,EAAE,sBAAsB;IAC/B,KAAK,EAAE,gDAAgD;IACvD,WAAW,EACT,gfAAgf;IAClf,IAAI,EAAE;QACJ,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6DV;QACE,KAAK,EAAE
|
|
1
|
+
{"version":3,"file":"codeExamples.js","sourceRoot":"","sources":["../../../src/tools/data/codeExamples.ts"],"names":[],"mappings":"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"}
|
|
@@ -31,7 +31,7 @@ export const VERSION_INFO = {
|
|
|
31
31
|
// block (1.4.0-phase4-dogfood via mavenLocal) is retired — pre-release
|
|
32
32
|
// handling in generateConnectionModule / validateIntegration keys on the
|
|
33
33
|
// version-string suffix, not on a field here.
|
|
34
|
-
latestStable: "1.
|
|
34
|
+
latestStable: "1.7.0",
|
|
35
35
|
specVersion: "1.0",
|
|
36
36
|
android: {
|
|
37
37
|
minimumSdk: 31,
|
|
@@ -74,8 +74,8 @@ export const VERSION_INFO = {
|
|
|
74
74
|
datSdkVersion: DAT_SDK_VERSION,
|
|
75
75
|
artifacts: {
|
|
76
76
|
android: {
|
|
77
|
-
core: "com.extentos:glasses:1.
|
|
78
|
-
ui: "com.extentos:glasses-ui:1.
|
|
77
|
+
core: "com.extentos:glasses:1.7.0",
|
|
78
|
+
ui: "com.extentos:glasses-ui:1.7.0",
|
|
79
79
|
// glasses-debug is NOT yet a real Android module. iOS has a `GlassesDebug`
|
|
80
80
|
// product in the Swift package (see ios.products below), but the Android
|
|
81
81
|
// equivalent was never scaffolded into `android-library/settings.gradle.kts`
|
|
@@ -94,9 +94,9 @@ export const VERSION_INFO = {
|
|
|
94
94
|
// surface an explicit unpublished sentinel rather than a stale literal
|
|
95
95
|
// version — a misleading "1.1.36-pair" made getPlatformInfo.artifacts.ios
|
|
96
96
|
// look resolvable when no such release exists.
|
|
97
|
-
version: "
|
|
98
|
-
published:
|
|
99
|
-
versionNote: "
|
|
97
|
+
version: "1.7.0",
|
|
98
|
+
published: true,
|
|
99
|
+
versionNote: "Published: add the Swift package via https://github.com/extentos/swift-glasses at exact version 1.7.0 (version-locked with com.extentos:glasses on Android). The binary xcframework downloads automatically via SPM checksum verification.",
|
|
100
100
|
products: ["GlassesCore", "GlassesUI", "GlassesDebug", "GlassesLifecycle", "GlassesTesting"],
|
|
101
101
|
},
|
|
102
102
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/tools/data/version.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,0EAA0E;AAC1E,uEAAuE;AACvE,qEAAqE;AACrE,oEAAoE;AACpE,qEAAqE;AACrE,2DAA2D;AAC3D,EAAE;AACF,2EAA2E;AAC3E,wEAAwE;AACxE,uEAAuE;AACvE,+EAA+E;AAC/E,wEAAwE;AACxE,0EAA0E;AAC1E,yEAAyE;AACzE,4EAA4E;AAC5E,sCAAsC;AACtC,+EAA+E;AAC/E,4EAA4E;AAC5E,qEAAqE;AACrE,yEAAyE;AACzE,wEAAwE;AACxE,iDAAiD;AACjD,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,OAAO,EAAE,OAAO;IAChB,GAAG,EAAE,OAAO;CACJ,CAAC;AAEX,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,0EAA0E;IAC1E,0EAA0E;IAC1E,uEAAuE;IACvE,yEAAyE;IACzE,8CAA8C;IAC9C,YAAY,EAAE,OAAO;IACrB,WAAW,EAAE,KAAK;IAClB,OAAO,EAAE;QACP,UAAU,EAAE,EAAE;QACd,yEAAyE;QACzE,wEAAwE;QACxE,qEAAqE;QACrE,kEAAkE;QAClE,yFAAyF;QACzF,oEAAoE;QACpE,gEAAgE;QAChE,UAAU,EAAE,EAAE;QACd,SAAS,EAAE,EAAE;QACb,aAAa,EACX,wPAAwP;QAC1P,0EAA0E;QAC1E,uEAAuE;QACvE,4EAA4E;QAC5E,yEAAyE;QACzE,uDAAuD;QACvD,aAAa,EAAE,QAAQ;QACvB,wEAAwE;QACxE,oCAAoC;QACpC,qEAAqE;QACrE,iDAAiD;QACjD,gEAAgE;QAChE,8EAA8E;QAC9E,2EAA2E;QAC3E,qDAAqD;QACrD,iBAAiB,EAAE,OAAO;QAC1B,oBAAoB,EAAE,KAAK;KAC5B;IACD,GAAG,EAAE;QACH,uBAAuB,EAAE,MAAM;QAC/B,YAAY,EAAE,KAAK;QACnB,wEAAwE;QACxE,uEAAuE;QACvE,wEAAwE;QACxE,+DAA+D;QAC/D,mBAAmB,EAAE,MAAM;KAC5B;IACD,aAAa,EAAE,eAAe;IAC9B,SAAS,EAAE;QACT,OAAO,EAAE;YACP,IAAI,EAAE,4BAA4B;YAClC,EAAE,EAAE,+BAA+B;YACnC,2EAA2E;YAC3E,yEAAyE;YACzE,6EAA6E;YAC7E,0EAA0E;YAC1E,4EAA4E;YAC5E,uEAAuE;YACvE,wEAAwE;YACxE,2EAA2E;YAC3E,uEAAuE;SACxE;QACD,GAAG,EAAE;YACH,OAAO,EAAE,2CAA2C;YACpD,iEAAiE;YACjE,qEAAqE;YACrE,sEAAsE;YACtE,uEAAuE;YACvE,0EAA0E;YAC1E,+CAA+C;YAC/C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/tools/data/version.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,0EAA0E;AAC1E,uEAAuE;AACvE,qEAAqE;AACrE,oEAAoE;AACpE,qEAAqE;AACrE,2DAA2D;AAC3D,EAAE;AACF,2EAA2E;AAC3E,wEAAwE;AACxE,uEAAuE;AACvE,+EAA+E;AAC/E,wEAAwE;AACxE,0EAA0E;AAC1E,yEAAyE;AACzE,4EAA4E;AAC5E,sCAAsC;AACtC,+EAA+E;AAC/E,4EAA4E;AAC5E,qEAAqE;AACrE,yEAAyE;AACzE,wEAAwE;AACxE,iDAAiD;AACjD,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,OAAO,EAAE,OAAO;IAChB,GAAG,EAAE,OAAO;CACJ,CAAC;AAEX,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,0EAA0E;IAC1E,0EAA0E;IAC1E,uEAAuE;IACvE,yEAAyE;IACzE,8CAA8C;IAC9C,YAAY,EAAE,OAAO;IACrB,WAAW,EAAE,KAAK;IAClB,OAAO,EAAE;QACP,UAAU,EAAE,EAAE;QACd,yEAAyE;QACzE,wEAAwE;QACxE,qEAAqE;QACrE,kEAAkE;QAClE,yFAAyF;QACzF,oEAAoE;QACpE,gEAAgE;QAChE,UAAU,EAAE,EAAE;QACd,SAAS,EAAE,EAAE;QACb,aAAa,EACX,wPAAwP;QAC1P,0EAA0E;QAC1E,uEAAuE;QACvE,4EAA4E;QAC5E,yEAAyE;QACzE,uDAAuD;QACvD,aAAa,EAAE,QAAQ;QACvB,wEAAwE;QACxE,oCAAoC;QACpC,qEAAqE;QACrE,iDAAiD;QACjD,gEAAgE;QAChE,8EAA8E;QAC9E,2EAA2E;QAC3E,qDAAqD;QACrD,iBAAiB,EAAE,OAAO;QAC1B,oBAAoB,EAAE,KAAK;KAC5B;IACD,GAAG,EAAE;QACH,uBAAuB,EAAE,MAAM;QAC/B,YAAY,EAAE,KAAK;QACnB,wEAAwE;QACxE,uEAAuE;QACvE,wEAAwE;QACxE,+DAA+D;QAC/D,mBAAmB,EAAE,MAAM;KAC5B;IACD,aAAa,EAAE,eAAe;IAC9B,SAAS,EAAE;QACT,OAAO,EAAE;YACP,IAAI,EAAE,4BAA4B;YAClC,EAAE,EAAE,+BAA+B;YACnC,2EAA2E;YAC3E,yEAAyE;YACzE,6EAA6E;YAC7E,0EAA0E;YAC1E,4EAA4E;YAC5E,uEAAuE;YACvE,wEAAwE;YACxE,2EAA2E;YAC3E,uEAAuE;SACxE;QACD,GAAG,EAAE;YACH,OAAO,EAAE,2CAA2C;YACpD,iEAAiE;YACjE,qEAAqE;YACrE,sEAAsE;YACtE,uEAAuE;YACvE,0EAA0E;YAC1E,+CAA+C;YAC/C,OAAO,EAAE,OAAO;YAChB,SAAS,EAAE,IAAI;YACf,WAAW,EACT,4OAA4O;YAC9O,QAAQ,EAAE,CAAC,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,kBAAkB,EAAE,gBAAgB,CAAC;SAC7F;KACF;CACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/tools/definitions.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IAMpB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,oBAAoB,EAAE,KAAK,CAAC;KAC7B,CAAC;CACH;AAMD,eAAO,MAAM,eAAe,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/tools/definitions.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IAMpB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,oBAAoB,EAAE,KAAK,CAAC;KAC7B,CAAC;CACH;AAMD,eAAO,MAAM,eAAe,EAAE,OAAO,EA89BpC,CAAC;AAEF,eAAO,MAAM,SAAS,QAAyB,CAAC;AAShD,wBAAgB,iCAAiC,CAC/C,IAAI,GAAE,SAAS,OAAO,EAAoB,GACzC,IAAI,CAiBN"}
|