@agentdeck/bridge 0.2.2 → 1.0.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/assets/fm-helper/agentdeck-fm-helper +0 -0
- 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 +133 -6
- package/dist/apme/collector.d.ts.map +1 -1
- package/dist/apme/collector.js +471 -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 +117 -11
- package/dist/apme/dashboard-html.js.map +1 -1
- package/dist/apme/http.d.ts.map +1 -1
- package/dist/apme/http.js +52 -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 +146 -9
- package/dist/apme/index.js.map +1 -1
- package/dist/apme/judge-detect.d.ts +26 -0
- package/dist/apme/judge-detect.d.ts.map +1 -0
- package/dist/apme/judge-detect.js +69 -0
- package/dist/apme/judge-detect.js.map +1 -0
- 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 +99 -4
- package/dist/apme/runner.d.ts.map +1 -1
- package/dist/apme/runner.js +743 -72
- 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 +17 -11
- package/dist/apme/settings.d.ts.map +1 -1
- package/dist/apme/settings.js +30 -9
- 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 +112 -0
- package/dist/awaiting-overlay.d.ts.map +1 -0
- package/dist/awaiting-overlay.js +179 -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 +34 -1
- package/dist/bridge-core.d.ts.map +1 -1
- package/dist/bridge-core.js +207 -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/claude-permission-rules.d.ts +55 -0
- package/dist/claude-permission-rules.d.ts.map +1 -0
- package/dist/claude-permission-rules.js +197 -0
- package/dist/claude-permission-rules.js.map +1 -0
- package/dist/cli.d.ts +15 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1030 -93
- 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/d200h/image-renderer.d.ts +4 -16
- package/dist/d200h/image-renderer.d.ts.map +1 -1
- package/dist/d200h/image-renderer.js +46 -212
- package/dist/d200h/image-renderer.js.map +1 -1
- package/dist/daemon-server.d.ts +85 -0
- package/dist/daemon-server.d.ts.map +1 -1
- package/dist/daemon-server.js +1975 -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 +190 -1
- package/dist/esp32-serial.d.ts.map +1 -1
- package/dist/esp32-serial.js +1090 -156
- 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 +119 -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 +23 -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 +217 -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 +3 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +18 -5
- 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/model-catalog.d.ts +1 -1
- package/dist/model-catalog.d.ts.map +1 -1
- package/dist/model-catalog.js +2 -4
- package/dist/model-catalog.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/d200h-module.d.ts +22 -0
- package/dist/modules/d200h-module.d.ts.map +1 -1
- package/dist/modules/d200h-module.js +200 -65
- package/dist/modules/d200h-module.js.map +1 -1
- 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/trmnl-module.d.ts +38 -0
- package/dist/modules/trmnl-module.d.ts.map +1 -0
- package/dist/modules/trmnl-module.js +111 -0
- package/dist/modules/trmnl-module.js.map +1 -0
- package/dist/modules/types.d.ts +4 -2
- package/dist/modules/types.d.ts.map +1 -1
- package/dist/observed-steering.d.ts +93 -0
- package/dist/observed-steering.d.ts.map +1 -0
- package/dist/observed-steering.js +247 -0
- package/dist/observed-steering.js.map +1 -0
- 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/opencode-steering.d.ts +36 -0
- package/dist/opencode-steering.d.ts.map +1 -0
- package/dist/opencode-steering.js +84 -0
- package/dist/opencode-steering.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 +172 -18
- package/dist/output-parser.js.map +1 -1
- package/dist/passive-observer.d.ts +32 -0
- package/dist/passive-observer.d.ts.map +1 -1
- package/dist/passive-observer.js +288 -49
- package/dist/passive-observer.js.map +1 -1
- package/dist/permission-resolver.d.ts +55 -0
- package/dist/permission-resolver.d.ts.map +1 -0
- package/dist/permission-resolver.js +112 -0
- package/dist/permission-resolver.js.map +1 -0
- package/dist/pixoo/micro-glyphs.d.ts +18 -0
- package/dist/pixoo/micro-glyphs.d.ts.map +1 -0
- package/dist/pixoo/micro-glyphs.js +143 -0
- package/dist/pixoo/micro-glyphs.js.map +1 -0
- package/dist/pixoo/official-dot-glyphs.generated.d.ts +8 -0
- package/dist/pixoo/official-dot-glyphs.generated.d.ts.map +1 -0
- package/dist/pixoo/official-dot-glyphs.generated.js +247 -0
- package/dist/pixoo/official-dot-glyphs.generated.js.map +1 -0
- package/dist/pixoo/pixoo-bridge.d.ts +16 -8
- package/dist/pixoo/pixoo-bridge.d.ts.map +1 -1
- package/dist/pixoo/pixoo-bridge.js +127 -35
- 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 +27 -3
- package/dist/pixoo/pixoo-renderer.d.ts.map +1 -1
- package/dist/pixoo/pixoo-renderer.js +533 -135
- 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 +84 -11
- package/dist/pixoo/pixoo-sprites.d.ts.map +1 -1
- package/dist/pixoo/pixoo-sprites.js +620 -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/review-runner.d.ts +113 -0
- package/dist/review-runner.d.ts.map +1 -0
- package/dist/review-runner.js +428 -0
- package/dist/review-runner.js.map +1 -0
- 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 +25 -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-focus-relay.d.ts.map +1 -1
- package/dist/session-focus-relay.js +7 -1
- package/dist/session-focus-relay.js.map +1 -1
- package/dist/session-registry.d.ts +74 -3
- package/dist/session-registry.d.ts.map +1 -1
- package/dist/session-registry.js +140 -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 +112 -3
- package/dist/timeline-store.d.ts.map +1 -1
- package/dist/timeline-store.js +460 -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/trmnl/byos-server.d.ts +39 -0
- package/dist/trmnl/byos-server.d.ts.map +1 -0
- package/dist/trmnl/byos-server.js +301 -0
- package/dist/trmnl/byos-server.js.map +1 -0
- package/dist/trmnl/frame-cache.d.ts +37 -0
- package/dist/trmnl/frame-cache.d.ts.map +1 -0
- package/dist/trmnl/frame-cache.js +157 -0
- package/dist/trmnl/frame-cache.js.map +1 -0
- package/dist/trmnl/image-renderer.d.ts +27 -0
- package/dist/trmnl/image-renderer.d.ts.map +1 -0
- package/dist/trmnl/image-renderer.js +235 -0
- package/dist/trmnl/image-renderer.js.map +1 -0
- package/dist/trmnl/trmnl-settings.d.ts +96 -0
- package/dist/trmnl/trmnl-settings.d.ts.map +1 -0
- package/dist/trmnl/trmnl-settings.js +177 -0
- package/dist/trmnl/trmnl-settings.js.map +1 -0
- package/dist/trmnl/trmnl-telemetry.d.ts +47 -0
- package/dist/trmnl/trmnl-telemetry.d.ts.map +1 -0
- package/dist/trmnl/trmnl-telemetry.js +56 -0
- package/dist/trmnl/trmnl-telemetry.js.map +1 -0
- 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 +38 -11
- 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 +355 -121
- package/dist/tui/renderer.js.map +1 -1
- package/dist/tui/terrarium.d.ts.map +1 -1
- package/dist/tui/terrarium.js +44 -51
- 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 +98 -13
- 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/version-check.d.ts.map +1 -1
- package/dist/version-check.js +1 -17
- package/dist/version-check.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 +17 -3
- package/dist/ws-server.d.ts.map +1 -1
- package/dist/ws-server.js +78 -8
- package/dist/ws-server.js.map +1 -1
- package/fm-helper/AgentDeckFMHelper.swift +112 -0
- package/package.json +10 -4
- 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
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* On-demand independent review (the REVIEW deck button).
|
|
3
|
+
*
|
|
4
|
+
* NOT a prompt to the agent: the daemon collects the session's latest work
|
|
5
|
+
* product (working-tree delta of its cwd) and has an INDEPENDENT judge model
|
|
6
|
+
* assess risk — the same local-first judge stack APME uses (MLX / Foundation
|
|
7
|
+
* Models relay / opt-in API). Because no agent control is involved, every
|
|
8
|
+
* session type qualifies: managed, observed Claude/OpenCode, and even
|
|
9
|
+
* control-less observed Codex.
|
|
10
|
+
*
|
|
11
|
+
* Output fan-out:
|
|
12
|
+
* - `review_status` / `review_result` WS events (dashboards, future UIs)
|
|
13
|
+
* - SessionInfo badge fields via `reviewSnapshot` (REVIEW tile verdict)
|
|
14
|
+
* - a self-contained HTML report written under <dataDir>/reviews/ and
|
|
15
|
+
* opened in the default browser — the "no macOS app" tier's popup.
|
|
16
|
+
*/
|
|
17
|
+
import { execFile } from 'child_process';
|
|
18
|
+
import { mkdirSync, writeFileSync } from 'fs';
|
|
19
|
+
import { join } from 'path';
|
|
20
|
+
import { homedir } from 'os';
|
|
21
|
+
import { callJudgeWithMeta, probeJudgeBackend } from './apme/runner.js';
|
|
22
|
+
import { loadApmeConfig } from './apme/settings.js';
|
|
23
|
+
import { debug, logError } from './logger.js';
|
|
24
|
+
const DIFF_BYTE_CAP = 60_000;
|
|
25
|
+
/** Basic-tier judges (on-device FM relay) overflow long diffs — keep the
|
|
26
|
+
* whole prompt inside a small context window. */
|
|
27
|
+
const BASIC_DIFF_BYTE_CAP = 12_000;
|
|
28
|
+
/** Recent user-request ↔ agent-response context appended to the prompt so
|
|
29
|
+
* the judge evaluates the diff against what the user actually asked. */
|
|
30
|
+
const ACTIVITY_CHAR_CAP = 4_000;
|
|
31
|
+
const GIT_TIMEOUT_MS = 10_000;
|
|
32
|
+
export function reviewJudgeTier(backend) {
|
|
33
|
+
return backend === 'foundationModels' ? 'basic' : 'advanced';
|
|
34
|
+
}
|
|
35
|
+
/** Verdicts older than this stop badging the REVIEW tile. */
|
|
36
|
+
const BADGE_TTL_MS = 30 * 60_000;
|
|
37
|
+
const stateBySession = new Map();
|
|
38
|
+
/** Badge fields for the sessions_list enricher. */
|
|
39
|
+
export function reviewSnapshot(sessionId) {
|
|
40
|
+
const s = stateBySession.get(sessionId);
|
|
41
|
+
if (!s)
|
|
42
|
+
return {};
|
|
43
|
+
if (Date.now() - s.ts > BADGE_TTL_MS) {
|
|
44
|
+
stateBySession.delete(sessionId);
|
|
45
|
+
return {};
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
reviewStatus: s.status,
|
|
49
|
+
...(s.risk ? { reviewRisk: s.risk } : {}),
|
|
50
|
+
...(s.findings != null ? { reviewFindings: s.findings } : {}),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export function isReviewRunning(sessionId) {
|
|
54
|
+
return stateBySession.get(sessionId)?.status === 'running';
|
|
55
|
+
}
|
|
56
|
+
function git(cwd, args) {
|
|
57
|
+
// External-process await: hard timeout is the first line of defense
|
|
58
|
+
// (a wedged git must never wedge a review).
|
|
59
|
+
return new Promise((resolve, reject) => {
|
|
60
|
+
execFile('git', ['-C', cwd, ...args], {
|
|
61
|
+
timeout: GIT_TIMEOUT_MS, maxBuffer: 4 * 1024 * 1024,
|
|
62
|
+
}, (err, stdout) => {
|
|
63
|
+
if (err)
|
|
64
|
+
reject(err);
|
|
65
|
+
else
|
|
66
|
+
resolve(stdout);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
async function collectDelta(cwd, byteCap = DIFF_BYTE_CAP) {
|
|
71
|
+
try {
|
|
72
|
+
await git(cwd, ['rev-parse', '--is-inside-work-tree']);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return null; // not a git repo — trajectory-less Node review has no input
|
|
76
|
+
}
|
|
77
|
+
const [stat, status] = await Promise.all([
|
|
78
|
+
git(cwd, ['diff', 'HEAD', '--stat']).catch(() => ''),
|
|
79
|
+
git(cwd, ['status', '--porcelain']).catch(() => ''),
|
|
80
|
+
]);
|
|
81
|
+
let diff = await git(cwd, ['diff', 'HEAD']).catch(() => '');
|
|
82
|
+
const untracked = status.split('\n')
|
|
83
|
+
.filter((l) => l.startsWith('??'))
|
|
84
|
+
.map((l) => l.slice(3).trim())
|
|
85
|
+
.filter(Boolean);
|
|
86
|
+
let truncated = false;
|
|
87
|
+
if (diff.length > byteCap) {
|
|
88
|
+
diff = diff.slice(0, byteCap);
|
|
89
|
+
truncated = true;
|
|
90
|
+
}
|
|
91
|
+
return { diff, stat, untracked, truncated };
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The review answers the user's question: "what did I ask this agent
|
|
95
|
+
* recently, how did it handle it, and is the result appropriate?" — sized to
|
|
96
|
+
* what the configured judge can actually do (mirrors apple
|
|
97
|
+
* ReviewRunner.buildPrompt). `recentActivity` is the session's recent
|
|
98
|
+
* user-request ↔ agent-response lines so the diff is judged against intent.
|
|
99
|
+
*/
|
|
100
|
+
function buildJudgePrompt(projectName, delta, tier, recentActivity) {
|
|
101
|
+
const activity = recentActivity?.trim()
|
|
102
|
+
? [
|
|
103
|
+
'--- recent session activity (what the user asked ↔ what the agent answered) ---',
|
|
104
|
+
recentActivity.slice(-ACTIVITY_CHAR_CAP),
|
|
105
|
+
'',
|
|
106
|
+
]
|
|
107
|
+
: [];
|
|
108
|
+
const shared = [
|
|
109
|
+
`Project: ${projectName}`,
|
|
110
|
+
delta.truncated ? `(diff truncated to the first ${tier === 'basic' ? '12' : '60'}KB)` : '',
|
|
111
|
+
'',
|
|
112
|
+
...activity,
|
|
113
|
+
'--- git diff --stat ---',
|
|
114
|
+
delta.stat || '(empty)',
|
|
115
|
+
delta.untracked.length ? `Untracked files: ${delta.untracked.slice(0, 20).join(', ')}` : '',
|
|
116
|
+
'--- git diff ---',
|
|
117
|
+
delta.diff || '(no tracked changes)',
|
|
118
|
+
'',
|
|
119
|
+
'Respond with STRICT JSON only, no prose, exactly this shape:',
|
|
120
|
+
'{"risk":"low|medium|high","summary":"<one sentence: what the user asked and whether the change handles it appropriately>","findings":[{"severity":"high|medium|low","title":"...","detail":"...","file":"..."}]}',
|
|
121
|
+
'Include "file" only when it names a real file from the diff; otherwise',
|
|
122
|
+
'omit the key. Every finding must cite something actually present above —',
|
|
123
|
+
'return an empty findings array when nothing is genuinely risky. Do not',
|
|
124
|
+
'invent findings to fill space.',
|
|
125
|
+
];
|
|
126
|
+
if (tier === 'basic') {
|
|
127
|
+
// Small on-device model: one narrow, checkable task — no broad
|
|
128
|
+
// security-audit rubric (small judges fill it with invented findings).
|
|
129
|
+
return [
|
|
130
|
+
'You are reviewing a coding agent\'s uncommitted changes for its user.',
|
|
131
|
+
'Answer one question: does this change look like a reasonable, complete',
|
|
132
|
+
'response to what the user asked? Flag only what you can point to in',
|
|
133
|
+
'the diff: code that is obviously broken or unfinished, deleted files',
|
|
134
|
+
'or data the user did not ask to remove, and leftover debug or secret',
|
|
135
|
+
'material.',
|
|
136
|
+
'',
|
|
137
|
+
...shared,
|
|
138
|
+
].filter(Boolean).join('\n');
|
|
139
|
+
}
|
|
140
|
+
return [
|
|
141
|
+
'You are an independent code reviewer helping the USER of a coding agent',
|
|
142
|
+
'answer: "what did I ask this agent recently, how did it handle it, and',
|
|
143
|
+
'is the result appropriate?" Judge only the delta below — not overall',
|
|
144
|
+
'project quality. Assess, in order of importance: alignment between the',
|
|
145
|
+
'user\'s requests and the change; destructive or irreversible operations;',
|
|
146
|
+
'security issues (secrets, injection, permissions); broken or untested',
|
|
147
|
+
'code paths; incomplete work (TODO/FIXME/stubs); and changes that',
|
|
148
|
+
'contradict their apparent intent. A documentation issue is not a',
|
|
149
|
+
'security issue; use "high"/"medium" only for concrete, evidenced risk.',
|
|
150
|
+
'',
|
|
151
|
+
...shared,
|
|
152
|
+
].filter(Boolean).join('\n');
|
|
153
|
+
}
|
|
154
|
+
function parseJudgeJson(text) {
|
|
155
|
+
const start = text.indexOf('{');
|
|
156
|
+
const end = text.lastIndexOf('}');
|
|
157
|
+
if (start < 0 || end <= start)
|
|
158
|
+
return null;
|
|
159
|
+
try {
|
|
160
|
+
const parsed = JSON.parse(text.slice(start, end + 1));
|
|
161
|
+
const risk = parsed.risk === 'high' || parsed.risk === 'medium' ? parsed.risk : 'low';
|
|
162
|
+
const summary = typeof parsed.summary === 'string' ? parsed.summary.slice(0, 400) : '';
|
|
163
|
+
const findings = Array.isArray(parsed.findings)
|
|
164
|
+
? parsed.findings.slice(0, 20).flatMap((f) => {
|
|
165
|
+
if (!f || typeof f !== 'object')
|
|
166
|
+
return [];
|
|
167
|
+
const o = f;
|
|
168
|
+
return [{
|
|
169
|
+
severity: o.severity === 'high' || o.severity === 'medium' ? o.severity : 'low',
|
|
170
|
+
title: typeof o.title === 'string' ? o.title.slice(0, 160) : 'Finding',
|
|
171
|
+
detail: typeof o.detail === 'string' ? o.detail.slice(0, 1000) : '',
|
|
172
|
+
// Small judges echo schema placeholders back as the path.
|
|
173
|
+
...(typeof o.file === 'string' && o.file && o.file !== 'optional/path' && o.file !== '...'
|
|
174
|
+
? { file: o.file.slice(0, 200) } : {}),
|
|
175
|
+
}];
|
|
176
|
+
})
|
|
177
|
+
: [];
|
|
178
|
+
// Coherence guard (mirrored in apple ReviewRunner.parse): an above-low
|
|
179
|
+
// risk with zero findings is judge noise — the badge would alarm with
|
|
180
|
+
// nothing to show. Risk must be substantiated by at least one finding.
|
|
181
|
+
return { risk: findings.length === 0 ? 'low' : risk, summary, findings };
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
function esc(s) {
|
|
188
|
+
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
189
|
+
}
|
|
190
|
+
/** Self-contained aquarium-tide report — no external assets (works offline,
|
|
191
|
+
* same file doubles as the App Store tier's browser fallback template). */
|
|
192
|
+
export function renderReviewHtml(opts) {
|
|
193
|
+
const { outcome } = opts;
|
|
194
|
+
const riskColor = outcome.risk === 'high' ? '#c2410c' : outcome.risk === 'medium' ? '#b45309' : '#15803d';
|
|
195
|
+
const rows = outcome.findings.map((f) => `
|
|
196
|
+
<div class="finding sev-${f.severity}">
|
|
197
|
+
<div class="head"><span class="sev">${f.severity.toUpperCase()}</span> <strong>${esc(f.title)}</strong>${f.file ? `<code>${esc(f.file)}</code>` : ''}</div>
|
|
198
|
+
<p>${esc(f.detail)}</p>
|
|
199
|
+
</div>`).join('\n');
|
|
200
|
+
return `<!doctype html>
|
|
201
|
+
<html lang="en"><head><meta charset="utf-8"><title>AgentDeck Review — ${esc(opts.projectName)}</title>
|
|
202
|
+
<style>
|
|
203
|
+
:root { color-scheme: light; }
|
|
204
|
+
body { font-family: "IBM Plex Sans", -apple-system, sans-serif; background: #f6f3ec; color: #1c2a25; margin: 0; padding: 32px; }
|
|
205
|
+
.card { max-width: 760px; margin: 0 auto; background: #fffdf8; border: 1px solid #e2dcc9; border-radius: 12px; padding: 28px 32px; }
|
|
206
|
+
h1 { font-size: 20px; margin: 0 0 4px; }
|
|
207
|
+
.meta { color: #5b6f66; font-size: 13px; margin-bottom: 20px; }
|
|
208
|
+
.risk { display: inline-block; padding: 4px 12px; border-radius: 999px; color: #fffdf8; background: ${riskColor}; font-weight: 600; font-size: 13px; letter-spacing: 0.04em; }
|
|
209
|
+
.summary { font-size: 15px; margin: 16px 0 24px; }
|
|
210
|
+
.finding { border-left: 3px solid #e2dcc9; padding: 8px 14px; margin: 12px 0; }
|
|
211
|
+
.finding.sev-high { border-color: #c2410c; }
|
|
212
|
+
.finding.sev-medium { border-color: #b45309; }
|
|
213
|
+
.finding .sev { font-size: 11px; font-weight: 700; color: #5b6f66; margin-right: 6px; }
|
|
214
|
+
.finding code { margin-left: 8px; font-family: "JetBrains Mono", monospace; font-size: 12px; color: #3b5249; }
|
|
215
|
+
.finding p { margin: 6px 0 0; font-size: 14px; }
|
|
216
|
+
pre { background: #efe9da; border-radius: 8px; padding: 12px; overflow-x: auto; font-family: "JetBrains Mono", monospace; font-size: 12px; }
|
|
217
|
+
.empty { color: #5b6f66; font-style: italic; }
|
|
218
|
+
footer { margin-top: 24px; color: #8a9a91; font-size: 12px; }
|
|
219
|
+
</style></head><body><div class="card">
|
|
220
|
+
<h1>Independent Review — ${esc(opts.projectName)}</h1>
|
|
221
|
+
<div class="meta">${esc(opts.sessionLabel)} · ${opts.generatedAt.toISOString()}</div>
|
|
222
|
+
<span class="risk">RISK ${esc(outcome.risk.toUpperCase())}</span>
|
|
223
|
+
<p class="summary">${esc(outcome.summary || 'No summary provided by the judge.')}</p>
|
|
224
|
+
${outcome.findings.length ? rows : '<p class="empty">No risky findings — the judge saw nothing worth flagging in this delta.</p>'}
|
|
225
|
+
<h2 style="font-size:15px">Changed files</h2>
|
|
226
|
+
<pre>${esc(opts.deltaStat || '(no tracked changes)')}</pre>
|
|
227
|
+
<footer>judge: ${esc(outcome.backend)}${opts.tierNote ? ` · ${esc(opts.tierNote)}` : ''} · generated by AgentDeck (independent of the coding agent)</footer>
|
|
228
|
+
</div></body></html>`;
|
|
229
|
+
}
|
|
230
|
+
function reviewsDir() {
|
|
231
|
+
return join(process.env.AGENTDECK_DATA_DIR ?? join(homedir(), '.agentdeck'), 'reviews');
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Honest capability note per judge backend. A risk review is only as good as
|
|
235
|
+
* the judge — an on-device ~3B model can screen for obvious hazards but not
|
|
236
|
+
* audit; small local models below ~8B are not worth trusting at all.
|
|
237
|
+
*/
|
|
238
|
+
export function judgeTierNote(backend) {
|
|
239
|
+
if (backend === 'foundationModels') {
|
|
240
|
+
return 'judge tier: on-device small model — basic screening only, not a thorough audit';
|
|
241
|
+
}
|
|
242
|
+
if (backend === 'mlx' || backend === 'openai') {
|
|
243
|
+
return 'judge tier: configured model — review depth depends on model size (8B minimum, 30B-class recommended for local)';
|
|
244
|
+
}
|
|
245
|
+
return undefined; // api / openclaw route to frontier-class models
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Setup guidance shown when the REVIEW button is pressed with no usable
|
|
249
|
+
* judge. Written to <dataDir>/reviews/ and opened in the browser — the same
|
|
250
|
+
* channel the report itself uses, so the "popup" behaviour is consistent.
|
|
251
|
+
* Deliberately calm: not using REVIEW is a fully supported choice.
|
|
252
|
+
*/
|
|
253
|
+
export function renderJudgeGuidanceHtml(opts) {
|
|
254
|
+
const detected = opts.detected ?? [];
|
|
255
|
+
const detectedBlock = detected.length ? `
|
|
256
|
+
<h2 style="color:#15803d">✓ Detected on this machine — use what you already have</h2>
|
|
257
|
+
${detected.map((d) => `<div style="margin:8px 0;padding:10px 12px;background:#e8f2ea;border:1px solid #bcd9c2;border-radius:8px">
|
|
258
|
+
<strong>${esc(d.label)}</strong> <span class="tier">at ${esc(d.endpoint)}</span>
|
|
259
|
+
<div style="font-size:12px;color:#3b5249;margin-top:2px">${d.models.length} model${d.models.length === 1 ? '' : 's'}: ${esc(d.models.slice(0, 6).join(', '))}</div>
|
|
260
|
+
<pre style="margin-top:6px">{ "apme": { "judge": { "backend": "openai", "endpoint": "${esc(d.endpoint)}", "model": "${esc(d.models[0] ?? '')}" } } }</pre>
|
|
261
|
+
</div>`).join('')}
|
|
262
|
+
<p style="font-size:12px;color:#5b6f66">Point AgentDeck at a server you already run — nothing new to install. An 8B-class instruct model is the realistic minimum for a trustworthy review; smaller models give unreliable findings.</p>
|
|
263
|
+
` : '';
|
|
264
|
+
return `<!doctype html>
|
|
265
|
+
<html lang="en"><head><meta charset="utf-8"><title>AgentDeck Review — judge setup</title>
|
|
266
|
+
<style>
|
|
267
|
+
body { font-family: "IBM Plex Sans", -apple-system, sans-serif; background: #f6f3ec; color: #1c2a25; margin: 0; padding: 32px; }
|
|
268
|
+
.card { max-width: 760px; margin: 0 auto; background: #fffdf8; border: 1px solid #e2dcc9; border-radius: 12px; padding: 28px 32px; }
|
|
269
|
+
h1 { font-size: 20px; margin: 0 0 8px; }
|
|
270
|
+
h2 { font-size: 15px; margin: 22px 0 6px; }
|
|
271
|
+
.why { background: #efe9da; border-radius: 8px; padding: 10px 14px; font-size: 13px; }
|
|
272
|
+
code, pre { font-family: "JetBrains Mono", monospace; font-size: 12px; }
|
|
273
|
+
pre { background: #efe9da; border-radius: 8px; padding: 12px; overflow-x: auto; }
|
|
274
|
+
.rank { display: inline-block; min-width: 20px; text-align: center; background: #1c2a25; color: #fffdf8; border-radius: 999px; font-size: 12px; margin-right: 6px; }
|
|
275
|
+
.tier { color: #5b6f66; font-size: 12px; }
|
|
276
|
+
.optout { margin-top: 24px; padding: 12px 14px; border: 1px dashed #e2dcc9; border-radius: 8px; font-size: 13px; color: #5b6f66; }
|
|
277
|
+
footer { margin-top: 20px; color: #8a9a91; font-size: 12px; }
|
|
278
|
+
</style></head><body><div class="card">
|
|
279
|
+
<h1>REVIEW needs a judge model</h1>
|
|
280
|
+
<div class="why">The REVIEW button runs an <strong>independent</strong> risk review of your session's work — a separate model (never the coding agent itself) reads the changes and reports risks. Right now no usable judge is configured:<br><br>
|
|
281
|
+
<code>backend: ${esc(opts.backend)}${opts.model ? ` · model: ${esc(opts.model)}` : ''}</code><br>
|
|
282
|
+
<code>${esc(opts.reason ?? 'not ready')}</code></div>
|
|
283
|
+
${detectedBlock}
|
|
284
|
+
<h2>All options <span class="tier">— ranked by review quality</span></h2>
|
|
285
|
+
<h2><span class="rank">1</span>Anthropic API <span class="tier">— best review quality (usage-billed, opt-in)</span></h2>
|
|
286
|
+
<pre>{ "apme": { "judge": { "backend": "api", "model": "claude-opus-4-8" } } }</pre>
|
|
287
|
+
<p style="font-size:13px">Credential: <code>export ANTHROPIC_API_KEY=…</code>, or <code>ant auth login</code>, or add <code>"apiKey"</code> next to the model. <code>claude-haiku-4-5</code> is the budget option if review volume is high.</p>
|
|
288
|
+
|
|
289
|
+
<h2><span class="rank">2</span>OpenRouter <span class="tier">— one key, hundreds of models (usage-billed)</span></h2>
|
|
290
|
+
<pre>{ "apme": { "judge": { "backend": "openai",
|
|
291
|
+
"endpoint": "https://openrouter.ai/api/v1",
|
|
292
|
+
"apiKey": "sk-or-…", "model": "anthropic/claude-opus-4" } } }</pre>
|
|
293
|
+
<p style="font-size:13px">If you already have an OpenRouter key. Any OpenAI-compatible cloud (Together, Groq, Fireworks, …) works the same way — set <code>endpoint</code> + <code>apiKey</code> + <code>model</code>.</p>
|
|
294
|
+
|
|
295
|
+
<h2><span class="rank">3</span>OpenClaw gateway <span class="tier">— strong quality via your existing subscription models</span></h2>
|
|
296
|
+
<pre>{ "apme": { "judge": { "backend": "openclaw" } } }</pre>
|
|
297
|
+
<p style="font-size:13px">Works when the OpenClaw gateway is connected in AgentDeck.</p>
|
|
298
|
+
|
|
299
|
+
<h2><span class="rank">4</span>Local Ollama / LM Studio / MLX <span class="tier">— free & private; needs a capable model</span></h2>
|
|
300
|
+
<pre># Ollama (default port)
|
|
301
|
+
{ "apme": { "judge": { "backend": "openai",
|
|
302
|
+
"endpoint": "http://127.0.0.1:11434/v1", "model": "qwen2.5-coder:32b" } } }</pre>
|
|
303
|
+
<p style="font-size:13px">Any local OpenAI-compatible server (Ollama :11434, LM Studio :1234, MLX, vLLM, llama.cpp). Realistic minimum is an <strong>8B-class instruct model</strong>; 30B-class recommended.</p>
|
|
304
|
+
|
|
305
|
+
<h2><span class="rank">5</span>Apple Intelligence <span class="tier">— free, on-device, basic screening only</span></h2>
|
|
306
|
+
<p style="font-size:13px">Available automatically when the AgentDeck macOS app runs with Apple Intelligence enabled (<code>backend: "foundationModels"</code>). Fine for a quick smoke check; the on-device model is small, so large changes may not fit — use one of the above for a thorough audit.</p>
|
|
307
|
+
|
|
308
|
+
<div class="optout">Not planning to use REVIEW? Nothing to do — the button stays, nothing runs in the background, and no popups will nag you. This page only appears when you press REVIEW without a judge.</div>
|
|
309
|
+
<footer>AgentDeck independent review · settings.json path: <code>~/.agentdeck/settings.json</code> (or the app's sandbox container) · details: docs/apme.md</footer>
|
|
310
|
+
</div></body></html>`;
|
|
311
|
+
}
|
|
312
|
+
function openInBrowser(path) {
|
|
313
|
+
const opener = process.platform === 'darwin' ? 'open'
|
|
314
|
+
: process.platform === 'win32' ? 'cmd'
|
|
315
|
+
: 'xdg-open';
|
|
316
|
+
const args = process.platform === 'win32' ? ['/c', 'start', '', path] : [path];
|
|
317
|
+
execFile(opener, args, { timeout: 5_000 }, () => { });
|
|
318
|
+
}
|
|
319
|
+
export async function runSessionReview(opts) {
|
|
320
|
+
const { sessionId, cwd, projectName } = opts;
|
|
321
|
+
if (isReviewRunning(sessionId))
|
|
322
|
+
return;
|
|
323
|
+
stateBySession.set(sessionId, { status: 'running', ts: Date.now() });
|
|
324
|
+
opts.onEvent({ type: 'review_status', sessionId, status: 'running' });
|
|
325
|
+
const fail = (message) => {
|
|
326
|
+
stateBySession.set(sessionId, { status: 'error', ts: Date.now() });
|
|
327
|
+
opts.onEvent({ type: 'review_status', sessionId, status: 'error', message });
|
|
328
|
+
debug('review', `review failed for ${sessionId}: ${message}`);
|
|
329
|
+
};
|
|
330
|
+
try {
|
|
331
|
+
// Judge preflight FIRST — the most common setup gap, and the one with an
|
|
332
|
+
// actionable fix. When no usable judge exists, open the setup guide in
|
|
333
|
+
// the browser (the same channel the report uses) instead of a bare error.
|
|
334
|
+
const judgeCfg = loadApmeConfig().judge;
|
|
335
|
+
const probe = await probeJudgeBackend(judgeCfg);
|
|
336
|
+
if (probe.status !== 'ready') {
|
|
337
|
+
try {
|
|
338
|
+
// Offer the user's already-running local servers first.
|
|
339
|
+
const { detectLocalJudgeProviders } = await import('./apme/judge-detect.js');
|
|
340
|
+
const detected = await detectLocalJudgeProviders().catch(() => []);
|
|
341
|
+
const dir = reviewsDir();
|
|
342
|
+
mkdirSync(dir, { recursive: true });
|
|
343
|
+
const guidePath = join(dir, 'review-judge-setup.html');
|
|
344
|
+
writeFileSync(guidePath, renderJudgeGuidanceHtml({
|
|
345
|
+
backend: judgeCfg.backend,
|
|
346
|
+
model: judgeCfg.model,
|
|
347
|
+
reason: probe.reason,
|
|
348
|
+
detected,
|
|
349
|
+
}));
|
|
350
|
+
openInBrowser(guidePath);
|
|
351
|
+
}
|
|
352
|
+
catch (err) {
|
|
353
|
+
logError(`[review] guidance write failed: ${String(err)}`);
|
|
354
|
+
}
|
|
355
|
+
return fail(`no usable judge (${judgeCfg.backend}: ${probe.reason ?? 'not ready'}) — setup guide opened in browser`);
|
|
356
|
+
}
|
|
357
|
+
if (!cwd)
|
|
358
|
+
return fail('session working directory unknown');
|
|
359
|
+
// Tier decides the diff budget and the prompt shape (basic = on-device
|
|
360
|
+
// FM relay with a small context; advanced = server/frontier judges).
|
|
361
|
+
const tier = reviewJudgeTier(judgeCfg.backend);
|
|
362
|
+
const delta = await collectDelta(cwd, tier === 'basic' ? BASIC_DIFF_BYTE_CAP : DIFF_BYTE_CAP);
|
|
363
|
+
if (!delta)
|
|
364
|
+
return fail(`not a git repository: ${cwd}`);
|
|
365
|
+
if (!delta.diff.trim() && delta.untracked.length === 0) {
|
|
366
|
+
return fail('working tree is clean — nothing to review');
|
|
367
|
+
}
|
|
368
|
+
const prompt = buildJudgePrompt(projectName, delta, tier, opts.recentActivity);
|
|
369
|
+
const result = await callJudgeWithMeta(prompt, judgeCfg);
|
|
370
|
+
const parsed = parseJudgeJson(result.text);
|
|
371
|
+
if (!parsed)
|
|
372
|
+
return fail(`judge returned unparseable output (${result.effectiveLabel})`);
|
|
373
|
+
const outcome = { ...parsed, backend: result.effectiveLabel };
|
|
374
|
+
// HTML report + browser open — the CLI tier's "popup".
|
|
375
|
+
let reportPath;
|
|
376
|
+
try {
|
|
377
|
+
const dir = reviewsDir();
|
|
378
|
+
mkdirSync(dir, { recursive: true });
|
|
379
|
+
reportPath = join(dir, `review-${Date.now()}-${projectName.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 40)}.html`);
|
|
380
|
+
writeFileSync(reportPath, renderReviewHtml({
|
|
381
|
+
projectName,
|
|
382
|
+
sessionLabel: sessionId,
|
|
383
|
+
outcome,
|
|
384
|
+
deltaStat: delta.stat,
|
|
385
|
+
generatedAt: new Date(),
|
|
386
|
+
tierNote: judgeTierNote(judgeCfg.backend),
|
|
387
|
+
}));
|
|
388
|
+
openInBrowser(reportPath);
|
|
389
|
+
}
|
|
390
|
+
catch (err) {
|
|
391
|
+
logError(`[review] report write failed: ${String(err)}`);
|
|
392
|
+
}
|
|
393
|
+
stateBySession.set(sessionId, {
|
|
394
|
+
status: 'done', risk: outcome.risk, findings: outcome.findings.length, ts: Date.now(),
|
|
395
|
+
});
|
|
396
|
+
// Manual reviews and the automatic APME pipeline share one purpose — so
|
|
397
|
+
// record this into the same eval store, flagged manual_review.
|
|
398
|
+
try {
|
|
399
|
+
const score = outcome.risk === 'high' ? 0 : outcome.risk === 'medium' ? 0.5 : 1;
|
|
400
|
+
opts.recordEval?.({
|
|
401
|
+
sessionId, risk: outcome.risk, score,
|
|
402
|
+
summary: outcome.summary, findings: outcome.findings.length,
|
|
403
|
+
judgeModel: outcome.backend,
|
|
404
|
+
raw: JSON.stringify({ risk: outcome.risk, summary: outcome.summary, findings: outcome.findings }),
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
catch (err) {
|
|
408
|
+
logError(`[review] eval record failed: ${String(err)}`);
|
|
409
|
+
}
|
|
410
|
+
opts.onEvent({
|
|
411
|
+
type: 'review_result',
|
|
412
|
+
sessionId,
|
|
413
|
+
risk: outcome.risk,
|
|
414
|
+
findings: outcome.findings.length,
|
|
415
|
+
summary: outcome.summary,
|
|
416
|
+
...(reportPath ? { reportPath } : {}),
|
|
417
|
+
});
|
|
418
|
+
debug('review', `review done for ${sessionId}: risk=${outcome.risk} findings=${outcome.findings.length} backend=${outcome.backend}`);
|
|
419
|
+
}
|
|
420
|
+
catch (err) {
|
|
421
|
+
fail(String(err));
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
/** Test helper. */
|
|
425
|
+
export function _resetReviewState() {
|
|
426
|
+
stateBySession.clear();
|
|
427
|
+
}
|
|
428
|
+
//# sourceMappingURL=review-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-runner.js","sourceRoot":"","sources":["../src/review-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { EnrichedSession } from './session-aggregator.js';
|
|
2
|
+
/** Synchronous, always-available clean one-liner. */
|
|
3
|
+
export declare function quickActivity(s: EnrichedSession): string | undefined;
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the per-session activity line. Returns the cached FM summary when it
|
|
6
|
+
* matches the current session signature, else the synchronous heuristic — and
|
|
7
|
+
* kicks off an async FM summarization whose result surfaces on a later broadcast.
|
|
8
|
+
*/
|
|
9
|
+
export declare function activityFor(s: EnrichedSession): string | undefined;
|
|
10
|
+
/** Drop a session's cached summary (call on session removal). */
|
|
11
|
+
export declare function clearSessionActivity(sessionId: string): void;
|
|
12
|
+
/** Test seam — reset FM availability + cache. */
|
|
13
|
+
export declare function resetSessionActivityForTests(): void;
|
|
14
|
+
//# sourceMappingURL=session-activity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-activity.d.ts","sourceRoot":"","sources":["../src/session-activity.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AA8B/D,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,GAAG,SAAS,CAmBpE;AAgED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,GAAG,SAAS,CAMlE;AAED,iEAAiE;AACjE,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAG5D;AAED,iDAAiD;AACjD,wBAAgB,4BAA4B,IAAI,IAAI,CAInD"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// session-activity.ts — per-session "what is this agent doing right now" one-liner.
|
|
2
|
+
//
|
|
3
|
+
// A single shared source so glance surfaces (XTeink X3 rows, TRMNL list) render
|
|
4
|
+
// the same clean, natural-language text instead of a raw tool path. Two layers:
|
|
5
|
+
//
|
|
6
|
+
// 1. quickActivity() — synchronous heuristic (clean current action). Always
|
|
7
|
+
// available, instant, used for the immediate broadcast.
|
|
8
|
+
// 2. Foundation Models upgrade — when the macOS 26+ FM helper is reachable
|
|
9
|
+
// (bundled in the @agentdeck/bridge package, NOT the App Store target), the
|
|
10
|
+
// current action is rephrased into a short natural-language summary, cached
|
|
11
|
+
// per session and surfaced on the NEXT periodic sessions_list broadcast (no
|
|
12
|
+
// explicit re-broadcast needed). Falls back to the heuristic when FM is
|
|
13
|
+
// unavailable or errors. Cost-free (on-device), see feedback_cost_sensitive_defaults.
|
|
14
|
+
//
|
|
15
|
+
import { callFoundationModelsHelper, probeFoundationModelsHelper } from './foundation-models-helper.js';
|
|
16
|
+
import { stripUnsafeText } from '@agentdeck/shared';
|
|
17
|
+
import { debug } from './logger.js';
|
|
18
|
+
/** "Edit /a/b/c.ts" → "Edit c.ts"; "Bash cd /x; rm…" → "Bash cd…". Mirrors
|
|
19
|
+
* cleanAction in shared/src/trmnl-layout.ts (kept local to avoid a cross-package
|
|
20
|
+
* export churn while that file is under active concurrent edit). */
|
|
21
|
+
function cleanAction(raw) {
|
|
22
|
+
const s = raw.trim();
|
|
23
|
+
if (!s)
|
|
24
|
+
return '';
|
|
25
|
+
const sp = s.indexOf(' ');
|
|
26
|
+
if (sp < 0)
|
|
27
|
+
return s;
|
|
28
|
+
const verb = s.slice(0, sp);
|
|
29
|
+
const rest = s.slice(sp + 1).trim();
|
|
30
|
+
const firstTok = rest.split(/\s+/)[0] || '';
|
|
31
|
+
if (firstTok.includes('/')) {
|
|
32
|
+
const base = firstTok.split('/').filter(Boolean).pop() || firstTok;
|
|
33
|
+
return `${verb} ${base}`;
|
|
34
|
+
}
|
|
35
|
+
return rest.length > 22 ? `${verb} ${rest.slice(0, 21)}…` : `${verb} ${rest}`;
|
|
36
|
+
}
|
|
37
|
+
/** Tool name → present-continuous verb for a natural reading. */
|
|
38
|
+
function verbForm(tool) {
|
|
39
|
+
const map = {
|
|
40
|
+
Edit: 'Editing', MultiEdit: 'Editing', Write: 'Writing', NotebookEdit: 'Editing',
|
|
41
|
+
Read: 'Reading', Bash: 'Running', Grep: 'Searching', Glob: 'Finding',
|
|
42
|
+
Task: 'Delegating', WebFetch: 'Fetching', WebSearch: 'Searching', TodoWrite: 'Planning',
|
|
43
|
+
};
|
|
44
|
+
return map[tool] ?? tool;
|
|
45
|
+
}
|
|
46
|
+
/** Synchronous, always-available clean one-liner. */
|
|
47
|
+
export function quickActivity(s) {
|
|
48
|
+
const state = s.state ?? '';
|
|
49
|
+
// Strip PTY escape/control bytes first — a raw ESC in these strings used to
|
|
50
|
+
// break the SVG parse downstream and blank the TRMNL/D200H frame.
|
|
51
|
+
if (state.startsWith('awaiting') && s.question && s.question.trim()) {
|
|
52
|
+
return stripUnsafeText(s.question.trim()).slice(0, 72);
|
|
53
|
+
}
|
|
54
|
+
// currentTask, when present, is the full "Verb /path" action — clean the path off.
|
|
55
|
+
const task = stripUnsafeText((s.currentTask ?? '').trim());
|
|
56
|
+
if (task) {
|
|
57
|
+
const cleaned = cleanAction(task);
|
|
58
|
+
// If it's "Verb basename", prefer the present-continuous verb.
|
|
59
|
+
const sp = cleaned.indexOf(' ');
|
|
60
|
+
if (sp > 0)
|
|
61
|
+
return `${verbForm(cleaned.slice(0, sp))} ${cleaned.slice(sp + 1)}`;
|
|
62
|
+
return cleaned;
|
|
63
|
+
}
|
|
64
|
+
if (s.currentTool && s.currentTool.trim())
|
|
65
|
+
return verbForm(stripUnsafeText(s.currentTool.trim()));
|
|
66
|
+
if (s.goal && s.goal.trim())
|
|
67
|
+
return cleanAction(stripUnsafeText(s.goal.trim()));
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
const cache = new Map();
|
|
71
|
+
const inflight = new Set();
|
|
72
|
+
let fmAvailable = null; // null = not yet probed
|
|
73
|
+
const MIN_SUMMARIZE_INTERVAL_MS = 15_000;
|
|
74
|
+
function signature(s) {
|
|
75
|
+
return [s.state, s.currentTool, s.currentTask, s.question, s.goal].map((v) => v ?? '').join('|');
|
|
76
|
+
}
|
|
77
|
+
const FM_INSTRUCTIONS = 'You label a coding agent\'s current work for a tiny status display. Reply with ONE short ' +
|
|
78
|
+
'present-tense phrase (max 8 words, no period, no quotes) describing what the agent is doing, ' +
|
|
79
|
+
'e.g. "Editing the auth module" or "Running the test suite". English only.';
|
|
80
|
+
function buildContext(s) {
|
|
81
|
+
const parts = [];
|
|
82
|
+
if (s.projectName)
|
|
83
|
+
parts.push(`Project: ${s.projectName}`);
|
|
84
|
+
if (s.agentType)
|
|
85
|
+
parts.push(`Agent: ${s.agentType}`);
|
|
86
|
+
if (s.currentTool)
|
|
87
|
+
parts.push(`Current tool: ${s.currentTool}`);
|
|
88
|
+
if (s.currentTask)
|
|
89
|
+
parts.push(`Action: ${s.currentTask}`);
|
|
90
|
+
if (s.goal)
|
|
91
|
+
parts.push(`Goal: ${s.goal}`);
|
|
92
|
+
if (s.state?.startsWith('awaiting') && s.question)
|
|
93
|
+
parts.push(`Awaiting answer to: ${s.question}`);
|
|
94
|
+
return parts.join('\n');
|
|
95
|
+
}
|
|
96
|
+
function sanitize(text) {
|
|
97
|
+
const t = text.replace(/^["'\s]+|["'\s.]+$/g, '').replace(/\s+/g, ' ').trim();
|
|
98
|
+
if (!t)
|
|
99
|
+
return undefined;
|
|
100
|
+
return t.length > 72 ? `${t.slice(0, 71)}…` : t;
|
|
101
|
+
}
|
|
102
|
+
/** Fire-and-forget FM summarization; result lands in `cache` for the next broadcast. */
|
|
103
|
+
function maybeSummarize(s) {
|
|
104
|
+
const sig = signature(s);
|
|
105
|
+
const existing = cache.get(s.id);
|
|
106
|
+
if (existing && existing.sig === sig)
|
|
107
|
+
return; // already current
|
|
108
|
+
if (existing && Date.now() - existing.at < MIN_SUMMARIZE_INTERVAL_MS)
|
|
109
|
+
return; // debounce churn
|
|
110
|
+
if (inflight.has(s.id))
|
|
111
|
+
return;
|
|
112
|
+
// Nothing meaningful to summarize → don't spin up FM.
|
|
113
|
+
if (!s.currentTool && !s.currentTask && !s.goal && !(s.state?.startsWith('awaiting')))
|
|
114
|
+
return;
|
|
115
|
+
inflight.add(s.id);
|
|
116
|
+
void (async () => {
|
|
117
|
+
try {
|
|
118
|
+
if (fmAvailable === null)
|
|
119
|
+
fmAvailable = (await probeFoundationModelsHelper()).available;
|
|
120
|
+
if (!fmAvailable) {
|
|
121
|
+
cache.set(s.id, { sig, summary: undefined, at: Date.now() }); // mark probed; heuristic wins
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const text = await callFoundationModelsHelper(buildContext(s), FM_INSTRUCTIONS);
|
|
125
|
+
cache.set(s.id, { sig, summary: sanitize(text), at: Date.now() });
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
debug('APME', `session-activity FM summarize failed sid=${s.id.slice(0, 16)}: ${String(err).slice(0, 120)}`);
|
|
129
|
+
cache.set(s.id, { sig, summary: undefined, at: Date.now() });
|
|
130
|
+
}
|
|
131
|
+
finally {
|
|
132
|
+
inflight.delete(s.id);
|
|
133
|
+
}
|
|
134
|
+
})();
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Resolve the per-session activity line. Returns the cached FM summary when it
|
|
138
|
+
* matches the current session signature, else the synchronous heuristic — and
|
|
139
|
+
* kicks off an async FM summarization whose result surfaces on a later broadcast.
|
|
140
|
+
*/
|
|
141
|
+
export function activityFor(s) {
|
|
142
|
+
const quick = quickActivity(s);
|
|
143
|
+
const cached = cache.get(s.id);
|
|
144
|
+
maybeSummarize(s);
|
|
145
|
+
if (cached && cached.sig === signature(s) && cached.summary)
|
|
146
|
+
return cached.summary;
|
|
147
|
+
return quick;
|
|
148
|
+
}
|
|
149
|
+
/** Drop a session's cached summary (call on session removal). */
|
|
150
|
+
export function clearSessionActivity(sessionId) {
|
|
151
|
+
cache.delete(sessionId);
|
|
152
|
+
inflight.delete(sessionId);
|
|
153
|
+
}
|
|
154
|
+
/** Test seam — reset FM availability + cache. */
|
|
155
|
+
export function resetSessionActivityForTests() {
|
|
156
|
+
cache.clear();
|
|
157
|
+
inflight.clear();
|
|
158
|
+
fmAvailable = null;
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=session-activity.js.map
|