@agentdeck/bridge 0.2.1 → 0.2.3
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/assets/fonts/IBMPlexSans-Bold.ttf +0 -0
- package/assets/fonts/IBMPlexSans-Regular.ttf +0 -0
- package/assets/fonts/JetBrainsMono-Bold.ttf +0 -0
- package/assets/fonts/JetBrainsMono-Regular.ttf +0 -0
- package/assets/fonts/LICENSES.md +22 -0
- package/dist/adapters/claude-code.d.ts +6 -0
- package/dist/adapters/claude-code.d.ts.map +1 -1
- package/dist/adapters/claude-code.js +8 -0
- package/dist/adapters/claude-code.js.map +1 -1
- package/dist/adapters/openclaw.d.ts +24 -0
- package/dist/adapters/openclaw.d.ts.map +1 -1
- package/dist/adapters/openclaw.js +291 -35
- package/dist/adapters/openclaw.js.map +1 -1
- package/dist/adapters/opencode-adapter.d.ts +59 -0
- package/dist/adapters/opencode-adapter.d.ts.map +1 -1
- package/dist/adapters/opencode-adapter.js +297 -35
- package/dist/adapters/opencode-adapter.js.map +1 -1
- package/dist/adb-reverse.d.ts +1 -1
- package/dist/adb-reverse.js +1 -1
- package/dist/antigravity-local.d.ts +1 -0
- package/dist/antigravity-local.d.ts.map +1 -1
- package/dist/antigravity-local.js +33 -0
- package/dist/antigravity-local.js.map +1 -1
- package/dist/apme/adapters/claude-hook.d.ts.map +1 -1
- package/dist/apme/adapters/claude-hook.js +5 -0
- package/dist/apme/adapters/claude-hook.js.map +1 -1
- package/dist/apme/adapters/codex-hook.d.ts +17 -0
- package/dist/apme/adapters/codex-hook.d.ts.map +1 -0
- package/dist/apme/adapters/codex-hook.js +95 -0
- package/dist/apme/adapters/codex-hook.js.map +1 -0
- package/dist/apme/adapters/codex-turn-manager.d.ts +86 -0
- package/dist/apme/adapters/codex-turn-manager.d.ts.map +1 -0
- package/dist/apme/adapters/codex-turn-manager.js +496 -0
- package/dist/apme/adapters/codex-turn-manager.js.map +1 -0
- package/dist/apme/adapters/openclaw-hook.d.ts +99 -0
- package/dist/apme/adapters/openclaw-hook.d.ts.map +1 -0
- package/dist/apme/adapters/openclaw-hook.js +234 -0
- package/dist/apme/adapters/openclaw-hook.js.map +1 -0
- package/dist/apme/adapters/opencode-hook.d.ts +56 -0
- package/dist/apme/adapters/opencode-hook.d.ts.map +1 -0
- package/dist/apme/adapters/opencode-hook.js +182 -0
- package/dist/apme/adapters/opencode-hook.js.map +1 -0
- package/dist/apme/adapters/timeline.d.ts.map +1 -1
- package/dist/apme/adapters/timeline.js +6 -1
- package/dist/apme/adapters/timeline.js.map +1 -1
- package/dist/apme/antigravity-transcript.d.ts +18 -0
- package/dist/apme/antigravity-transcript.d.ts.map +1 -0
- package/dist/apme/antigravity-transcript.js +94 -0
- package/dist/apme/antigravity-transcript.js.map +1 -0
- package/dist/apme/classify-turn.d.ts +13 -0
- package/dist/apme/classify-turn.d.ts.map +1 -0
- package/dist/apme/classify-turn.js +49 -0
- package/dist/apme/classify-turn.js.map +1 -0
- package/dist/apme/claude-transcript-reader.d.ts +10 -0
- package/dist/apme/claude-transcript-reader.d.ts.map +1 -1
- package/dist/apme/claude-transcript-reader.js +35 -0
- package/dist/apme/claude-transcript-reader.js.map +1 -1
- package/dist/apme/collector.d.ts +129 -6
- package/dist/apme/collector.d.ts.map +1 -1
- package/dist/apme/collector.js +470 -23
- package/dist/apme/collector.js.map +1 -1
- package/dist/apme/dashboard-html.d.ts.map +1 -1
- package/dist/apme/dashboard-html.js +87 -11
- package/dist/apme/dashboard-html.js.map +1 -1
- package/dist/apme/http.d.ts.map +1 -1
- package/dist/apme/http.js +43 -6
- package/dist/apme/http.js.map +1 -1
- package/dist/apme/index.d.ts +26 -5
- package/dist/apme/index.d.ts.map +1 -1
- package/dist/apme/index.js +135 -9
- package/dist/apme/index.js.map +1 -1
- package/dist/apme/pareto.d.ts +39 -0
- package/dist/apme/pareto.d.ts.map +1 -0
- package/dist/apme/pareto.js +59 -0
- package/dist/apme/pareto.js.map +1 -0
- package/dist/apme/recommend.d.ts +3 -0
- package/dist/apme/recommend.d.ts.map +1 -1
- package/dist/apme/recommend.js +43 -1
- package/dist/apme/recommend.js.map +1 -1
- package/dist/apme/runner.d.ts +92 -4
- package/dist/apme/runner.d.ts.map +1 -1
- package/dist/apme/runner.js +586 -70
- package/dist/apme/runner.js.map +1 -1
- package/dist/apme/sample-to-timeline.d.ts +26 -0
- package/dist/apme/sample-to-timeline.d.ts.map +1 -0
- package/dist/apme/sample-to-timeline.js +95 -0
- package/dist/apme/sample-to-timeline.js.map +1 -0
- package/dist/apme/scorers/index.d.ts +47 -0
- package/dist/apme/scorers/index.d.ts.map +1 -0
- package/dist/apme/scorers/index.js +96 -0
- package/dist/apme/scorers/index.js.map +1 -0
- package/dist/apme/settings.d.ts +14 -10
- package/dist/apme/settings.d.ts.map +1 -1
- package/dist/apme/settings.js +34 -8
- package/dist/apme/settings.js.map +1 -1
- package/dist/apme/store.d.ts +33 -1
- package/dist/apme/store.d.ts.map +1 -1
- package/dist/apme/store.js +334 -25
- package/dist/apme/store.js.map +1 -1
- package/dist/awaiting-overlay.d.ts +99 -0
- package/dist/awaiting-overlay.d.ts.map +1 -0
- package/dist/awaiting-overlay.js +148 -0
- package/dist/awaiting-overlay.js.map +1 -0
- package/dist/ble-sync-spawn.d.ts +63 -0
- package/dist/ble-sync-spawn.d.ts.map +1 -0
- package/dist/ble-sync-spawn.js +196 -0
- package/dist/ble-sync-spawn.js.map +1 -0
- package/dist/bridge-core.d.ts +24 -1
- package/dist/bridge-core.d.ts.map +1 -1
- package/dist/bridge-core.js +157 -24
- package/dist/bridge-core.js.map +1 -1
- package/dist/broadcast.d.ts +3 -0
- package/dist/broadcast.d.ts.map +1 -0
- package/dist/broadcast.js +122 -0
- package/dist/broadcast.js.map +1 -0
- package/dist/check-deps.d.ts.map +1 -1
- package/dist/check-deps.js +25 -9
- package/dist/check-deps.js.map +1 -1
- package/dist/cli.d.ts +15 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1025 -94
- package/dist/cli.js.map +1 -1
- package/dist/codex-auth.d.ts +21 -0
- package/dist/codex-auth.d.ts.map +1 -1
- package/dist/codex-auth.js +52 -1
- package/dist/codex-auth.js.map +1 -1
- package/dist/codex-output-parser.d.ts +8 -0
- package/dist/codex-output-parser.d.ts.map +1 -1
- package/dist/codex-output-parser.js +110 -25
- package/dist/codex-output-parser.js.map +1 -1
- package/dist/codex-rate-limits.d.ts +16 -0
- package/dist/codex-rate-limits.d.ts.map +1 -0
- package/dist/codex-rate-limits.js +197 -0
- package/dist/codex-rate-limits.js.map +1 -0
- package/dist/codex-rollout-response.d.ts +31 -0
- package/dist/codex-rollout-response.d.ts.map +1 -0
- package/dist/codex-rollout-response.js +135 -0
- package/dist/codex-rollout-response.js.map +1 -0
- package/dist/daemon-server.d.ts +85 -0
- package/dist/daemon-server.d.ts.map +1 -1
- package/dist/daemon-server.js +1627 -159
- package/dist/daemon-server.js.map +1 -1
- package/dist/daemon.js +15 -6
- package/dist/daemon.js.map +1 -1
- package/dist/display-dim.d.ts +9 -0
- package/dist/display-dim.d.ts.map +1 -0
- package/dist/display-dim.js +53 -0
- package/dist/display-dim.js.map +1 -0
- package/dist/display-monitor.d.ts +15 -2
- package/dist/display-monitor.d.ts.map +1 -1
- package/dist/display-monitor.js +104 -26
- package/dist/display-monitor.js.map +1 -1
- package/dist/esp32-serial.d.ts +160 -1
- package/dist/esp32-serial.d.ts.map +1 -1
- package/dist/esp32-serial.js +950 -153
- package/dist/esp32-serial.js.map +1 -1
- package/dist/fallback-task-timeline.d.ts +42 -0
- package/dist/fallback-task-timeline.d.ts.map +1 -0
- package/dist/fallback-task-timeline.js +112 -0
- package/dist/fallback-task-timeline.js.map +1 -0
- package/dist/foundation-models-helper.d.ts +11 -0
- package/dist/foundation-models-helper.d.ts.map +1 -0
- package/dist/foundation-models-helper.js +241 -0
- package/dist/foundation-models-helper.js.map +1 -0
- package/dist/hook-migration.js +1 -1
- package/dist/hook-migration.js.map +1 -1
- package/dist/hook-server.d.ts +2 -3
- package/dist/hook-server.d.ts.map +1 -1
- package/dist/hook-server.js +22 -10
- package/dist/hook-server.js.map +1 -1
- package/dist/idotmatrix/idotmatrix-daemon-sync.d.ts +33 -0
- package/dist/idotmatrix/idotmatrix-daemon-sync.d.ts.map +1 -0
- package/dist/idotmatrix/idotmatrix-daemon-sync.js +164 -0
- package/dist/idotmatrix/idotmatrix-daemon-sync.js.map +1 -0
- package/dist/idotmatrix/idotmatrix-discover.d.ts +18 -0
- package/dist/idotmatrix/idotmatrix-discover.d.ts.map +1 -0
- package/dist/idotmatrix/idotmatrix-discover.js +85 -0
- package/dist/idotmatrix/idotmatrix-discover.js.map +1 -0
- package/dist/idotmatrix/idotmatrix-settings.d.ts +20 -0
- package/dist/idotmatrix/idotmatrix-settings.d.ts.map +1 -0
- package/dist/idotmatrix/idotmatrix-settings.js +57 -0
- package/dist/idotmatrix/idotmatrix-settings.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +215 -179
- package/dist/index.js.map +1 -1
- package/dist/log-stream.d.ts +15 -16
- package/dist/log-stream.d.ts.map +1 -1
- package/dist/log-stream.js +18 -96
- package/dist/log-stream.js.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +12 -3
- package/dist/logger.js.map +1 -1
- package/dist/mdns.d.ts +17 -0
- package/dist/mdns.d.ts.map +1 -1
- package/dist/mdns.js +52 -18
- package/dist/mdns.js.map +1 -1
- package/dist/modules/adb-module.d.ts +1 -1
- package/dist/modules/adb-module.d.ts.map +1 -1
- package/dist/modules/adb-module.js +4 -3
- package/dist/modules/adb-module.js.map +1 -1
- package/dist/modules/broadcast-module.d.ts +17 -0
- package/dist/modules/broadcast-module.d.ts.map +1 -0
- package/dist/modules/broadcast-module.js +26 -0
- package/dist/modules/broadcast-module.js.map +1 -0
- package/dist/modules/idotmatrix-module.d.ts +9 -0
- package/dist/modules/idotmatrix-module.d.ts.map +1 -0
- package/dist/modules/idotmatrix-module.js +46 -0
- package/dist/modules/idotmatrix-module.js.map +1 -0
- package/dist/modules/index.d.ts +3 -1
- package/dist/modules/index.d.ts.map +1 -1
- package/dist/modules/index.js +9 -3
- package/dist/modules/index.js.map +1 -1
- package/dist/modules/pixoo-module.d.ts.map +1 -1
- package/dist/modules/pixoo-module.js +14 -4
- package/dist/modules/pixoo-module.js.map +1 -1
- package/dist/modules/serial-module.d.ts +4 -0
- package/dist/modules/serial-module.d.ts.map +1 -1
- package/dist/modules/serial-module.js +14 -12
- package/dist/modules/serial-module.js.map +1 -1
- package/dist/modules/timebox-module.d.ts +9 -0
- package/dist/modules/timebox-module.d.ts.map +1 -0
- package/dist/modules/timebox-module.js +46 -0
- package/dist/modules/timebox-module.js.map +1 -0
- package/dist/modules/types.d.ts +4 -2
- package/dist/modules/types.d.ts.map +1 -1
- package/dist/openclaw-session.d.ts +18 -0
- package/dist/openclaw-session.d.ts.map +1 -0
- package/dist/openclaw-session.js +34 -0
- package/dist/openclaw-session.js.map +1 -0
- package/dist/output-parser.d.ts +30 -0
- package/dist/output-parser.d.ts.map +1 -1
- package/dist/output-parser.js +125 -9
- package/dist/output-parser.js.map +1 -1
- package/dist/passive-observer.d.ts +26 -0
- package/dist/passive-observer.d.ts.map +1 -1
- package/dist/passive-observer.js +258 -49
- package/dist/passive-observer.js.map +1 -1
- package/dist/permission-resolver.d.ts +47 -0
- package/dist/permission-resolver.d.ts.map +1 -0
- package/dist/permission-resolver.js +103 -0
- package/dist/permission-resolver.js.map +1 -0
- package/dist/pixoo/micro-glyphs.d.ts +49 -0
- package/dist/pixoo/micro-glyphs.d.ts.map +1 -0
- package/dist/pixoo/micro-glyphs.js +276 -0
- package/dist/pixoo/micro-glyphs.js.map +1 -0
- package/dist/pixoo/pixoo-bridge.d.ts +2 -2
- package/dist/pixoo/pixoo-bridge.d.ts.map +1 -1
- package/dist/pixoo/pixoo-bridge.js +93 -25
- package/dist/pixoo/pixoo-bridge.js.map +1 -1
- package/dist/pixoo/pixoo-camera.d.ts +19 -3
- package/dist/pixoo/pixoo-camera.d.ts.map +1 -1
- package/dist/pixoo/pixoo-camera.js +62 -27
- package/dist/pixoo/pixoo-camera.js.map +1 -1
- package/dist/pixoo/pixoo-client.d.ts +13 -3
- package/dist/pixoo/pixoo-client.d.ts.map +1 -1
- package/dist/pixoo/pixoo-client.js +51 -22
- package/dist/pixoo/pixoo-client.js.map +1 -1
- package/dist/pixoo/pixoo-discover.d.ts +37 -0
- package/dist/pixoo/pixoo-discover.d.ts.map +1 -0
- package/dist/pixoo/pixoo-discover.js +105 -0
- package/dist/pixoo/pixoo-discover.js.map +1 -0
- package/dist/pixoo/pixoo-renderer.d.ts +8 -3
- package/dist/pixoo/pixoo-renderer.d.ts.map +1 -1
- package/dist/pixoo/pixoo-renderer.js +189 -60
- package/dist/pixoo/pixoo-renderer.js.map +1 -1
- package/dist/pixoo/pixoo-settings.d.ts +6 -0
- package/dist/pixoo/pixoo-settings.d.ts.map +1 -1
- package/dist/pixoo/pixoo-settings.js +9 -0
- package/dist/pixoo/pixoo-settings.js.map +1 -1
- package/dist/pixoo/pixoo-sprites.d.ts +60 -11
- package/dist/pixoo/pixoo-sprites.d.ts.map +1 -1
- package/dist/pixoo/pixoo-sprites.js +512 -209
- package/dist/pixoo/pixoo-sprites.js.map +1 -1
- package/dist/pty-manager.d.ts.map +1 -1
- package/dist/pty-manager.js +8 -2
- package/dist/pty-manager.js.map +1 -1
- package/dist/session-activity.d.ts +14 -0
- package/dist/session-activity.d.ts.map +1 -0
- package/dist/session-activity.js +160 -0
- package/dist/session-activity.js.map +1 -0
- package/dist/session-aggregator.d.ts +17 -0
- package/dist/session-aggregator.d.ts.map +1 -1
- package/dist/session-aggregator.js +48 -9
- package/dist/session-aggregator.js.map +1 -1
- package/dist/session-registry.d.ts +71 -3
- package/dist/session-registry.d.ts.map +1 -1
- package/dist/session-registry.js +137 -8
- package/dist/session-registry.js.map +1 -1
- package/dist/session-timeline-relay.d.ts.map +1 -1
- package/dist/session-timeline-relay.js +13 -4
- package/dist/session-timeline-relay.js.map +1 -1
- package/dist/session-transcript-timeline.d.ts +49 -0
- package/dist/session-transcript-timeline.d.ts.map +1 -0
- package/dist/session-transcript-timeline.js +276 -0
- package/dist/session-transcript-timeline.js.map +1 -0
- package/dist/state-machine.d.ts +6 -1
- package/dist/state-machine.d.ts.map +1 -1
- package/dist/state-machine.js +86 -28
- package/dist/state-machine.js.map +1 -1
- package/dist/timebox/timebox-daemon-sync.d.ts +19 -0
- package/dist/timebox/timebox-daemon-sync.d.ts.map +1 -0
- package/dist/timebox/timebox-daemon-sync.js +135 -0
- package/dist/timebox/timebox-daemon-sync.js.map +1 -0
- package/dist/timebox/timebox-discover.d.ts +19 -0
- package/dist/timebox/timebox-discover.d.ts.map +1 -0
- package/dist/timebox/timebox-discover.js +87 -0
- package/dist/timebox/timebox-discover.js.map +1 -0
- package/dist/timebox/timebox-settings.d.ts +32 -0
- package/dist/timebox/timebox-settings.d.ts.map +1 -0
- package/dist/timebox/timebox-settings.js +80 -0
- package/dist/timebox/timebox-settings.js.map +1 -0
- package/dist/timeline-store.d.ts +63 -3
- package/dist/timeline-store.d.ts.map +1 -1
- package/dist/timeline-store.js +292 -14
- package/dist/timeline-store.js.map +1 -1
- package/dist/timeline-summarizer.d.ts.map +1 -1
- package/dist/timeline-summarizer.js +29 -5
- package/dist/timeline-summarizer.js.map +1 -1
- package/dist/tui/ansi.d.ts +0 -4
- package/dist/tui/ansi.d.ts.map +1 -1
- package/dist/tui/ansi.js +14 -7
- package/dist/tui/ansi.js.map +1 -1
- package/dist/tui/dashboard.d.ts +1 -0
- package/dist/tui/dashboard.d.ts.map +1 -1
- package/dist/tui/dashboard.js +24 -7
- package/dist/tui/dashboard.js.map +1 -1
- package/dist/tui/renderer.d.ts +36 -0
- package/dist/tui/renderer.d.ts.map +1 -1
- package/dist/tui/renderer.js +303 -119
- package/dist/tui/renderer.js.map +1 -1
- package/dist/tui/terrarium.d.ts.map +1 -1
- package/dist/tui/terrarium.js +37 -49
- package/dist/tui/terrarium.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -2
- package/dist/types.js.map +1 -1
- package/dist/usage-api.d.ts.map +1 -1
- package/dist/usage-api.js +7 -1
- package/dist/usage-api.js.map +1 -1
- package/dist/usage-event.d.ts +10 -3
- package/dist/usage-event.d.ts.map +1 -1
- package/dist/usage-event.js +74 -12
- package/dist/usage-event.js.map +1 -1
- package/dist/utility-proxy.d.ts.map +1 -1
- package/dist/utility-proxy.js +8 -0
- package/dist/utility-proxy.js.map +1 -1
- package/dist/utils/project-name.d.ts +3 -0
- package/dist/utils/project-name.d.ts.map +1 -1
- package/dist/utils/project-name.js +44 -2
- package/dist/utils/project-name.js.map +1 -1
- package/dist/windows-service.d.ts +26 -0
- package/dist/windows-service.d.ts.map +1 -0
- package/dist/windows-service.js +145 -0
- package/dist/windows-service.js.map +1 -0
- package/dist/ws-server.d.ts +22 -1
- package/dist/ws-server.d.ts.map +1 -1
- package/dist/ws-server.js +89 -4
- package/dist/ws-server.js.map +1 -1
- package/fm-helper/AgentDeckFMHelper.swift +112 -0
- package/package.json +9 -3
- package/scripts/build-fm-helper.mjs +26 -0
- package/LICENSE +0 -21
- package/dist/apme/tuner.d.ts +0 -64
- package/dist/apme/tuner.d.ts.map +0 -1
- package/dist/apme/tuner.js +0 -297
- package/dist/apme/tuner.js.map +0 -1
- package/dist/d200h/hid-protocol.d.ts +0 -62
- package/dist/d200h/hid-protocol.d.ts.map +0 -1
- package/dist/d200h/hid-protocol.js +0 -124
- package/dist/d200h/hid-protocol.js.map +0 -1
- package/dist/d200h/image-renderer.d.ts +0 -36
- package/dist/d200h/image-renderer.d.ts.map +0 -1
- package/dist/d200h/image-renderer.js +0 -487
- package/dist/d200h/image-renderer.js.map +0 -1
- package/dist/modules/d200h-module.d.ts +0 -43
- package/dist/modules/d200h-module.d.ts.map +0 -1
- package/dist/modules/d200h-module.js +0 -360
- package/dist/modules/d200h-module.js.map +0 -1
- package/dist/modules/d200h-renderer.d.ts +0 -7
- package/dist/modules/d200h-renderer.d.ts.map +0 -1
- package/dist/modules/d200h-renderer.js +0 -321
- package/dist/modules/d200h-renderer.js.map +0 -1
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw Gateway event → TelemetrySpan adapter.
|
|
3
|
+
*
|
|
4
|
+
* OpenClaw is a chat-style remote agent reached over a WebSocket Gateway
|
|
5
|
+
* (`shared/src/gateway-protocol.ts`). Unlike Claude Code (Stop hook +
|
|
6
|
+
* PostToolUse TodoWrite) and Codex CLI (hook system), OpenClaw never emits a
|
|
7
|
+
* structured "task complete" signal — it streams `chat.delta` chunks during
|
|
8
|
+
* generation and a single `chat.final` per assistant turn. With nothing
|
|
9
|
+
* stronger to anchor a task to, OpenClaw previously fell back to
|
|
10
|
+
* `session_end` only, collapsing every chat session to a single APME task
|
|
11
|
+
* and defeating per-task evaluation.
|
|
12
|
+
*
|
|
13
|
+
* # Boundary signal: idle_gap (90 s)
|
|
14
|
+
*
|
|
15
|
+
* The chosen boundary is **idle_gap**: after `chat.final`, if the user
|
|
16
|
+
* doesn't send a new `chat.send` within 90 seconds, treat the conversation
|
|
17
|
+
* as one closed task. Rationale, derived from inspecting the chat-final /
|
|
18
|
+
* chat-delta fixture set (`tests/parity/gateway-frames/`) and the four
|
|
19
|
+
* scenario classes that ship in the audit plan:
|
|
20
|
+
*
|
|
21
|
+
* (a) Single Q/A → 1 final, no follow-up → idle_gap fires once.
|
|
22
|
+
* (b) Multi-turn collab → user keeps replying within 90 s → 1 task
|
|
23
|
+
* (collaboration stays together).
|
|
24
|
+
* (c) Long task w/ Qs → same as (b), user clarifications keep the
|
|
25
|
+
* idle timer reset until the agent fully closes
|
|
26
|
+
* the topic.
|
|
27
|
+
* (d) Abrupt new topic → if the pivot happens within 90 s of the
|
|
28
|
+
* previous final, this v1 will lump both into
|
|
29
|
+
* one task. Acceptable v1 limitation —
|
|
30
|
+
* user-driven `manual` boundary or longer
|
|
31
|
+
* silence between topics splits them. A future
|
|
32
|
+
* topic-shift embedder is the obvious next step.
|
|
33
|
+
*
|
|
34
|
+
* 90 s is conservative: long enough that genuine multi-turn debugging
|
|
35
|
+
* stays together, short enough that a real "I'm done, walking away"
|
|
36
|
+
* gesture closes the task within a normal coffee break. The threshold is
|
|
37
|
+
* exposed as `OPENCLAW_IDLE_GAP_MS` so a downstream consumer can override
|
|
38
|
+
* for a hot-research session if needed.
|
|
39
|
+
*
|
|
40
|
+
* # Alternative boundaries considered (rejected for v1)
|
|
41
|
+
*
|
|
42
|
+
* - `chat.final` per turn: too granular — every user/assistant turn pair
|
|
43
|
+
* would be its own task. Defeats the "what did the agent accomplish"
|
|
44
|
+
* framing — evaluation should span the work, not the words.
|
|
45
|
+
* - Embedding-based topic shift: cost-heavy + cold-start fragile. Not v1.
|
|
46
|
+
* - Gateway `taskCompleted` event: no such event in `GatewayEventPayload`
|
|
47
|
+
* union. Adding it requires the OpenClaw server to emit it, which the
|
|
48
|
+
* bridge can't unilaterally do.
|
|
49
|
+
*
|
|
50
|
+
* # Wiring
|
|
51
|
+
*
|
|
52
|
+
* `bridge/src/adapters/openclaw.ts` calls `openclawChatEventToSpans(ctx,
|
|
53
|
+
* payload)` from its `chat` event branch and forwards the resulting spans
|
|
54
|
+
* to `apme.collector.ingestSpan`. The idle timer is owned by the OpenClaw
|
|
55
|
+
* adapter (not this module) because it needs access to the active session
|
|
56
|
+
* id and an actual `setTimeout`. This module is pure — given a payload it
|
|
57
|
+
* returns the spans the adapter should currently emit, no side effects.
|
|
58
|
+
*/
|
|
59
|
+
import { randomUUID } from 'crypto';
|
|
60
|
+
import { spanNameForKind } from '@agentdeck/shared';
|
|
61
|
+
/** Default idle-gap threshold after `chat.final` before we close the task. */
|
|
62
|
+
export const OPENCLAW_IDLE_GAP_MS = 90_000;
|
|
63
|
+
/**
|
|
64
|
+
* Convert a Gateway `chat` event payload into the spans the APME collector
|
|
65
|
+
* should ingest right now. Does NOT emit the idle-gap `task_boundary` —
|
|
66
|
+
* that's owned by the adapter's timer (it needs setTimeout + per-session
|
|
67
|
+
* state). Callers should also fire `emitIdleGapTaskBoundary(...)` when the
|
|
68
|
+
* idle timer expires.
|
|
69
|
+
*/
|
|
70
|
+
export function openclawChatEventToSpans(ctx, payload) {
|
|
71
|
+
const ts = Date.now();
|
|
72
|
+
const baseAttrs = {
|
|
73
|
+
'agentdeck.agent_type': ctx.agentType,
|
|
74
|
+
...(ctx.cwd ? { 'agentdeck.cwd': ctx.cwd } : {}),
|
|
75
|
+
...(payload.runId ? { 'agentdeck.run_id': payload.runId } : {}),
|
|
76
|
+
...(payload.sessionKey ? { 'agentdeck.gateway_session_key': payload.sessionKey } : {}),
|
|
77
|
+
};
|
|
78
|
+
const make = (kind, attributes = {}) => ({
|
|
79
|
+
traceId: ctx.traceId,
|
|
80
|
+
spanId: randomUUID(),
|
|
81
|
+
parentSpanId: ctx.activeTurnId,
|
|
82
|
+
name: spanNameForKind(kind),
|
|
83
|
+
kind,
|
|
84
|
+
ts,
|
|
85
|
+
attributes: { ...baseAttrs, ...attributes },
|
|
86
|
+
});
|
|
87
|
+
if (payload.state === 'delta') {
|
|
88
|
+
// Deltas are streaming chunks — only the first delta of a new turn is
|
|
89
|
+
// load-bearing for APME (opens the turn). The OpenClaw adapter detects
|
|
90
|
+
// "first delta" via `chatStarted` and is responsible for emitting the
|
|
91
|
+
// turn_start when calling us. We don't emit on every delta — that
|
|
92
|
+
// would balloon the steps table and add no eval signal.
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
if (payload.state === 'final') {
|
|
96
|
+
const spans = [];
|
|
97
|
+
if (payload.response) {
|
|
98
|
+
spans.push(make('turn_response', { 'agentdeck.response_text': payload.response }));
|
|
99
|
+
}
|
|
100
|
+
if (Array.isArray(payload.tools)) {
|
|
101
|
+
for (const t of payload.tools) {
|
|
102
|
+
if (!t.name)
|
|
103
|
+
continue;
|
|
104
|
+
spans.push(make('tool_result', {
|
|
105
|
+
'gen_ai.tool.name': t.name,
|
|
106
|
+
'agentdeck.tool_name': t.name,
|
|
107
|
+
...(t.status ? { 'agentdeck.tool_status': t.status } : {}),
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return spans;
|
|
112
|
+
}
|
|
113
|
+
if (payload.state === 'aborted') {
|
|
114
|
+
// Treat as a manual boundary — user explicitly stopped this turn. The
|
|
115
|
+
// composite outcome derivation will see the absence of a complete
|
|
116
|
+
// response and score accordingly.
|
|
117
|
+
return [make('task_boundary', { 'agentdeck.boundary_signal': 'manual' })];
|
|
118
|
+
}
|
|
119
|
+
if (payload.state === 'error') {
|
|
120
|
+
// Error doesn't close the task — agent might retry on the same prompt.
|
|
121
|
+
// The error is recorded for context but the idle timer continues to
|
|
122
|
+
// run. Returning empty array lets the adapter keep its lifecycle state.
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Convert a Gateway `session.tool` event into spans. This granular per-tool
|
|
129
|
+
* stream carries the tool INPUT/OUTPUT that the coarse `chat.final` tools array
|
|
130
|
+
* lacks — and it was previously silently dropped (openclaw.ts default case), so
|
|
131
|
+
* the sample's tool trajectory had no detail. A `running`/`pending` status maps
|
|
132
|
+
* to a `tool_call` (opens a pending ToolEvent); a terminal status maps to a
|
|
133
|
+
* `tool_result` (resolves it). Pure — no side effects.
|
|
134
|
+
*/
|
|
135
|
+
export function openclawSessionToolToSpans(ctx, payload) {
|
|
136
|
+
const name = payload.name ?? payload.tool;
|
|
137
|
+
if (!name)
|
|
138
|
+
return [];
|
|
139
|
+
const ts = typeof payload.ts === 'number' ? payload.ts : Date.now();
|
|
140
|
+
const status = (payload.status ?? '').toLowerCase();
|
|
141
|
+
const pending = status === '' || status === 'running' || status === 'pending' || status === 'started' || status === 'in_progress';
|
|
142
|
+
const kind = pending ? 'tool_call' : 'tool_result';
|
|
143
|
+
const attrs = {
|
|
144
|
+
'agentdeck.agent_type': ctx.agentType,
|
|
145
|
+
...(ctx.cwd ? { 'agentdeck.cwd': ctx.cwd } : {}),
|
|
146
|
+
'gen_ai.tool.name': name,
|
|
147
|
+
'agentdeck.tool_name': name,
|
|
148
|
+
'agentdeck.raw_payload': {
|
|
149
|
+
...(payload.status ? { status: payload.status } : {}),
|
|
150
|
+
...(payload.input !== undefined ? { tool_input: payload.input } : {}),
|
|
151
|
+
...(payload.output !== undefined ? { tool_response: payload.output } : {}),
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
return [{
|
|
155
|
+
traceId: ctx.traceId,
|
|
156
|
+
spanId: randomUUID(),
|
|
157
|
+
parentSpanId: ctx.activeTurnId,
|
|
158
|
+
name: spanNameForKind(kind),
|
|
159
|
+
kind,
|
|
160
|
+
ts,
|
|
161
|
+
attributes: attrs,
|
|
162
|
+
}];
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Convert a Gateway `session.out-of-band message` into a turn span. User
|
|
166
|
+
* messages open a turn (turn_start); assistant messages set the response
|
|
167
|
+
* (turn_response). Previously dropped, so gateway-initiated turns (cron,
|
|
168
|
+
* automations) had no captured prompt/response in the sample.
|
|
169
|
+
*/
|
|
170
|
+
export function openclawSessionMessageToSpans(ctx, payload) {
|
|
171
|
+
const text = (typeof payload.text === 'string' ? payload.text : undefined)
|
|
172
|
+
?? (typeof payload.content === 'string' ? payload.content : undefined);
|
|
173
|
+
if (!text || !text.trim())
|
|
174
|
+
return [];
|
|
175
|
+
const ts = typeof payload.ts === 'number' ? payload.ts : Date.now();
|
|
176
|
+
const role = (payload.role ?? '').toLowerCase();
|
|
177
|
+
const kind = role === 'assistant' ? 'turn_response' : 'turn_start';
|
|
178
|
+
const attrs = {
|
|
179
|
+
'agentdeck.agent_type': ctx.agentType,
|
|
180
|
+
...(ctx.cwd ? { 'agentdeck.cwd': ctx.cwd } : {}),
|
|
181
|
+
...(kind === 'turn_start' ? { 'agentdeck.prompt_text': text } : { 'agentdeck.response_text': text }),
|
|
182
|
+
};
|
|
183
|
+
return [{
|
|
184
|
+
traceId: ctx.traceId,
|
|
185
|
+
spanId: randomUUID(),
|
|
186
|
+
parentSpanId: ctx.activeTurnId,
|
|
187
|
+
name: spanNameForKind(kind),
|
|
188
|
+
kind,
|
|
189
|
+
ts,
|
|
190
|
+
attributes: attrs,
|
|
191
|
+
}];
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Build the spans the adapter should emit when its idle-gap timer expires.
|
|
195
|
+
* Returned as a function (not a constant) because the timestamp is "now"
|
|
196
|
+
* at expiry, not "now" at adapter construction.
|
|
197
|
+
*/
|
|
198
|
+
export function openclawIdleGapTaskBoundary(ctx) {
|
|
199
|
+
return {
|
|
200
|
+
traceId: ctx.traceId,
|
|
201
|
+
spanId: randomUUID(),
|
|
202
|
+
parentSpanId: ctx.activeTurnId,
|
|
203
|
+
name: spanNameForKind('task_boundary'),
|
|
204
|
+
kind: 'task_boundary',
|
|
205
|
+
ts: Date.now(),
|
|
206
|
+
attributes: {
|
|
207
|
+
'agentdeck.agent_type': ctx.agentType,
|
|
208
|
+
...(ctx.cwd ? { 'agentdeck.cwd': ctx.cwd } : {}),
|
|
209
|
+
'agentdeck.boundary_signal': 'idle_gap',
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Build the user-prompt span the adapter should emit on `chat.send`. Kept
|
|
215
|
+
* here for symmetry with `claude-hook.ts::claudeHookToSpans` and so future
|
|
216
|
+
* test fixtures can exercise the boundary detector without spinning a real
|
|
217
|
+
* Gateway connection.
|
|
218
|
+
*/
|
|
219
|
+
export function openclawChatSendToSpan(ctx, prompt) {
|
|
220
|
+
return {
|
|
221
|
+
traceId: ctx.traceId,
|
|
222
|
+
spanId: randomUUID(),
|
|
223
|
+
parentSpanId: undefined,
|
|
224
|
+
name: spanNameForKind('turn_start'),
|
|
225
|
+
kind: 'turn_start',
|
|
226
|
+
ts: Date.now(),
|
|
227
|
+
attributes: {
|
|
228
|
+
'agentdeck.agent_type': ctx.agentType,
|
|
229
|
+
...(ctx.cwd ? { 'agentdeck.cwd': ctx.cwd } : {}),
|
|
230
|
+
'agentdeck.prompt_text': prompt,
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=openclaw-hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openclaw-hook.js","sourceRoot":"","sources":["../../../src/apme/adapters/openclaw-hook.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode SSE → TelemetrySpan adapter.
|
|
3
|
+
*
|
|
4
|
+
* OpenCode (https://github.com/sst/opencode) is the third coding agent
|
|
5
|
+
* AgentDeck monitors. Unlike Claude Code and Codex CLI, it has no command-
|
|
6
|
+
* level hook layer — its lifecycle is observed via the SSE stream emitted by
|
|
7
|
+
* `opencode serve` on its HTTP port. The OpenCode adapter
|
|
8
|
+
* (`bridge/src/adapters/opencode-adapter.ts`) subscribes to that stream and
|
|
9
|
+
* forwards `OpenCodeSSEEvent` payloads into the bridge.
|
|
10
|
+
*
|
|
11
|
+
* This helper takes those SSE payloads and produces the same `TelemetrySpan`
|
|
12
|
+
* shape that `claude-hook.ts` and `codex-hook.ts` emit, so the existing
|
|
13
|
+
* `ApmeCollector.ingestSpan` pipeline handles all three agents uniformly.
|
|
14
|
+
* Without this, OpenCode runs never reach APME — they fall back to
|
|
15
|
+
* `session_end`-only task boundaries (one task per session, defeating
|
|
16
|
+
* per-task evaluation).
|
|
17
|
+
*
|
|
18
|
+
* Detected boundary signals (priority order):
|
|
19
|
+
* 1. `todo_complete` — `message.part.updated` carrying a tool part whose
|
|
20
|
+
* tool name is "todowrite" and whose `state.output` reports every todo
|
|
21
|
+
* with `status === 'completed'`. OpenCode's todowrite tool is the
|
|
22
|
+
* analogue of Claude's TodoWrite + Codex's todo manager.
|
|
23
|
+
* 2. `idle_gap` — the adapter arms a timer on `session.idle` and fires
|
|
24
|
+
* `opencodeIdleGapTaskBoundary` after OPENCODE_IDLE_GAP_MS with no new
|
|
25
|
+
* work (mirrors the OpenClaw idle-gap segmentation). Without it,
|
|
26
|
+
* OpenCode tasks close only on `session_end` — one task per session,
|
|
27
|
+
* defeating per-task evaluation.
|
|
28
|
+
* 3. (`/clear` and `manual` are reserved for future direct integrations —
|
|
29
|
+
* OpenCode doesn't currently surface either via SSE.)
|
|
30
|
+
*
|
|
31
|
+
* Tool calls and tool results map to `tool_call` / `tool_result` spans for
|
|
32
|
+
* step-level parity with Claude / Codex (drives the timeline and the
|
|
33
|
+
* deterministic Layer 1 efficiency metrics).
|
|
34
|
+
*/
|
|
35
|
+
import type { AdapterContext, TelemetrySpan } from '@agentdeck/shared';
|
|
36
|
+
import type { OpenCodeMessagePart, OpenCodeMessageInfo } from '../../opencode-client.js';
|
|
37
|
+
/**
|
|
38
|
+
* Convert a single OpenCode SSE `message.part.updated` payload into spans.
|
|
39
|
+
*
|
|
40
|
+
* Returns an empty array when the part isn't APME-relevant (text / step-finish
|
|
41
|
+
* are accumulated elsewhere). Caller is expected to drop empty arrays.
|
|
42
|
+
*/
|
|
43
|
+
export declare function opencodePartToSpans(ctx: AdapterContext, part: OpenCodeMessagePart): TelemetrySpan[];
|
|
44
|
+
/**
|
|
45
|
+
* Spans for a `message.updated` SSE payload. OpenCode emits these on both
|
|
46
|
+
* user prompts (open a turn) and assistant turn-end signals (close it).
|
|
47
|
+
*/
|
|
48
|
+
export declare function opencodeMessageToSpans(ctx: AdapterContext, info: OpenCodeMessageInfo, promptText: string | undefined, responseText: string | undefined): TelemetrySpan[];
|
|
49
|
+
/** How long a session must sit idle (no new work after `session.idle`)
|
|
50
|
+
* before the active task closes with an `idle_gap` boundary. Matches
|
|
51
|
+
* OPENCLAW_IDLE_GAP_MS — the two adapters segment on the same rhythm. */
|
|
52
|
+
export declare const OPENCODE_IDLE_GAP_MS = 90000;
|
|
53
|
+
/** Build the `task_boundary` (idle_gap) span the adapter emits when the
|
|
54
|
+
* idle-gap timer fires. Mirrors `openclawIdleGapTaskBoundary`. */
|
|
55
|
+
export declare function opencodeIdleGapTaskBoundary(ctx: AdapterContext): TelemetrySpan;
|
|
56
|
+
//# sourceMappingURL=opencode-hook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode-hook.d.ts","sourceRoot":"","sources":["../../../src/apme/adapters/opencode-hook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAGH,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EAEd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEzF;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,mBAAmB,GACxB,aAAa,EAAE,CAuCjB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,mBAAmB,EACzB,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,aAAa,EAAE,CAoCjB;AAED;;0EAE0E;AAC1E,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAE3C;mEACmE;AACnE,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,cAAc,GAAG,aAAa,CAc9E"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode SSE → TelemetrySpan adapter.
|
|
3
|
+
*
|
|
4
|
+
* OpenCode (https://github.com/sst/opencode) is the third coding agent
|
|
5
|
+
* AgentDeck monitors. Unlike Claude Code and Codex CLI, it has no command-
|
|
6
|
+
* level hook layer — its lifecycle is observed via the SSE stream emitted by
|
|
7
|
+
* `opencode serve` on its HTTP port. The OpenCode adapter
|
|
8
|
+
* (`bridge/src/adapters/opencode-adapter.ts`) subscribes to that stream and
|
|
9
|
+
* forwards `OpenCodeSSEEvent` payloads into the bridge.
|
|
10
|
+
*
|
|
11
|
+
* This helper takes those SSE payloads and produces the same `TelemetrySpan`
|
|
12
|
+
* shape that `claude-hook.ts` and `codex-hook.ts` emit, so the existing
|
|
13
|
+
* `ApmeCollector.ingestSpan` pipeline handles all three agents uniformly.
|
|
14
|
+
* Without this, OpenCode runs never reach APME — they fall back to
|
|
15
|
+
* `session_end`-only task boundaries (one task per session, defeating
|
|
16
|
+
* per-task evaluation).
|
|
17
|
+
*
|
|
18
|
+
* Detected boundary signals (priority order):
|
|
19
|
+
* 1. `todo_complete` — `message.part.updated` carrying a tool part whose
|
|
20
|
+
* tool name is "todowrite" and whose `state.output` reports every todo
|
|
21
|
+
* with `status === 'completed'`. OpenCode's todowrite tool is the
|
|
22
|
+
* analogue of Claude's TodoWrite + Codex's todo manager.
|
|
23
|
+
* 2. `idle_gap` — the adapter arms a timer on `session.idle` and fires
|
|
24
|
+
* `opencodeIdleGapTaskBoundary` after OPENCODE_IDLE_GAP_MS with no new
|
|
25
|
+
* work (mirrors the OpenClaw idle-gap segmentation). Without it,
|
|
26
|
+
* OpenCode tasks close only on `session_end` — one task per session,
|
|
27
|
+
* defeating per-task evaluation.
|
|
28
|
+
* 3. (`/clear` and `manual` are reserved for future direct integrations —
|
|
29
|
+
* OpenCode doesn't currently surface either via SSE.)
|
|
30
|
+
*
|
|
31
|
+
* Tool calls and tool results map to `tool_call` / `tool_result` spans for
|
|
32
|
+
* step-level parity with Claude / Codex (drives the timeline and the
|
|
33
|
+
* deterministic Layer 1 efficiency metrics).
|
|
34
|
+
*/
|
|
35
|
+
import { randomUUID } from 'crypto';
|
|
36
|
+
import { spanNameForKind } from '@agentdeck/shared';
|
|
37
|
+
/**
|
|
38
|
+
* Convert a single OpenCode SSE `message.part.updated` payload into spans.
|
|
39
|
+
*
|
|
40
|
+
* Returns an empty array when the part isn't APME-relevant (text / step-finish
|
|
41
|
+
* are accumulated elsewhere). Caller is expected to drop empty arrays.
|
|
42
|
+
*/
|
|
43
|
+
export function opencodePartToSpans(ctx, part) {
|
|
44
|
+
if (part.type !== 'tool')
|
|
45
|
+
return [];
|
|
46
|
+
const ts = Date.now();
|
|
47
|
+
const toolName = (part.tool ?? 'unknown').toLowerCase();
|
|
48
|
+
const status = part.state?.status ?? 'running';
|
|
49
|
+
const baseAttrs = {
|
|
50
|
+
'agentdeck.agent_type': ctx.agentType,
|
|
51
|
+
...(ctx.cwd ? { 'agentdeck.cwd': ctx.cwd } : {}),
|
|
52
|
+
'gen_ai.tool.name': toolName,
|
|
53
|
+
'agentdeck.tool_name': toolName,
|
|
54
|
+
'agentdeck.raw_payload': part,
|
|
55
|
+
};
|
|
56
|
+
const make = (kind, attributes = {}) => ({
|
|
57
|
+
traceId: ctx.traceId,
|
|
58
|
+
spanId: randomUUID(),
|
|
59
|
+
parentSpanId: ctx.activeTurnId,
|
|
60
|
+
name: spanNameForKind(kind),
|
|
61
|
+
kind,
|
|
62
|
+
ts,
|
|
63
|
+
attributes: { ...baseAttrs, ...attributes },
|
|
64
|
+
});
|
|
65
|
+
const spans = [];
|
|
66
|
+
if (status === 'completed') {
|
|
67
|
+
spans.push(make('tool_result'));
|
|
68
|
+
// todowrite completion with every item marked 'completed' is the agent
|
|
69
|
+
// declaring the task done — same semantics as Claude's TodoWrite
|
|
70
|
+
// PostToolUse boundary check in `collector.ts::ingestHook`.
|
|
71
|
+
if (toolName === 'todowrite' && allTodosCompleted(part)) {
|
|
72
|
+
spans.push(make('task_boundary', { 'agentdeck.boundary_signal': 'todo_complete' }));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
spans.push(make('tool_call'));
|
|
77
|
+
}
|
|
78
|
+
return spans;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Spans for a `message.updated` SSE payload. OpenCode emits these on both
|
|
82
|
+
* user prompts (open a turn) and assistant turn-end signals (close it).
|
|
83
|
+
*/
|
|
84
|
+
export function opencodeMessageToSpans(ctx, info, promptText, responseText) {
|
|
85
|
+
const ts = Date.now();
|
|
86
|
+
const baseAttrs = {
|
|
87
|
+
'agentdeck.agent_type': ctx.agentType,
|
|
88
|
+
...(ctx.cwd ? { 'agentdeck.cwd': ctx.cwd } : {}),
|
|
89
|
+
};
|
|
90
|
+
const make = (kind, attributes = {}) => ({
|
|
91
|
+
traceId: ctx.traceId,
|
|
92
|
+
spanId: randomUUID(),
|
|
93
|
+
parentSpanId: ctx.activeTurnId,
|
|
94
|
+
name: spanNameForKind(kind),
|
|
95
|
+
kind,
|
|
96
|
+
ts,
|
|
97
|
+
attributes: { ...baseAttrs, ...attributes },
|
|
98
|
+
});
|
|
99
|
+
const spans = [];
|
|
100
|
+
// Attribute the model as soon as an assistant message reveals it. OpenCode's
|
|
101
|
+
// SSE `message.updated` carries modelID/providerID, but that only ever
|
|
102
|
+
// reached the display StateMachine — the APME span pipeline never emitted a
|
|
103
|
+
// session_meta span, so every opencode run persisted model_id=NULL. Emitting
|
|
104
|
+
// it here routes through collector.ts (gen_ai.request.model -> updateModel),
|
|
105
|
+
// which writes directly to the bound APME session (no StateMachine reliance).
|
|
106
|
+
if (info.role === 'assistant' && info.modelID) {
|
|
107
|
+
const model = info.providerID ? `${info.providerID}/${info.modelID}` : info.modelID;
|
|
108
|
+
spans.push(make('session_meta', { 'gen_ai.request.model': model }));
|
|
109
|
+
}
|
|
110
|
+
if (info.role === 'user' && promptText) {
|
|
111
|
+
spans.push(make('turn_start', { 'agentdeck.prompt_text': promptText }));
|
|
112
|
+
}
|
|
113
|
+
else if (info.role === 'assistant' && responseText) {
|
|
114
|
+
spans.push(make('turn_response', { 'agentdeck.response_text': responseText }));
|
|
115
|
+
}
|
|
116
|
+
return spans;
|
|
117
|
+
}
|
|
118
|
+
/** How long a session must sit idle (no new work after `session.idle`)
|
|
119
|
+
* before the active task closes with an `idle_gap` boundary. Matches
|
|
120
|
+
* OPENCLAW_IDLE_GAP_MS — the two adapters segment on the same rhythm. */
|
|
121
|
+
export const OPENCODE_IDLE_GAP_MS = 90_000;
|
|
122
|
+
/** Build the `task_boundary` (idle_gap) span the adapter emits when the
|
|
123
|
+
* idle-gap timer fires. Mirrors `openclawIdleGapTaskBoundary`. */
|
|
124
|
+
export function opencodeIdleGapTaskBoundary(ctx) {
|
|
125
|
+
return {
|
|
126
|
+
traceId: ctx.traceId,
|
|
127
|
+
spanId: randomUUID(),
|
|
128
|
+
parentSpanId: ctx.activeTurnId,
|
|
129
|
+
name: spanNameForKind('task_boundary'),
|
|
130
|
+
kind: 'task_boundary',
|
|
131
|
+
ts: Date.now(),
|
|
132
|
+
attributes: {
|
|
133
|
+
'agentdeck.agent_type': ctx.agentType,
|
|
134
|
+
...(ctx.cwd ? { 'agentdeck.cwd': ctx.cwd } : {}),
|
|
135
|
+
'agentdeck.boundary_signal': 'idle_gap',
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Read the todos array out of an OpenCode todowrite tool part. OpenCode's
|
|
141
|
+
* todowrite stores its state under `part.state.output` as a JSON string of
|
|
142
|
+
* `{ todos: [{ status, ... }] }` (the same shape Claude Code's TodoWrite
|
|
143
|
+
* uses). Returns true when every entry is `completed`. Empty list returns
|
|
144
|
+
* false — we shouldn't treat "no todos" as task completion.
|
|
145
|
+
*/
|
|
146
|
+
function allTodosCompleted(part) {
|
|
147
|
+
// Try input first (some OpenCode versions echo the final todos list there).
|
|
148
|
+
const inputTodos = readTodosFromUnknown(part.state?.input);
|
|
149
|
+
if (inputTodos && inputTodos.length > 0 && inputTodos.every((t) => t.status === 'completed')) {
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
// Output is usually a JSON-encoded string.
|
|
153
|
+
const output = part.state?.output;
|
|
154
|
+
if (typeof output === 'string') {
|
|
155
|
+
try {
|
|
156
|
+
const parsed = JSON.parse(output);
|
|
157
|
+
const todos = readTodosFromUnknown(parsed);
|
|
158
|
+
if (todos && todos.length > 0) {
|
|
159
|
+
return todos.every((t) => t.status === 'completed');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
// ignore malformed output — treat as not-all-completed
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
function readTodosFromUnknown(value) {
|
|
169
|
+
if (!value || typeof value !== 'object')
|
|
170
|
+
return null;
|
|
171
|
+
const obj = value;
|
|
172
|
+
const candidates = [obj.todos, obj.tool_input?.todos];
|
|
173
|
+
for (const c of candidates) {
|
|
174
|
+
if (Array.isArray(c)) {
|
|
175
|
+
return c
|
|
176
|
+
.filter((it) => !!it && typeof it === 'object')
|
|
177
|
+
.map((it) => ({ status: String(it.status ?? '') }));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=opencode-hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode-hook.js","sourceRoot":"","sources":["../../../src/apme/adapters/opencode-hook.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeline.d.ts","sourceRoot":"","sources":["../../../src/apme/adapters/timeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EAEb,aAAa,EACd,MAAM,mBAAmB,CAAC;AAG3B,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,cAAc,EACnB,KAAK,EAAE,aAAa,GACnB,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"timeline.d.ts","sourceRoot":"","sources":["../../../src/apme/adapters/timeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EAEb,aAAa,EACd,MAAM,mBAAmB,CAAC;AAG3B,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,cAAc,EACnB,KAAK,EAAE,aAAa,GACnB,aAAa,EAAE,CAwDjB"}
|
|
@@ -48,7 +48,12 @@ export function timelineEntryToSpans(ctx, entry) {
|
|
|
48
48
|
'agentdeck.fallback_to_last_closed': true,
|
|
49
49
|
})];
|
|
50
50
|
}
|
|
51
|
-
|
|
51
|
+
// tool_request: Claude PreToolUse hook + Codex parser tool_action (after
|
|
52
|
+
// 2025-05 alignment) emit this. tool_exec: legacy OpenClaw parseLogLine
|
|
53
|
+
// and pre-alignment Codex emits — treated identically so APME counts
|
|
54
|
+
// every tool invocation regardless of source.
|
|
55
|
+
case 'tool_request':
|
|
56
|
+
case 'tool_exec': {
|
|
52
57
|
// Some sources pack the tool name as the first whitespace-delimited token
|
|
53
58
|
// in `raw`; when missing, the collector falls back to the literal 'tool'.
|
|
54
59
|
const toolName = entry.raw?.split(' ')[0] ?? 'tool';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeline.js","sourceRoot":"","sources":["../../../src/apme/adapters/timeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAOpC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,UAAU,oBAAoB,CAClC,GAAmB,EACnB,KAAoB;IAEpB,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;IAClC,MAAM,SAAS,GAAwB;QACrC,sBAAsB,EAAE,GAAG,CAAC,SAAS;QACrC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACjD,CAAC;IACF,MAAM,IAAI,GAAG,CACX,IAA2B,EAC3B,UAA+B,EAChB,EAAE,CAAC,CAAC;QACnB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,MAAM,EAAE,UAAU,EAAE;QACpB,YAAY,EAAE,GAAG,CAAC,YAAY;QAC9B,IAAI,EAAE,eAAe,CAAC,IAAI,CAAC;QAC3B,IAAI;QACJ,EAAE;QACF,UAAU,EAAE,EAAE,GAAG,SAAS,EAAE,GAAG,UAAU,EAAE;KAC5C,CAAC,CAAC;IAEH,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,EAAE,CAAC;YAC/C,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,uBAAuB,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QACnE,CAAC;QACD,KAAK,eAAe,CAAC,CAAC,CAAC;YACrB,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,EAAE,CAAC;YACjD,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC;gBAAE,OAAO,EAAE,CAAC;YACpC,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,yBAAyB,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QAC1E,CAAC;QACD,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC;YACpC,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC;gBAAE,OAAO,EAAE,CAAC;YACpC,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE;oBAC5B,yBAAyB,EAAE,QAAQ;oBACnC,mCAAmC,EAAE,IAAI;iBAC1C,CAAC,CAAC,CAAC;QACN,CAAC;QACD,KAAK,cAAc,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"timeline.js","sourceRoot":"","sources":["../../../src/apme/adapters/timeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAOpC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,UAAU,oBAAoB,CAClC,GAAmB,EACnB,KAAoB;IAEpB,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;IAClC,MAAM,SAAS,GAAwB;QACrC,sBAAsB,EAAE,GAAG,CAAC,SAAS;QACrC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACjD,CAAC;IACF,MAAM,IAAI,GAAG,CACX,IAA2B,EAC3B,UAA+B,EAChB,EAAE,CAAC,CAAC;QACnB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,MAAM,EAAE,UAAU,EAAE;QACpB,YAAY,EAAE,GAAG,CAAC,YAAY;QAC9B,IAAI,EAAE,eAAe,CAAC,IAAI,CAAC;QAC3B,IAAI;QACJ,EAAE;QACF,UAAU,EAAE,EAAE,GAAG,SAAS,EAAE,GAAG,UAAU,EAAE;KAC5C,CAAC,CAAC;IAEH,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,EAAE,CAAC;YAC/C,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,uBAAuB,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QACnE,CAAC;QACD,KAAK,eAAe,CAAC,CAAC,CAAC;YACrB,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,EAAE,CAAC;YACjD,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC;gBAAE,OAAO,EAAE,CAAC;YACpC,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,yBAAyB,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QAC1E,CAAC;QACD,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC;YACpC,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC;gBAAE,OAAO,EAAE,CAAC;YACpC,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE;oBAC5B,yBAAyB,EAAE,QAAQ;oBACnC,mCAAmC,EAAE,IAAI;iBAC1C,CAAC,CAAC,CAAC;QACN,CAAC;QACD,yEAAyE;QACzE,wEAAwE;QACxE,qEAAqE;QACrE,8CAA8C;QAC9C,KAAK,cAAc,CAAC;QACpB,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,0EAA0E;YAC1E,0EAA0E;YAC1E,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC;YACpD,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE;oBACxB,kBAAkB,EAAE,QAAQ;oBAC5B,qBAAqB,EAAE,QAAQ;iBAChC,CAAC,CAAC,CAAC;QACN,CAAC;QACD,KAAK,eAAe;YAClB,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,CAAC;QACnC;YACE,OAAO,EAAE,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface AntigravityTranscriptSummary {
|
|
2
|
+
goal?: string;
|
|
3
|
+
state: 'idle' | 'processing';
|
|
4
|
+
currentTask?: string;
|
|
5
|
+
/** Human model label from the transcript's last USER_SETTINGS_CHANGE, if any
|
|
6
|
+
* (e.g. "GPT-OSS 120B (Medium)", "Gemini 3.5 Flash (Medium)"). */
|
|
7
|
+
model?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function antigravityRoot(): string;
|
|
10
|
+
/** Parse an agy transcript sample into goal / state / currentTask / model. */
|
|
11
|
+
export declare function parseAntigravityTranscript(raw: string): AntigravityTranscriptSummary;
|
|
12
|
+
/** Global default model from settings.json (fallback when a conversation never
|
|
13
|
+
* recorded an explicit model selection). */
|
|
14
|
+
export declare function antigravityDefaultModel(): string | undefined;
|
|
15
|
+
/** Resolve the conversationId for a workspace cwd via the last-opened cache. */
|
|
16
|
+
export declare function antigravityConversationId(cwd: string | undefined): string | undefined;
|
|
17
|
+
export declare function antigravityTranscriptPath(conversationId: string): string;
|
|
18
|
+
//# sourceMappingURL=antigravity-transcript.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"antigravity-transcript.d.ts","sourceRoot":"","sources":["../../src/apme/antigravity-transcript.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,4BAA4B;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,YAAY,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;uEACmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAgBD,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,8EAA8E;AAC9E,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,4BAA4B,CA8BpF;AAMD;6CAC6C;AAC7C,wBAAgB,uBAAuB,IAAI,MAAM,GAAG,SAAS,CAK5D;AAED,gFAAgF;AAChF,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAQrF;AAED,wBAAgB,yBAAyB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAExE"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antigravity (`agy` CLI) transcript parsing.
|
|
3
|
+
*
|
|
4
|
+
* The agy CLI persists each conversation as a plain JSONL transcript at
|
|
5
|
+
* ~/.gemini/antigravity-cli/brain/<conversationId>/.system_generated/logs/transcript.jsonl
|
|
6
|
+
* one JSON object per step:
|
|
7
|
+
* { step_index, source, type, status, created_at, content?, thinking?, tool_calls? }
|
|
8
|
+
*
|
|
9
|
+
* Unlike Claude/Codex, the model id is NOT on each record. It surfaces in the
|
|
10
|
+
* first USER_INPUT's `<USER_SETTINGS_CHANGE>` tag ("...from None to <MODEL>.")
|
|
11
|
+
* when a model is selected for the conversation; otherwise the global default
|
|
12
|
+
* in `settings.json` applies. The session log carries a live override line too,
|
|
13
|
+
* but the per-conversation transcript is the cleanest attribution source.
|
|
14
|
+
*
|
|
15
|
+
* These pure functions are shared by the passive observer (creature + model
|
|
16
|
+
* display) and the APME ingester (run/turn model attribution) so agy gets the
|
|
17
|
+
* same scorecard treatment as the other agents.
|
|
18
|
+
*/
|
|
19
|
+
import { readFileSync } from 'fs';
|
|
20
|
+
import { homedir } from 'os';
|
|
21
|
+
import { join } from 'path';
|
|
22
|
+
/** Step types that represent the agent doing tool work (drives currentTask). */
|
|
23
|
+
const TOOL_TYPES = new Set([
|
|
24
|
+
'VIEW_FILE', 'RUN_COMMAND', 'GREP_SEARCH', 'LIST_DIRECTORY', 'CODE_ACTION', 'EDIT_FILE',
|
|
25
|
+
]);
|
|
26
|
+
export function antigravityRoot() {
|
|
27
|
+
return join(homedir(), '.gemini', 'antigravity-cli');
|
|
28
|
+
}
|
|
29
|
+
/** Parse an agy transcript sample into goal / state / currentTask / model. */
|
|
30
|
+
export function parseAntigravityTranscript(raw) {
|
|
31
|
+
const records = [];
|
|
32
|
+
for (const line of raw.split('\n')) {
|
|
33
|
+
if (!line.trim())
|
|
34
|
+
continue;
|
|
35
|
+
try {
|
|
36
|
+
records.push(JSON.parse(line));
|
|
37
|
+
}
|
|
38
|
+
catch { /* skip malformed line */ }
|
|
39
|
+
}
|
|
40
|
+
let goal;
|
|
41
|
+
let model;
|
|
42
|
+
let currentTask;
|
|
43
|
+
let processing = false;
|
|
44
|
+
for (const rec of records) {
|
|
45
|
+
if (rec.type === 'USER_INPUT' && typeof rec.content === 'string') {
|
|
46
|
+
if (!goal) {
|
|
47
|
+
const req = rec.content.match(/<USER_REQUEST>\s*([\s\S]*?)\s*<\/USER_REQUEST>/);
|
|
48
|
+
if (req && req[1].trim())
|
|
49
|
+
goal = cleanGoal(req[1]);
|
|
50
|
+
}
|
|
51
|
+
// "The user changed setting `Model Selection` from None to GPT-OSS 120B (Medium)."
|
|
52
|
+
// Take the latest one seen → the model active for this conversation.
|
|
53
|
+
const change = rec.content.match(/Model Selection`?\s+from\s+.*?\s+to\s+(.+?)\.(?:\s|$)/);
|
|
54
|
+
if (change && change[1].trim())
|
|
55
|
+
model = change[1].trim();
|
|
56
|
+
}
|
|
57
|
+
if (rec.status === 'RUNNING')
|
|
58
|
+
processing = true;
|
|
59
|
+
if (rec.type && TOOL_TYPES.has(rec.type)) {
|
|
60
|
+
currentTask = rec.tool_calls?.[0]?.name ?? rec.type.toLowerCase();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return { goal, model, currentTask, state: processing ? 'processing' : 'idle' };
|
|
64
|
+
}
|
|
65
|
+
function cleanGoal(s) {
|
|
66
|
+
return s.replace(/\s+/g, ' ').trim().slice(0, 200);
|
|
67
|
+
}
|
|
68
|
+
/** Global default model from settings.json (fallback when a conversation never
|
|
69
|
+
* recorded an explicit model selection). */
|
|
70
|
+
export function antigravityDefaultModel() {
|
|
71
|
+
try {
|
|
72
|
+
const j = JSON.parse(readFileSync(join(antigravityRoot(), 'settings.json'), 'utf8'));
|
|
73
|
+
return typeof j.model === 'string' ? j.model : undefined;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** Resolve the conversationId for a workspace cwd via the last-opened cache. */
|
|
80
|
+
export function antigravityConversationId(cwd) {
|
|
81
|
+
if (!cwd)
|
|
82
|
+
return undefined;
|
|
83
|
+
try {
|
|
84
|
+
const j = JSON.parse(readFileSync(join(antigravityRoot(), 'cache', 'last_conversations.json'), 'utf8'));
|
|
85
|
+
return typeof j[cwd] === 'string' ? j[cwd] : undefined;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
export function antigravityTranscriptPath(conversationId) {
|
|
92
|
+
return join(antigravityRoot(), 'brain', conversationId, '.system_generated', 'logs', 'transcript.jsonl');
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=antigravity-transcript.js.map
|