@agentprojectcontext/apx 1.80.2 → 1.89.1
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/package.json +9 -8
- package/skills/apc-context/SKILL.md +14 -7
- package/skills/apx/SKILL.md +62 -2
- package/skills/apx-mcp/SKILL.md +42 -15
- package/src/core/agent/a2a/peers.js +161 -0
- package/src/core/agent/a2a/reply.js +379 -27
- package/src/core/agent/abort.js +25 -0
- package/src/core/agent/agent-model.js +58 -0
- package/src/core/agent/agent-tools.js +101 -0
- package/src/core/agent/author-line.js +110 -0
- package/src/core/agent/build-agent-system.js +52 -18
- package/src/core/agent/channels/voice-context.js +17 -2
- package/src/core/agent/closing-floor.js +117 -0
- package/src/core/agent/constants.js +119 -11
- package/src/core/agent/engine-call.js +56 -0
- package/src/core/agent/group/run-group-turn.js +218 -0
- package/src/core/agent/group/turn-resolver.js +165 -0
- package/src/core/agent/judge.js +138 -11
- package/src/core/agent/loop/side-effects.js +106 -3
- package/src/core/agent/memory.js +31 -18
- package/src/core/agent/model-capabilities.js +47 -0
- package/src/core/agent/model-router.js +11 -40
- package/src/core/agent/prompt-builder.js +47 -0
- package/src/core/agent/prompts/channels/a2a.md +12 -0
- package/src/core/agent/prompts/channels/code.md +3 -1
- package/src/core/agent/prompts/channels/telegram.md +2 -0
- package/src/core/agent/prompts/channels/web_code.md +1 -1
- package/src/core/agent/prompts/channels/whatsapp.md +37 -0
- package/src/core/agent/prompts/core/agent-base.md +2 -0
- package/src/core/agent/prompts/discipline/action.md +1 -0
- package/src/core/agent/prompts/discipline/two-segment.md +2 -1
- package/src/core/agent/prompts/modes/mobility.md +36 -0
- package/src/core/agent/retry.js +42 -0
- package/src/core/agent/run-agent.js +322 -25
- package/src/core/agent/run-turn.js +253 -0
- package/src/core/agent/self-memory.js +18 -52
- package/src/core/agent/skills/agent-skills.js +118 -0
- package/src/core/agent/skills/catalog.js +1 -1
- package/src/core/agent/skills/declared.js +13 -0
- package/src/core/agent/skills/index-store.js +8 -1
- package/src/core/agent/skills/inspector.js +20 -3
- package/src/core/agent/skills/loader.js +18 -3
- package/src/core/agent/skills/media.js +121 -0
- package/src/core/agent/skills/origin.js +61 -0
- package/src/core/agent/skills/sections.js +136 -0
- package/src/core/agent/super-agent.js +54 -14
- package/src/core/agent/tools/handlers/_calendar.js +50 -0
- package/src/core/agent/tools/handlers/add-mcp.js +103 -0
- package/src/core/agent/tools/handlers/asana-create-task.js +3 -1
- package/src/core/agent/tools/handlers/attach-media.js +56 -0
- package/src/core/agent/tools/handlers/calendar-create-event.js +38 -0
- package/src/core/agent/tools/handlers/calendar-find-slot.js +39 -0
- package/src/core/agent/tools/handlers/calendar-list-events.js +39 -0
- package/src/core/agent/tools/handlers/calendar-update-event.js +35 -0
- package/src/core/agent/tools/handlers/call-agent.js +14 -6
- package/src/core/agent/tools/handlers/call-runtime.js +27 -49
- package/src/core/agent/tools/handlers/comment-task.js +78 -0
- package/src/core/agent/tools/handlers/complete-task.js +60 -0
- package/src/core/agent/tools/handlers/configure-agent.js +70 -0
- package/src/core/agent/tools/handlers/create-agent.js +68 -0
- package/src/core/agent/tools/handlers/create-task.js +41 -3
- package/src/core/agent/tools/handlers/import-agent.js +5 -5
- package/src/core/agent/tools/handlers/list-mcp-tools.js +83 -0
- package/src/core/agent/tools/handlers/list-routines.js +46 -0
- package/src/core/agent/tools/handlers/list-tasks.js +8 -1
- package/src/core/agent/tools/handlers/mark-commitment.js +57 -0
- package/src/core/agent/tools/handlers/read-skill.js +64 -0
- package/src/core/agent/tools/handlers/remember-routine.js +2 -8
- package/src/core/agent/tools/handlers/remember.js +82 -6
- package/src/core/agent/tools/handlers/remove-agent.js +42 -0
- package/src/core/agent/tools/handlers/run-routine.js +94 -0
- package/src/core/agent/tools/handlers/run-shell.js +44 -2
- package/src/core/agent/tools/handlers/send-telegram.js +41 -19
- package/src/core/agent/tools/handlers/set-agent-prompt.js +44 -0
- package/src/core/agent/tools/handlers/view-media.js +69 -0
- package/src/core/agent/tools/handlers/write-agent-memory.js +52 -0
- package/src/core/agent/tools/helpers.js +36 -4
- package/src/core/agent/tools/names.js +64 -0
- package/src/core/agent/tools/registry-bridge.js +24 -1
- package/src/core/agent/tools/registry.js +79 -0
- package/src/core/agent/tools/tool-call-parser.js +136 -13
- package/src/core/agent/vision-bridge.js +69 -0
- package/src/core/apc/agent-identity.js +74 -0
- package/src/core/apc/agent-rename-refs.js +187 -0
- package/src/core/apc/agent-write.js +312 -0
- package/src/core/apc/agents-vault.js +1 -1
- package/src/core/apc/blob-keys.js +42 -0
- package/src/core/apc/frontmatter.js +166 -10
- package/src/core/apc/parser.js +33 -83
- package/src/core/apc/paths.js +4 -6
- package/src/core/apc/project-memory.js +44 -0
- package/src/core/apc/projects-helpers.js +33 -0
- package/src/core/apc/scaffold.js +36 -16
- package/src/core/channels/telegram/ask-callbacks.js +103 -0
- package/src/core/channels/telegram/dispatch.js +154 -30
- package/src/core/channels/telegram/helpers.js +59 -7
- package/src/core/channels/telegram/inbound/audio.js +26 -30
- package/src/core/channels/telegram/inbound/file.js +22 -32
- package/src/core/channels/telegram/inbound/photo.js +24 -28
- package/src/core/channels/telegram/progress-gate.js +76 -0
- package/src/core/channels/telegram/reply.js +151 -43
- package/src/core/channels/telegram/voice-note.js +150 -0
- package/src/core/config/index.js +53 -54
- package/src/core/config/paths.js +117 -31
- package/src/core/config/redact.js +89 -4
- package/src/core/config/secret-values.js +2 -4
- package/src/core/constants/actors.js +5 -0
- package/src/core/constants/channels.js +3 -1
- package/src/core/constants/task-categories.js +73 -0
- package/src/core/constants/task-fields.js +28 -0
- package/src/core/engines/_globs.js +33 -0
- package/src/core/engines/anthropic.js +19 -1
- package/src/core/engines/catalog.js +20 -0
- package/src/core/engines/gemini.js +84 -16
- package/src/core/engines/index.js +19 -3
- package/src/core/engines/mock.js +145 -1
- package/src/core/engines/openai-compatible.js +150 -15
- package/src/core/engines/presets.js +36 -9
- package/src/core/engines/zen.js +131 -0
- package/src/core/events/bus.js +140 -0
- package/src/core/events/mascot-notify.js +156 -0
- package/src/core/http-tools/browser.js +366 -36
- package/src/core/http-tools/catalog.js +206 -22
- package/src/core/http-tools/grep.js +62 -7
- package/src/core/http-tools/registry.js +3 -1
- package/src/core/i18n/en.js +34 -3
- package/src/core/i18n/es.js +36 -4
- package/src/core/i18n/index.js +5 -5
- package/src/core/i18n/pt.js +32 -3
- package/src/core/identity/self.js +14 -1
- package/src/core/images/engines/a1111.js +219 -0
- package/src/core/images/engines/index.js +187 -0
- package/src/core/images/engines/mock.js +74 -0
- package/src/core/images/engines/openai.js +130 -0
- package/src/core/images/engines/sdcpp.js +204 -0
- package/src/core/images/engines/shared.js +218 -0
- package/src/core/images/generate.js +260 -0
- package/src/core/integrations/catalog.js +8 -3
- package/src/core/integrations/plugins/_google-oauth.js +179 -0
- package/src/core/integrations/plugins/asana.js +7 -3
- package/src/core/integrations/plugins/calendar.js +404 -0
- package/src/core/integrations/store.js +2 -0
- package/src/core/memory/broker.js +16 -1
- package/src/core/memory/compactor.js +19 -3
- package/src/core/memory/consolidate.js +2 -2
- package/src/core/memory/dated-log.js +66 -0
- package/src/core/memory/embed-engines/custom.js +59 -0
- package/src/core/memory/embed-engines/gemini.js +9 -3
- package/src/core/memory/embed-engines/index.js +87 -15
- package/src/core/memory/embeddings.js +52 -24
- package/src/core/memory/index.js +13 -3
- package/src/core/memory/indexer.js +83 -27
- package/src/core/memory/prune.js +182 -0
- package/src/core/memory/store.js +22 -0
- package/src/core/memory/summarizer.js +72 -8
- package/src/core/mobility/answer.js +80 -0
- package/src/core/mobility/geofence.js +667 -0
- package/src/core/mobility/osm-route.js +282 -0
- package/src/core/mobility/preferences.js +91 -0
- package/src/core/mobility/state.js +245 -0
- package/src/core/mobility/trip-event.js +384 -0
- package/src/core/net/tailscale.js +168 -0
- package/src/core/profiles/bundled/secretary/PROFILE.md +32 -42
- package/src/core/profiles/bundled/secretary/config.schema.es.json +68 -0
- package/src/core/profiles/bundled/secretary/config.schema.json +30 -2
- package/src/core/profiles/bundled/secretary/profile.json +3 -1
- package/src/core/profiles/bundled/secretary/routines/a2a-sweep.json +20 -0
- package/src/core/profiles/bundled/secretary/routines/day-close.json +4 -1
- package/src/core/profiles/bundled/secretary/routines/day-open.json +7 -1
- package/src/core/profiles/bundled/secretary/routines/watch.json +13 -2
- package/src/core/profiles/lifecycle.js +243 -19
- package/src/core/profiles/paths.js +12 -0
- package/src/core/profiles/store.js +47 -0
- package/src/core/routines/active-runs.js +213 -0
- package/src/core/routines/delivery.js +612 -0
- package/src/core/routines/header.js +88 -0
- package/src/core/routines/index.js +26 -0
- package/src/core/routines/run-log.js +78 -0
- package/src/core/routines/runner.js +629 -66
- package/src/core/routines/signals.js +75 -0
- package/src/core/runtime-skills/apc-context/SKILL.md +14 -7
- package/src/core/runtime-skills/apx/SKILL.md +93 -1
- package/src/core/runtime-skills/apx-agency-agents/SKILL.md +2 -2
- package/src/core/runtime-skills/apx-agent/SKILL.md +134 -19
- package/src/core/runtime-skills/apx-commitment/SKILL.md +134 -0
- package/src/core/runtime-skills/apx-image/SKILL.md +60 -0
- package/src/core/runtime-skills/apx-integrations/SKILL.md +82 -0
- package/src/core/runtime-skills/apx-mcp/SKILL.md +45 -14
- package/src/core/runtime-skills/apx-mcp-builder/SKILL.md +4 -4
- package/src/core/runtime-skills/apx-profile/SKILL.md +27 -2
- package/src/core/runtime-skills/apx-project/SKILL.md +23 -2
- package/src/core/runtime-skills/apx-routine/SKILL.md +40 -17
- package/src/core/runtime-skills/apx-runtime/SKILL.md +124 -14
- package/src/core/runtime-skills/apx-sessions/SKILL.md +7 -6
- package/src/core/runtime-skills/apx-skill-builder/SKILL.md +15 -13
- package/src/core/runtime-skills/apx-task/SKILL.md +79 -26
- package/src/core/runtime-skills/apx-telegram/SKILL.md +12 -12
- package/src/core/runtime-skills/apx-transcribe/SKILL.md +56 -0
- package/src/core/runtime-skills/apx-voice/SKILL.md +27 -8
- package/src/core/runtime-skills/claude-code/SKILL.md +8 -0
- package/src/core/runtime-skills/openrouter/SKILL.md +8 -2
- package/src/core/runtimes/_spawn.js +9 -1
- package/src/core/runtimes/claude-code.js +11 -2
- package/src/core/runtimes/codex.js +44 -10
- package/src/core/runtimes/index.js +17 -2
- package/src/core/runtimes/opencode.js +88 -9
- package/src/core/runtimes/outcome.js +119 -0
- package/src/core/sessions/index.js +193 -1
- package/src/core/stores/agent-inbox.js +109 -23
- package/src/core/stores/code-sessions.js +21 -0
- package/src/core/stores/commitments.js +27 -3
- package/src/core/stores/conversations.js +220 -20
- package/src/core/stores/deliveries.js +177 -0
- package/src/core/stores/media-archive.js +228 -0
- package/src/core/stores/messages.js +1096 -112
- package/src/core/stores/organization.js +34 -0
- package/src/core/stores/project-memory.js +71 -0
- package/src/core/stores/routine-memory.js +16 -8
- package/src/core/stores/routines.js +27 -49
- package/src/core/stores/sessions.js +4 -8
- package/src/core/stores/tasks.js +212 -18
- package/src/core/stores/turn-record.js +209 -0
- package/src/core/tasks/columns.js +136 -0
- package/src/core/tasks/comment-turn.js +258 -0
- package/src/core/util/time.js +13 -0
- package/src/core/voice/engines/index.js +54 -1
- package/src/core/voice/engines/openai.js +50 -4
- package/src/core/voice/opus.js +67 -0
- package/src/core/voice/pronounceable.js +43 -0
- package/src/core/voice/transcription.js +4 -0
- package/src/core/voice/tts.js +114 -24
- package/src/host/daemon/active-turns.js +188 -0
- package/src/host/daemon/api/admin-config.js +9 -0
- package/src/host/daemon/api/agents.js +99 -90
- package/src/host/daemon/api/artifact-preview.js +7 -6
- package/src/host/daemon/api/artifacts.js +3 -2
- package/src/host/daemon/api/code.js +55 -9
- package/src/host/daemon/api/commitments.js +11 -0
- package/src/host/daemon/api/confirm.js +3 -2
- package/src/host/daemon/api/conversations.js +543 -35
- package/src/host/daemon/api/deck.js +9 -8
- package/src/host/daemon/api/deliveries.js +33 -0
- package/src/host/daemon/api/desktop.js +5 -4
- package/src/host/daemon/api/embeddings.js +15 -6
- package/src/host/daemon/api/engines.js +59 -8
- package/src/host/daemon/api/exec.js +437 -121
- package/src/host/daemon/api/groups.js +215 -0
- package/src/host/daemon/api/images.js +107 -0
- package/src/host/daemon/api/inbox.js +123 -2
- package/src/host/daemon/api/integrations.js +64 -2
- package/src/host/daemon/api/mcps.js +7 -6
- package/src/host/daemon/api/media.js +283 -0
- package/src/host/daemon/api/mobility.js +177 -0
- package/src/host/daemon/api/net.js +182 -0
- package/src/host/daemon/api/pairing.js +38 -5
- package/src/host/daemon/api/profiles.js +30 -2
- package/src/host/daemon/api/routines.js +36 -4
- package/src/host/daemon/api/runtimes.js +74 -39
- package/src/host/daemon/api/sessions-search.js +7 -2
- package/src/host/daemon/api/sessions.js +44 -2
- package/src/host/daemon/api/shared.js +127 -20
- package/src/host/daemon/api/skills.js +11 -4
- package/src/host/daemon/api/super-agent.js +384 -53
- package/src/host/daemon/api/tasks.js +180 -10
- package/src/host/daemon/api/telegram.js +11 -10
- package/src/host/daemon/api/thread-faces.js +159 -0
- package/src/host/daemon/api/top-level.js +3 -3
- package/src/host/daemon/api/transcribe.js +11 -10
- package/src/host/daemon/api/tts.js +97 -4
- package/src/host/daemon/api/turn-abort.js +23 -0
- package/src/host/daemon/api/turns.js +49 -0
- package/src/host/daemon/api/voice.js +5 -4
- package/src/host/daemon/api/web.js +98 -0
- package/src/host/daemon/api.js +39 -0
- package/src/host/daemon/delivery-sweep.js +58 -0
- package/src/host/daemon/desktop-ws.js +5 -23
- package/src/host/daemon/events-ws.js +273 -0
- package/src/host/daemon/index.js +59 -15
- package/src/host/daemon/plugins/desktop/index.js +17 -4
- package/src/host/daemon/plugins/telegram/index.js +78 -40
- package/src/host/daemon/pty-bridge.py +99 -0
- package/src/host/daemon/routines-scheduler.js +1 -0
- package/src/host/daemon/smoke.js +1 -2
- package/src/host/daemon/terminal-ws.js +132 -0
- package/src/host/daemon/tts-keepwarm.js +87 -0
- package/src/host/daemon/wakeup.js +11 -6
- package/src/host/daemon/whisper-server.js +44 -0
- package/src/host/daemon/whisper-server.py +70 -13
- package/src/host/daemon/ws-auth.js +28 -0
- package/src/interfaces/android/app/build.gradle +42 -0
- package/src/interfaces/android/app/proguard-rules.pro +4 -0
- package/src/interfaces/android/app/src/main/AndroidManifest.xml +139 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/AlertScreen.java +139 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/AndroidAutoDetector.java +106 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ApxCarAppService.java +57 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ApxPreferences.java +165 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/CarAlertStore.java +84 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/CarMessageActionReceiver.java +47 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/CarMessageNotification.java +152 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/DaemonAddress.java +35 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/DaemonClient.java +339 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/DeviceLocation.java +38 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ErrandScreen.java +127 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MainActivity.java +872 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MapsNavigationDetector.java +63 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MapsNavigationListenerService.java +453 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MapsShareIntentParser.java +93 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MascotBlobCatalog.java +66 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MascotOverlayService.java +448 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MascotView.java +249 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MessageFrameParser.java +240 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/NotifyChannels.java +69 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ProximityActionReceiver.java +78 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ProximityNotification.java +161 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/StartupReceiver.java +57 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TravelEventGate.java +62 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TravelStatusBanner.java +116 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TripLocationService.java +272 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TripPlacesSheet.java +203 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TripScreen.java +182 -0
- package/src/interfaces/android/app/src/main/res/drawable/app_background.xml +12 -0
- package/src/interfaces/android/app/src/main/res/drawable/ic_apx_app.xml +10 -0
- package/src/interfaces/android/app/src/main/res/drawable/ic_apx_launcher_foreground.xml +12 -0
- package/src/interfaces/android/app/src/main/res/drawable/ic_apx_notification.xml +22 -0
- package/src/interfaces/android/app/src/main/res/drawable/ic_trip_car.xml +37 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/apx_logo.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_amatista.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_aqua.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_brasa.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_campana.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_caracol.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_carbon.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_cobalto.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_cometa.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_coral.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_cubi.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_eclipse.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_faro.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_gajo.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_iris.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_kiwi.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_laguna.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_lila.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_menta.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_nimbo.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_noche.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_onyx.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_orbita.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_ovni.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_papa.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_parche.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_peon.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_perla.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_pino.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_quad.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_rubi.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_saturno.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_trebol.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_trino.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_volcan.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_zafiro.png +0 -0
- package/src/interfaces/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +5 -0
- package/src/interfaces/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +5 -0
- package/src/interfaces/android/app/src/main/res/raw/apx_notification.mp3 +0 -0
- package/src/interfaces/android/app/src/main/res/values/colors.xml +4 -0
- package/src/interfaces/android/app/src/main/res/values/strings.xml +25 -0
- package/src/interfaces/android/app/src/main/res/values/styles.xml +10 -0
- package/src/interfaces/android/app/src/main/res/values-v31/styles.xml +14 -0
- package/src/interfaces/android/app/src/main/res/xml/automotive_app_desc.xml +9 -0
- package/src/interfaces/android/app/src/main/res/xml/network_security_config.xml +10 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/AndroidAutoDetectorTest.java +85 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/CarAlertStoreTest.java +104 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/DaemonAddressTest.java +23 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/MapsNavigationDetectorTest.java +69 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/MapsShareIntentParserTest.java +31 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/MessageFrameParserTest.java +180 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/TravelEventGateTest.java +64 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/TripPlacesSheetTest.java +66 -0
- package/src/interfaces/android/build.gradle +3 -0
- package/src/interfaces/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/src/interfaces/android/gradle/wrapper/gradle-wrapper.properties +9 -0
- package/src/interfaces/android/gradle.properties +3 -0
- package/src/interfaces/android/gradlew +248 -0
- package/src/interfaces/android/gradlew.bat +82 -0
- package/src/interfaces/android/settings.gradle +18 -0
- package/src/interfaces/cli/commands/a2a.js +145 -4
- package/src/interfaces/cli/commands/agent.js +247 -22
- package/src/interfaces/cli/commands/code.js +1 -1
- package/src/interfaces/cli/commands/commitment.js +5 -0
- package/src/interfaces/cli/commands/config.js +85 -6
- package/src/interfaces/cli/commands/exec.js +90 -1
- package/src/interfaces/cli/commands/image.js +314 -0
- package/src/interfaces/cli/commands/mcp.js +87 -23
- package/src/interfaces/cli/commands/memory.js +35 -22
- package/src/interfaces/cli/commands/panel.js +94 -0
- package/src/interfaces/cli/commands/profile.js +14 -0
- package/src/interfaces/cli/commands/project.js +29 -0
- package/src/interfaces/cli/commands/routine.js +45 -10
- package/src/interfaces/cli/commands/runtime.js +30 -7
- package/src/interfaces/cli/commands/session.js +90 -38
- package/src/interfaces/cli/commands/sessions.js +35 -2
- package/src/interfaces/cli/commands/skills.js +15 -9
- package/src/interfaces/cli/commands/status.js +2 -3
- package/src/interfaces/cli/commands/task.js +54 -5
- package/src/interfaces/cli/commands/telegram.js +12 -4
- package/src/interfaces/cli/commands/transcribe.js +177 -0
- package/src/interfaces/cli/help/index.js +311 -72
- package/src/interfaces/cli/http.js +61 -13
- package/src/interfaces/cli/index.js +1 -1
- package/src/interfaces/cli/routes/agent.js +5 -4
- package/src/interfaces/cli/routes/commitment.js +3 -2
- package/src/interfaces/cli/routes/config.js +7 -2
- package/src/interfaces/cli/routes/image.js +11 -0
- package/src/interfaces/cli/routes/index.js +2 -0
- package/src/interfaces/cli/routes/log.js +1 -1
- package/src/interfaces/cli/routes/memory.js +3 -2
- package/src/interfaces/cli/routes/panel.js +15 -2
- package/src/interfaces/cli/routes/profile.js +3 -2
- package/src/interfaces/cli/routes/transcribe.js +10 -0
- package/src/interfaces/cli/stdin.js +29 -0
- package/src/interfaces/desktop/assets/blobs/amatista.png +0 -0
- package/src/interfaces/desktop/assets/blobs/aqua.png +0 -0
- package/src/interfaces/desktop/assets/blobs/brasa.png +0 -0
- package/src/interfaces/desktop/assets/blobs/campana.png +0 -0
- package/src/interfaces/desktop/assets/blobs/caracol.png +0 -0
- package/src/interfaces/desktop/assets/blobs/carbon.png +0 -0
- package/src/interfaces/desktop/assets/blobs/cobalto.png +0 -0
- package/src/interfaces/desktop/assets/blobs/cometa.png +0 -0
- package/src/interfaces/desktop/assets/blobs/coral.png +0 -0
- package/src/interfaces/desktop/assets/blobs/cubi.png +0 -0
- package/src/interfaces/desktop/assets/blobs/eclipse.png +0 -0
- package/src/interfaces/desktop/assets/blobs/faro.png +0 -0
- package/src/interfaces/desktop/assets/blobs/gajo.png +0 -0
- package/src/interfaces/desktop/assets/blobs/iris.png +0 -0
- package/src/interfaces/desktop/assets/blobs/kiwi.png +0 -0
- package/src/interfaces/desktop/assets/blobs/laguna.png +0 -0
- package/src/interfaces/desktop/assets/blobs/lila.png +0 -0
- package/src/interfaces/desktop/assets/blobs/menta.png +0 -0
- package/src/interfaces/desktop/assets/blobs/nimbo.png +0 -0
- package/src/interfaces/desktop/assets/blobs/noche.png +0 -0
- package/src/interfaces/desktop/assets/blobs/onyx.png +0 -0
- package/src/interfaces/desktop/assets/blobs/orbita.png +0 -0
- package/src/interfaces/desktop/assets/blobs/ovni.png +0 -0
- package/src/interfaces/desktop/assets/blobs/papa.png +0 -0
- package/src/interfaces/desktop/assets/blobs/parche.png +0 -0
- package/src/interfaces/desktop/assets/blobs/peon.png +0 -0
- package/src/interfaces/desktop/assets/blobs/perla.png +0 -0
- package/src/interfaces/desktop/assets/blobs/pino.png +0 -0
- package/src/interfaces/desktop/assets/blobs/quad.png +0 -0
- package/src/interfaces/desktop/assets/blobs/rubi.png +0 -0
- package/src/interfaces/desktop/assets/blobs/saturno.png +0 -0
- package/src/interfaces/desktop/assets/blobs/trebol.png +0 -0
- package/src/interfaces/desktop/assets/blobs/trino.png +0 -0
- package/src/interfaces/desktop/assets/blobs/volcan.png +0 -0
- package/src/interfaces/desktop/assets/blobs/zafiro.png +0 -0
- package/src/interfaces/desktop/assets/notification.mp3 +0 -0
- package/src/interfaces/desktop/main.js +473 -29
- package/src/interfaces/desktop/mascot-blobs.js +41 -0
- package/src/interfaces/desktop/mascot-preload.js +32 -0
- package/src/interfaces/desktop/mascot.css +186 -0
- package/src/interfaces/desktop/mascot.html +40 -0
- package/src/interfaces/desktop/mascot.js +163 -0
- package/src/interfaces/desktop/preload.js +10 -0
- package/src/interfaces/desktop/renderer.js +308 -48
- package/src/interfaces/desktop/style.css +34 -0
- package/src/interfaces/mcp-server/index.js +87 -0
- package/src/interfaces/tui/_shims/util-locale.ts +0 -2
- package/src/interfaces/tui/app.tsx +0 -6
- package/src/interfaces/tui/attach.ts +0 -1
- package/src/interfaces/tui/context/sdk-apx.tsx +0 -4
- package/src/interfaces/tui/plugin/api.tsx +0 -3
- package/src/interfaces/tui/plugin/runtime.ts +0 -3
- package/src/interfaces/tui/thread.ts +0 -16
- package/src/interfaces/web/README.md +22 -14
- package/src/interfaces/web/dist/assets/claude-XtpLmGtF.webp +0 -0
- package/src/interfaces/web/dist/assets/codex-DExPUgvh.webp +0 -0
- package/src/interfaces/web/dist/assets/index-BEoRgIqd.css +32 -0
- package/src/interfaces/web/dist/assets/index-BEoRgIqd.css.br +0 -0
- package/src/interfaces/web/dist/assets/index-BEoRgIqd.css.gz +0 -0
- package/src/interfaces/web/dist/assets/index-C6fXHc1p.js +1074 -0
- package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.br +0 -0
- package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.gz +0 -0
- package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.map +1 -0
- package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.map.br +0 -0
- package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.map.gz +0 -0
- package/src/interfaces/web/dist/favicon/dark/site.webmanifest +12 -6
- package/src/interfaces/web/dist/favicon/white/site.webmanifest +12 -6
- package/src/interfaces/web/dist/index.html +22 -6
- package/src/interfaces/web/dist/index.html.br +0 -0
- package/src/interfaces/web/dist/index.html.gz +0 -0
- package/src/interfaces/web/dist/manifest.webmanifest +25 -0
- package/src/interfaces/web/dist/modules/blobs/amatista.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/aqua.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/brasa.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/campana.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/caracol.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/carbon.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/cobalto.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/cometa.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/coral.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/cubi.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/eclipse.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/faro.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/gajo.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/iris.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/kiwi.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/laguna.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/lila.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/menta.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/nimbo.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/noche.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/onyx.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/orbita.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/ovni.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/papa.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/parche.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/peon.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/perla.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/pino.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/quad.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/rubi.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/saturno.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/trebol.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/trino.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/volcan.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/zafiro.png +0 -0
- package/src/interfaces/web/dist/sw.js +106 -0
- package/src/interfaces/web/dist/sw.js.br +0 -0
- package/src/interfaces/web/dist/sw.js.gz +0 -0
- package/src/interfaces/web/eslint.config.js +83 -0
- package/src/interfaces/web/index.html +20 -4
- package/src/interfaces/web/package-lock.json +1651 -1280
- package/src/interfaces/web/package.json +9 -10
- package/src/interfaces/web/pnpm-lock.yaml +867 -869
- package/src/interfaces/web/public/favicon/dark/site.webmanifest +12 -6
- package/src/interfaces/web/public/favicon/white/site.webmanifest +12 -6
- package/src/interfaces/web/public/manifest.webmanifest +25 -0
- package/src/interfaces/web/public/modules/blobs/amatista.png +0 -0
- package/src/interfaces/web/public/modules/blobs/aqua.png +0 -0
- package/src/interfaces/web/public/modules/blobs/brasa.png +0 -0
- package/src/interfaces/web/public/modules/blobs/campana.png +0 -0
- package/src/interfaces/web/public/modules/blobs/caracol.png +0 -0
- package/src/interfaces/web/public/modules/blobs/carbon.png +0 -0
- package/src/interfaces/web/public/modules/blobs/cobalto.png +0 -0
- package/src/interfaces/web/public/modules/blobs/cometa.png +0 -0
- package/src/interfaces/web/public/modules/blobs/coral.png +0 -0
- package/src/interfaces/web/public/modules/blobs/cubi.png +0 -0
- package/src/interfaces/web/public/modules/blobs/eclipse.png +0 -0
- package/src/interfaces/web/public/modules/blobs/faro.png +0 -0
- package/src/interfaces/web/public/modules/blobs/gajo.png +0 -0
- package/src/interfaces/web/public/modules/blobs/iris.png +0 -0
- package/src/interfaces/web/public/modules/blobs/kiwi.png +0 -0
- package/src/interfaces/web/public/modules/blobs/laguna.png +0 -0
- package/src/interfaces/web/public/modules/blobs/lila.png +0 -0
- package/src/interfaces/web/public/modules/blobs/menta.png +0 -0
- package/src/interfaces/web/public/modules/blobs/nimbo.png +0 -0
- package/src/interfaces/web/public/modules/blobs/noche.png +0 -0
- package/src/interfaces/web/public/modules/blobs/onyx.png +0 -0
- package/src/interfaces/web/public/modules/blobs/orbita.png +0 -0
- package/src/interfaces/web/public/modules/blobs/ovni.png +0 -0
- package/src/interfaces/web/public/modules/blobs/papa.png +0 -0
- package/src/interfaces/web/public/modules/blobs/parche.png +0 -0
- package/src/interfaces/web/public/modules/blobs/peon.png +0 -0
- package/src/interfaces/web/public/modules/blobs/perla.png +0 -0
- package/src/interfaces/web/public/modules/blobs/pino.png +0 -0
- package/src/interfaces/web/public/modules/blobs/quad.png +0 -0
- package/src/interfaces/web/public/modules/blobs/rubi.png +0 -0
- package/src/interfaces/web/public/modules/blobs/saturno.png +0 -0
- package/src/interfaces/web/public/modules/blobs/trebol.png +0 -0
- package/src/interfaces/web/public/modules/blobs/trino.png +0 -0
- package/src/interfaces/web/public/modules/blobs/volcan.png +0 -0
- package/src/interfaces/web/public/modules/blobs/zafiro.png +0 -0
- package/src/interfaces/web/public/sw.js +106 -0
- package/src/interfaces/web/src/App.tsx +106 -10
- package/src/interfaces/web/src/assets/cli/claude.webp +0 -0
- package/src/interfaces/web/src/assets/cli/codex.webp +0 -0
- package/src/interfaces/web/src/assets/cli/cursor.svg +1 -0
- package/src/interfaces/web/src/assets/cli/opencode.png +0 -0
- package/src/interfaces/web/src/components/Combobox.tsx +201 -0
- package/src/interfaces/web/src/components/MobileHint.tsx +95 -0
- package/src/interfaces/web/src/components/MobileLinkDialog.tsx +156 -0
- package/src/interfaces/web/src/components/ModelCombobox.tsx +21 -113
- package/src/interfaces/web/src/components/{routines/ReadOnlyBlock.tsx → ReadOnlyBlock.tsx} +13 -4
- package/src/interfaces/web/src/components/Roby.tsx +5 -3
- package/src/interfaces/web/src/components/RobyBubble.tsx +23 -5
- package/src/interfaces/web/src/components/RowMenu.tsx +46 -0
- package/src/interfaces/web/src/components/TimezoneSelect.tsx +4 -1
- package/src/interfaces/web/src/components/Toast.tsx +50 -14
- package/src/interfaces/web/src/components/UiSelect.tsx +12 -5
- package/src/interfaces/web/src/components/agents/AgentAvatar.tsx +171 -0
- package/src/interfaces/web/src/components/agents/AgentFormFields.tsx +42 -11
- package/src/interfaces/web/src/components/agents/AgentModelBadge.tsx +157 -0
- package/src/interfaces/web/src/components/agents/AgentModelSelect.tsx +57 -0
- package/src/interfaces/web/src/components/agents/AgentSkillsPicker.tsx +115 -0
- package/src/interfaces/web/src/components/agents/BlobAvatar.tsx +50 -0
- package/src/interfaces/web/src/components/agents/blobPresets.ts +50 -0
- package/src/interfaces/web/src/components/agents/modelCatalog.ts +66 -0
- package/src/interfaces/web/src/components/chat/ActionGroup.tsx +162 -0
- package/src/interfaces/web/src/components/chat/AskAnswersCard.tsx +4 -3
- package/src/interfaces/web/src/components/chat/AskQuestionsCard.tsx +1 -1
- package/src/interfaces/web/src/components/chat/Attachment.tsx +220 -0
- package/src/interfaces/web/src/components/chat/ChatList.tsx +226 -51
- package/src/interfaces/web/src/components/chat/ChatRowActivity.tsx +45 -0
- package/src/interfaces/web/src/components/chat/Composer.tsx +672 -23
- package/src/interfaces/web/src/components/chat/ComposerCommands.tsx +175 -0
- package/src/interfaces/web/src/components/chat/ComposerSuggest.tsx +215 -0
- package/src/interfaces/web/src/components/chat/ContextBar.tsx +133 -65
- package/src/interfaces/web/src/components/chat/InlineAskPanel.tsx +107 -47
- package/src/interfaces/web/src/components/chat/MessageBubble.tsx +460 -119
- package/src/interfaces/web/src/components/chat/MessageList.tsx +165 -18
- package/src/interfaces/web/src/components/chat/ReasoningBlock.tsx +58 -0
- package/src/interfaces/web/src/components/chat/SessionPicker.tsx +182 -0
- package/src/interfaces/web/src/components/chat/SkillTrace.tsx +183 -0
- package/src/interfaces/web/src/components/chat/ToolCall.tsx +11 -11
- package/src/interfaces/web/src/components/code/CodeContextTab.tsx +87 -53
- package/src/interfaces/web/src/components/code/CodeFileTree.tsx +11 -52
- package/src/interfaces/web/src/components/code/CodeFileViewer.tsx +5 -4
- package/src/interfaces/web/src/components/code/CodeProjectPicker.tsx +31 -7
- package/src/interfaces/web/src/components/code/CodeSessionList.tsx +32 -11
- package/src/interfaces/web/src/components/code/CodeSidePanel.tsx +33 -3
- package/src/interfaces/web/src/components/code/CodeTerminal.tsx +5 -4
- package/src/interfaces/web/src/components/code/NewCodeSessionDialog.tsx +164 -0
- package/src/interfaces/web/src/components/commitments/CommitmentDetail.tsx +162 -0
- package/src/interfaces/web/src/components/commitments/CommitmentFormDialog.tsx +158 -0
- package/src/interfaces/web/src/components/commitments/CommitmentList.tsx +194 -0
- package/src/interfaces/web/src/components/commitments/commitmentState.tsx +46 -0
- package/src/interfaces/web/src/components/common/BulkActionBar.tsx +60 -0
- package/src/interfaces/web/src/components/common/ConfirmDialog.tsx +4 -1
- package/src/interfaces/web/src/components/common/SelectCheckbox.tsx +40 -0
- package/src/interfaces/web/src/components/common/TabNav.tsx +1 -1
- package/src/interfaces/web/src/components/cron/CronPicker.tsx +1 -1
- package/src/interfaces/web/src/components/files/FileBrowser.tsx +1 -1
- package/src/interfaces/web/src/components/files/FileTree.tsx +6 -4
- package/src/interfaces/web/src/components/files/FileViewer.tsx +9 -5
- package/src/interfaces/web/src/components/files/MarkdownPreview.tsx +45 -9
- package/src/interfaces/web/src/components/images/ImageDefaultsCard.tsx +93 -0
- package/src/interfaces/web/src/components/images/ImageProviderList.tsx +142 -0
- package/src/interfaces/web/src/components/images/ImageProviderModal.tsx +263 -0
- package/src/interfaces/web/src/components/images/ImageTestCard.tsx +142 -0
- package/src/interfaces/web/src/components/inbox/ChannelFilter.tsx +178 -0
- package/src/interfaces/web/src/components/inbox/InboxList.tsx +77 -81
- package/src/interfaces/web/src/components/inbox/InboxRowItem.tsx +140 -0
- package/src/interfaces/web/src/components/integrations/ComingSoonPlugin.tsx +2 -2
- package/src/interfaces/web/src/components/integrations/PluginConnect.tsx +208 -30
- package/src/interfaces/web/src/components/integrations/PluginToolsSection.tsx +1 -1
- package/src/interfaces/web/src/components/layout/ProjectAvatar.tsx +39 -24
- package/src/interfaces/web/src/components/layout/ProjectSidebar.tsx +253 -58
- package/src/interfaces/web/src/components/memory/MemoryBrowser.tsx +94 -47
- package/src/interfaces/web/src/components/routines/ExecutionsList.tsx +202 -90
- package/src/interfaces/web/src/components/routines/RoutineDetail.tsx +28 -6
- package/src/interfaces/web/src/components/routines/RoutineEditor.tsx +16 -5
- package/src/interfaces/web/src/components/routines/RoutineList.tsx +49 -9
- package/src/interfaces/web/src/components/routines/VarTextarea.tsx +1 -1
- package/src/interfaces/web/src/components/routines/runChat.ts +121 -0
- package/src/interfaces/web/src/components/sessions/SessionDetail.tsx +148 -0
- package/src/interfaces/web/src/components/sessions/SessionTerminal.tsx +98 -0
- package/src/interfaces/web/src/components/settings/AccessPanel.tsx +205 -0
- package/src/interfaces/web/src/components/settings/DefaultRouterCard.tsx +246 -101
- package/src/interfaces/web/src/components/settings/DesktopSettingsPanel.tsx +36 -2
- package/src/interfaces/web/src/components/settings/DevicesPanel.tsx +19 -6
- package/src/interfaces/web/src/components/settings/EmbedProviderList.tsx +274 -0
- package/src/interfaces/web/src/components/settings/EnginesPanel.tsx +26 -6
- package/src/interfaces/web/src/components/settings/MemoryPanel.tsx +118 -119
- package/src/interfaces/web/src/components/settings/NudgePanel.tsx +4 -3
- package/src/interfaces/web/src/components/settings/PairDeviceDialog.tsx +15 -4
- package/src/interfaces/web/src/components/settings/PanelPrefs.tsx +374 -0
- package/src/interfaces/web/src/components/settings/ProfilePanel.tsx +70 -2
- package/src/interfaces/web/src/components/settings/RoutingPanel.tsx +2 -1
- package/src/interfaces/web/src/components/settings/SkillsInspectorPanel.tsx +102 -43
- package/src/interfaces/web/src/components/settings/SkillsManager.tsx +76 -21
- package/src/interfaces/web/src/components/settings/SkillsSettings.tsx +10 -3
- package/src/interfaces/web/src/components/settings/SuperAgentPanel.tsx +8 -0
- package/src/interfaces/web/src/components/settings/TelegramChannelsPanel.tsx +11 -2
- package/src/interfaces/web/src/components/settings/TelegramContactsPanel.tsx +19 -8
- package/src/interfaces/web/src/components/settings/TelegramRolesPanel.tsx +12 -2
- package/src/interfaces/web/src/components/settings/WebPanel.tsx +22 -31
- package/src/interfaces/web/src/components/settings/providers/ProviderCard.tsx +15 -3
- package/src/interfaces/web/src/components/settings/providers/ProviderModal.tsx +97 -66
- package/src/interfaces/web/src/components/settings/providers/ProviderTestDialog.tsx +150 -0
- package/src/interfaces/web/src/components/settings/providers/typeStyles.ts +67 -25
- package/src/interfaces/web/src/components/settings/providers/types.ts +3 -0
- package/src/interfaces/web/src/components/tasks/TaskBoard.tsx +201 -0
- package/src/interfaces/web/src/components/tasks/TaskColumnsDialog.tsx +243 -0
- package/src/interfaces/web/src/components/tasks/TaskComments.tsx +167 -0
- package/src/interfaces/web/src/components/tasks/TaskDetail.tsx +335 -0
- package/src/interfaces/web/src/components/tasks/TaskFormDialog.tsx +406 -0
- package/src/interfaces/web/src/components/tasks/TaskList.tsx +258 -0
- package/src/interfaces/web/src/components/tasks/TaskSubtasks.tsx +126 -0
- package/src/interfaces/web/src/components/tasks/columns.ts +51 -0
- package/src/interfaces/web/src/components/tasks/taskStatus.tsx +159 -34
- package/src/interfaces/web/src/components/tasks/taskViewPrefs.ts +73 -0
- package/src/interfaces/web/src/components/tasks/useTaskColumns.ts +31 -0
- package/src/interfaces/web/src/components/ui/chat-input.tsx +136 -12
- package/src/interfaces/web/src/components/ui/context-menu.tsx +15 -198
- package/src/interfaces/web/src/components/ui/dialog.tsx +3 -2
- package/src/interfaces/web/src/components/ui/filter-chips.tsx +4 -0
- package/src/interfaces/web/src/components/ui/popover.tsx +14 -49
- package/src/interfaces/web/src/components/ui/sheet.tsx +2 -1
- package/src/interfaces/web/src/components/ui/spinner.tsx +2 -1
- package/src/interfaces/web/src/components/ui.tsx +62 -23
- package/src/interfaces/web/src/components/voice/VoiceProviderList.tsx +2 -1
- package/src/interfaces/web/src/components/voice/VoiceProviderModal.tsx +66 -8
- package/src/interfaces/web/src/components/voice/VoiceQvoxInstallCard.tsx +63 -0
- package/src/interfaces/web/src/components/voice/VoiceQvoxStatusCard.tsx +51 -0
- package/src/interfaces/web/src/components/voice/VoiceSttCard.tsx +4 -3
- package/src/interfaces/web/src/components/voice/VoiceTestCard.tsx +38 -4
- package/src/interfaces/web/src/constants/index.ts +1 -0
- package/src/interfaces/web/src/hooks/useChannelPrefs.ts +39 -0
- package/src/interfaces/web/src/hooks/useChat.ts +1092 -85
- package/src/interfaces/web/src/hooks/useChatActivity.ts +24 -0
- package/src/interfaces/web/src/hooks/useInbox.ts +26 -4
- package/src/interfaces/web/src/hooks/useLiveMessages.ts +16 -0
- package/src/interfaces/web/src/hooks/useOllamaModels.ts +79 -0
- package/src/interfaces/web/src/hooks/useRecorder.ts +198 -0
- package/src/interfaces/web/src/hooks/useTokenBootstrap.ts +23 -6
- package/src/interfaces/web/src/i18n/en.ts +832 -175
- package/src/interfaces/web/src/i18n/es.ts +841 -188
- package/src/interfaces/web/src/lib/api/agents.ts +23 -4
- package/src/interfaces/web/src/lib/api/code.ts +17 -0
- package/src/interfaces/web/src/lib/api/commitments.ts +7 -1
- package/src/interfaces/web/src/lib/api/conversations.ts +38 -11
- package/src/interfaces/web/src/lib/api/embeddings.ts +3 -0
- package/src/interfaces/web/src/lib/api/engines.ts +14 -0
- package/src/interfaces/web/src/lib/api/groups.ts +93 -0
- package/src/interfaces/web/src/lib/api/images.ts +193 -0
- package/src/interfaces/web/src/lib/api/inbox.ts +29 -5
- package/src/interfaces/web/src/lib/api/integrations.ts +9 -0
- package/src/interfaces/web/src/lib/api/media.ts +126 -0
- package/src/interfaces/web/src/lib/api/net.ts +44 -0
- package/src/interfaces/web/src/lib/api/profiles.ts +12 -0
- package/src/interfaces/web/src/lib/api/projects.ts +9 -1
- package/src/interfaces/web/src/lib/api/routines.ts +9 -1
- package/src/interfaces/web/src/lib/api/sessions.ts +18 -0
- package/src/interfaces/web/src/lib/api/skills.ts +8 -0
- package/src/interfaces/web/src/lib/api/super_agent.ts +3 -0
- package/src/interfaces/web/src/lib/api/tasks.ts +46 -6
- package/src/interfaces/web/src/lib/api/tools.ts +2 -0
- package/src/interfaces/web/src/lib/api/transcribe.ts +31 -0
- package/src/interfaces/web/src/lib/api/turns.ts +20 -0
- package/src/interfaces/web/src/lib/api/voice.ts +72 -2
- package/src/interfaces/web/src/lib/api.ts +3 -0
- package/src/interfaces/web/src/lib/channels.ts +214 -0
- package/src/interfaces/web/src/lib/chat-activity.ts +175 -0
- package/src/interfaces/web/src/lib/chat-prefs.ts +48 -0
- package/src/interfaces/web/src/lib/code-context.ts +0 -2
- package/src/interfaces/web/src/lib/http.ts +51 -17
- package/src/interfaces/web/src/lib/inbox-selection.ts +29 -0
- package/src/interfaces/web/src/lib/live.ts +252 -0
- package/src/interfaces/web/src/lib/net.ts +211 -0
- package/src/interfaces/web/src/lib/notify.ts +331 -0
- package/src/interfaces/web/src/lib/projectNav.ts +40 -0
- package/src/interfaces/web/src/lib/pwa.ts +115 -0
- package/src/interfaces/web/src/lib/qvox.ts +24 -0
- package/src/interfaces/web/src/lib/slug.ts +3 -0
- package/src/interfaces/web/src/lib/tone.ts +150 -0
- package/src/interfaces/web/src/main.tsx +15 -4
- package/src/interfaces/web/src/screens/ApxAdminScreen.tsx +33 -11
- package/src/interfaces/web/src/screens/InboxScreen.tsx +126 -71
- package/src/interfaces/web/src/screens/ProjectScreen.tsx +8 -4
- package/src/interfaces/web/src/screens/SettingsScreen.tsx +7 -4
- package/src/interfaces/web/src/screens/base/AgentDefaultsTab.tsx +30 -9
- package/src/interfaces/web/src/screens/base/CommitmentsTab.tsx +150 -168
- package/src/interfaces/web/src/screens/base/LogsTab.tsx +8 -7
- package/src/interfaces/web/src/screens/base/SessionsTab.tsx +99 -37
- package/src/interfaces/web/src/screens/base/WorkspacesTab.tsx +1 -1
- package/src/interfaces/web/src/screens/mobile/MobileChat.tsx +85 -0
- package/src/interfaces/web/src/screens/mobile/MobileChatList.tsx +244 -0
- package/src/interfaces/web/src/screens/mobile/MobileCommitments.tsx +350 -0
- package/src/interfaces/web/src/screens/mobile/MobileScreen.tsx +138 -0
- package/src/interfaces/web/src/screens/mobile/MobileTabBar.tsx +105 -0
- package/src/interfaces/web/src/screens/mobile/MobileTasks.tsx +407 -0
- package/src/interfaces/web/src/screens/mobile/NewChatSheet.tsx +313 -0
- package/src/interfaces/web/src/screens/mobile/mobileList.tsx +194 -0
- package/src/interfaces/web/src/screens/mobile/routes.ts +239 -0
- package/src/interfaces/web/src/screens/modules/CodeScreen.tsx +135 -64
- package/src/interfaces/web/src/screens/modules/DeckScreen.tsx +0 -1
- package/src/interfaces/web/src/screens/modules/ImagesScreen.tsx +172 -0
- package/src/interfaces/web/src/screens/modules/VoiceScreen.tsx +36 -4
- package/src/interfaces/web/src/screens/project/AgentBrainGraph.tsx +117 -30
- package/src/interfaces/web/src/screens/project/AgentDetailScreen.tsx +537 -92
- package/src/interfaces/web/src/screens/project/AgentsTab.tsx +344 -93
- package/src/interfaces/web/src/screens/project/ArtifactsTab.tsx +1 -1
- package/src/interfaces/web/src/screens/project/ChatTab.tsx +1160 -94
- package/src/interfaces/web/src/screens/project/IntegrationsTab.tsx +3 -2
- package/src/interfaces/web/src/screens/project/McpsTab.tsx +62 -14
- package/src/interfaces/web/src/screens/project/Overview.tsx +36 -15
- package/src/interfaces/web/src/screens/project/RoutinesTab.tsx +93 -8
- package/src/interfaces/web/src/screens/project/SkillsTab.tsx +4 -1
- package/src/interfaces/web/src/screens/project/StructureTab.tsx +5 -4
- package/src/interfaces/web/src/screens/project/TasksTab.tsx +351 -129
- package/src/interfaces/web/src/screens/project/VarsTab.tsx +17 -5
- package/src/interfaces/web/src/styles.css +106 -31
- package/src/interfaces/web/src/types/daemon.ts +246 -2
- package/src/interfaces/web/src/vite-env.d.ts +20 -0
- package/src/interfaces/tui/plugin/command-shim.ts +0 -109
- package/src/interfaces/web/components.json +0 -25
- package/src/interfaces/web/dist/assets/index-CvEoGtTf.js +0 -849
- package/src/interfaces/web/dist/assets/index-CvEoGtTf.js.map +0 -1
- package/src/interfaces/web/dist/assets/index-DzBBXFaO.css +0 -1
- package/src/interfaces/web/src/components/tasks/TaskDetailPanel.tsx +0 -142
- package/src/interfaces/web/src/components/ui/accordion.tsx +0 -72
- package/src/interfaces/web/src/components/ui/alert-dialog.tsx +0 -187
- package/src/interfaces/web/src/components/ui/alert.tsx +0 -76
- package/src/interfaces/web/src/components/ui/aspect-ratio.tsx +0 -22
- package/src/interfaces/web/src/components/ui/avatar.tsx +0 -107
- package/src/interfaces/web/src/components/ui/breadcrumb.tsx +0 -125
- package/src/interfaces/web/src/components/ui/button-group.tsx +0 -87
- package/src/interfaces/web/src/components/ui/calendar.tsx +0 -221
- package/src/interfaces/web/src/components/ui/card.tsx +0 -103
- package/src/interfaces/web/src/components/ui/carousel.tsx +0 -242
- package/src/interfaces/web/src/components/ui/chart.tsx +0 -371
- package/src/interfaces/web/src/components/ui/checkbox.tsx +0 -29
- package/src/interfaces/web/src/components/ui/collapsible.tsx +0 -19
- package/src/interfaces/web/src/components/ui/combobox.tsx +0 -295
- package/src/interfaces/web/src/components/ui/command.tsx +0 -196
- package/src/interfaces/web/src/components/ui/direction.tsx +0 -4
- package/src/interfaces/web/src/components/ui/drawer.tsx +0 -134
- package/src/interfaces/web/src/components/ui/empty.tsx +0 -104
- package/src/interfaces/web/src/components/ui/field.tsx +0 -236
- package/src/interfaces/web/src/components/ui/hover-card.tsx +0 -51
- package/src/interfaces/web/src/components/ui/input-otp.tsx +0 -85
- package/src/interfaces/web/src/components/ui/item.tsx +0 -201
- package/src/interfaces/web/src/components/ui/menubar.tsx +0 -280
- package/src/interfaces/web/src/components/ui/native-select.tsx +0 -61
- package/src/interfaces/web/src/components/ui/navigation-menu.tsx +0 -168
- package/src/interfaces/web/src/components/ui/pagination.tsx +0 -130
- package/src/interfaces/web/src/components/ui/progress.tsx +0 -83
- package/src/interfaces/web/src/components/ui/radio-group.tsx +0 -36
- package/src/interfaces/web/src/components/ui/resizable.tsx +0 -50
- package/src/interfaces/web/src/components/ui/scroll-area.tsx +0 -53
- package/src/interfaces/web/src/components/ui/sidebar.tsx +0 -726
- package/src/interfaces/web/src/components/ui/slider.tsx +0 -52
- package/src/interfaces/web/src/components/ui/sonner.tsx +0 -49
- package/src/interfaces/web/src/components/ui/table.tsx +0 -116
- package/src/interfaces/web/src/components/ui/toggle-group.tsx +0 -87
- package/src/interfaces/web/src/components/ui/toggle.tsx +0 -45
- package/src/interfaces/web/src/hooks/use-mobile.ts +0 -19
- package/src/interfaces/web/src/screens/base/GlobalTasksTab.tsx +0 -161
|
@@ -8,16 +8,21 @@
|
|
|
8
8
|
// + register it in PLUGIN_SERVICES (open/closed) — no API/route changes.
|
|
9
9
|
//
|
|
10
10
|
// Scope of this catalog (per product decision): Asana, GitHub, Obsidian,
|
|
11
|
-
// WhatsApp. Telegram is intentionally absent — it's a channel,
|
|
12
|
-
// its own surface, not a service plugin. Transcription lives
|
|
13
|
-
// STT stack. Obsidian is path-based (a local Vault) rather than
|
|
11
|
+
// Calendar, WhatsApp. Telegram is intentionally absent — it's a channel,
|
|
12
|
+
// configured under its own surface, not a service plugin. Transcription lives
|
|
13
|
+
// with the desktop STT stack. Obsidian is path-based (a local Vault) rather than
|
|
14
|
+
// token-based, and Calendar is user-OAuth-based (auth: "oauth") — see
|
|
15
|
+
// plugins/calendar.js for why it acts as you (invites + Meet) instead of as a
|
|
16
|
+
// service account.
|
|
14
17
|
import { asanaPlugin } from "./plugins/asana.js";
|
|
18
|
+
import { calendarPlugin } from "./plugins/calendar.js";
|
|
15
19
|
import { githubPlugin } from "./plugins/github.js";
|
|
16
20
|
import { obsidianPlugin } from "./plugins/obsidian.js";
|
|
17
21
|
|
|
18
22
|
// slug -> live plugin service (must implement the lifecycle contract).
|
|
19
23
|
export const PLUGIN_SERVICES = Object.freeze({
|
|
20
24
|
asana: asanaPlugin,
|
|
25
|
+
calendar: calendarPlugin,
|
|
21
26
|
github: githubPlugin,
|
|
22
27
|
obsidian: obsidianPlugin,
|
|
23
28
|
});
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
// Google OAuth2 for user-delegated integrations (Calendar today).
|
|
2
|
+
//
|
|
3
|
+
// Why this exists — and why it replaced the service account:
|
|
4
|
+
//
|
|
5
|
+
// A service account acts as ITSELF. It can read a shared calendar and create
|
|
6
|
+
// events on it, but Google blocks it from inviting other people or minting a
|
|
7
|
+
// Meet link unless the whole account lives inside a Google Workspace domain
|
|
8
|
+
// with Domain-Wide Delegation — a thing a personal @gmail.com simply does not
|
|
9
|
+
// have. So "agendá una reunión con Carlos y mandale el Meet" was impossible.
|
|
10
|
+
//
|
|
11
|
+
// User OAuth acts AS YOU. You consent once in the browser, Google hands back a
|
|
12
|
+
// refresh token, and from then on APX creates events, sends invitations, and
|
|
13
|
+
// creates Meet links on your own calendar — because it is you doing it. The
|
|
14
|
+
// price is a one-time OAuth client (client_id + secret) created in Google Cloud
|
|
15
|
+
// Console, and that is the only console step left: no key file, no manual
|
|
16
|
+
// calendar sharing, no Workspace.
|
|
17
|
+
//
|
|
18
|
+
// The flow: build a consent URL → the browser round-trips → Google redirects to
|
|
19
|
+
// our callback with a `code` → we exchange it for a refresh token → we cache
|
|
20
|
+
// short-lived access tokens in memory and refresh them as needed. ~1 file of
|
|
21
|
+
// node:crypto + fetch, no Google SDK.
|
|
22
|
+
import crypto from "node:crypto";
|
|
23
|
+
|
|
24
|
+
export const AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
25
|
+
export const TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
26
|
+
|
|
27
|
+
// The path Google redirects the browser back to. Kept scope/project-agnostic —
|
|
28
|
+
// everything the callback needs travels in the signed `state`, so ONE redirect
|
|
29
|
+
// URI is registered in the console and never changes. Mounted under /api by the
|
|
30
|
+
// daemon (see api/prefix.js), so the full URL is `<origin>/api/integrations/oauth/callback`.
|
|
31
|
+
export const CALLBACK_PATH = "/api/integrations/oauth/callback";
|
|
32
|
+
|
|
33
|
+
/** The redirect URI to register in the console and to send on every exchange. */
|
|
34
|
+
export function callbackUrl(origin) {
|
|
35
|
+
return `${String(origin || "").replace(/\/$/, "")}${CALLBACK_PATH}`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ─── state: signed, so the unauthenticated callback can't be forged ──────────
|
|
39
|
+
//
|
|
40
|
+
// The callback bypasses bearer auth (Google's browser redirect carries no
|
|
41
|
+
// token), so anyone could hit it. We defend it by signing the `state` we put in
|
|
42
|
+
// the consent URL with a per-process key: a callback whose state doesn't verify
|
|
43
|
+
// is rejected. The key is ephemeral on purpose — a daemon restart invalidates
|
|
44
|
+
// any consent link older than one boot, which is fine for a 10-minute flow.
|
|
45
|
+
const STATE_KEY = crypto.randomBytes(32);
|
|
46
|
+
const STATE_TTL_MS = 10 * 60_000;
|
|
47
|
+
|
|
48
|
+
const b64url = (buf) =>
|
|
49
|
+
Buffer.from(buf).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
50
|
+
const b64urlJson = (obj) => b64url(JSON.stringify(obj));
|
|
51
|
+
const fromB64url = (s) => Buffer.from(s.replace(/-/g, "+").replace(/_/g, "/"), "base64");
|
|
52
|
+
|
|
53
|
+
/** Sign a small state payload (slug, pid, scope, origin) into an opaque token. */
|
|
54
|
+
export function signState(payload) {
|
|
55
|
+
const body = b64urlJson({ ...payload, exp: Date.now() + STATE_TTL_MS });
|
|
56
|
+
const sig = b64url(crypto.createHmac("sha256", STATE_KEY).update(body).digest());
|
|
57
|
+
return `${body}.${sig}`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Verify + decode a state token, or return null if forged/expired/malformed. */
|
|
61
|
+
export function verifyState(token) {
|
|
62
|
+
const [body, sig] = String(token || "").split(".");
|
|
63
|
+
if (!body || !sig) return null;
|
|
64
|
+
const expected = b64url(crypto.createHmac("sha256", STATE_KEY).update(body).digest());
|
|
65
|
+
// Constant-time compare — the lengths match by construction (same HMAC).
|
|
66
|
+
if (sig.length !== expected.length || !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
let data;
|
|
70
|
+
try {
|
|
71
|
+
data = JSON.parse(fromB64url(body).toString("utf8"));
|
|
72
|
+
} catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
if (!data || typeof data.exp !== "number" || data.exp < Date.now()) return null;
|
|
76
|
+
return data;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ─── consent URL ─────────────────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* The URL to send the browser to. `access_type=offline` + `prompt=consent`
|
|
83
|
+
* guarantee a refresh token comes back every time (Google omits it on repeat
|
|
84
|
+
* consents otherwise, which would silently break reconnects).
|
|
85
|
+
*/
|
|
86
|
+
export function buildAuthUrl({ clientId, redirectUri, scope, state }) {
|
|
87
|
+
const u = new URL(AUTH_URL);
|
|
88
|
+
u.searchParams.set("client_id", clientId);
|
|
89
|
+
u.searchParams.set("redirect_uri", redirectUri);
|
|
90
|
+
u.searchParams.set("response_type", "code");
|
|
91
|
+
u.searchParams.set("scope", scope);
|
|
92
|
+
u.searchParams.set("access_type", "offline");
|
|
93
|
+
u.searchParams.set("prompt", "consent");
|
|
94
|
+
u.searchParams.set("include_granted_scopes", "true");
|
|
95
|
+
u.searchParams.set("state", state);
|
|
96
|
+
return u.toString();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ─── token exchange + refresh ────────────────────────────────────────────────
|
|
100
|
+
|
|
101
|
+
async function tokenRequest(params, { fetchImpl = fetch } = {}) {
|
|
102
|
+
const res = await fetchImpl(TOKEN_URL, {
|
|
103
|
+
method: "POST",
|
|
104
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
105
|
+
body: new URLSearchParams(params).toString(),
|
|
106
|
+
});
|
|
107
|
+
const data = await res.json().catch(() => ({}));
|
|
108
|
+
if (!res.ok) {
|
|
109
|
+
const detail = data.error_description || data.error || `HTTP ${res.status}`;
|
|
110
|
+
throw new Error(`Google rechazó el intercambio de token: ${detail}`);
|
|
111
|
+
}
|
|
112
|
+
return data;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** First exchange: authorization code → { refresh_token, access_token, email }. */
|
|
116
|
+
export async function exchangeCode({ clientId, clientSecret, code, redirectUri }, opts = {}) {
|
|
117
|
+
const data = await tokenRequest(
|
|
118
|
+
{
|
|
119
|
+
grant_type: "authorization_code",
|
|
120
|
+
code,
|
|
121
|
+
client_id: clientId,
|
|
122
|
+
client_secret: clientSecret,
|
|
123
|
+
redirect_uri: redirectUri,
|
|
124
|
+
},
|
|
125
|
+
opts,
|
|
126
|
+
);
|
|
127
|
+
if (!data.refresh_token) {
|
|
128
|
+
throw new Error(
|
|
129
|
+
"Google no devolvió un refresh token. Revocá el acceso de APX en myaccount.google.com/permissions y volvé a conectar (el flujo fuerza el consentimiento).",
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
refresh_token: data.refresh_token,
|
|
134
|
+
access_token: data.access_token || null,
|
|
135
|
+
expires_in: Number(data.expires_in) || 3600,
|
|
136
|
+
email: emailFromIdToken(data.id_token),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Access tokens last an hour and cost a round-trip; cache in memory keyed by the
|
|
141
|
+
// refresh token, so several tool calls in one turn don't each re-mint one.
|
|
142
|
+
const accessCache = new Map();
|
|
143
|
+
|
|
144
|
+
export function clearAccessCache() {
|
|
145
|
+
accessCache.clear();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** A valid access token for a refresh token, minted or served from cache. */
|
|
149
|
+
export async function accessTokenFor({ clientId, clientSecret, refreshToken }, opts = {}) {
|
|
150
|
+
const hit = accessCache.get(refreshToken);
|
|
151
|
+
if (hit && hit.expires_at - 60_000 > Date.now()) return hit.access_token;
|
|
152
|
+
const data = await tokenRequest(
|
|
153
|
+
{
|
|
154
|
+
grant_type: "refresh_token",
|
|
155
|
+
refresh_token: refreshToken,
|
|
156
|
+
client_id: clientId,
|
|
157
|
+
client_secret: clientSecret,
|
|
158
|
+
},
|
|
159
|
+
opts,
|
|
160
|
+
);
|
|
161
|
+
if (!data.access_token) throw new Error("Google no devolvió un access token al refrescar.");
|
|
162
|
+
accessCache.set(refreshToken, {
|
|
163
|
+
access_token: data.access_token,
|
|
164
|
+
expires_at: Date.now() + (Number(data.expires_in) || 3600) * 1000,
|
|
165
|
+
});
|
|
166
|
+
return data.access_token;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Best-effort account email, decoded from the id_token payload (no verify). */
|
|
170
|
+
export function emailFromIdToken(idToken) {
|
|
171
|
+
const seg = String(idToken || "").split(".")[1];
|
|
172
|
+
if (!seg) return null;
|
|
173
|
+
try {
|
|
174
|
+
const claims = JSON.parse(fromB64url(seg).toString("utf8"));
|
|
175
|
+
return claims.email || null;
|
|
176
|
+
} catch {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -93,21 +93,25 @@ export async function listProjects(token, workspaceGid) {
|
|
|
93
93
|
export async function listTasks(token, projectGid, completed = false) {
|
|
94
94
|
const result = await request(token, "GET", `/projects/${projectGid}/tasks`, {
|
|
95
95
|
params: {
|
|
96
|
-
opt_fields: "gid,name,completed,due_on,assignee.name,notes,permalink_url",
|
|
96
|
+
opt_fields: "gid,name,completed,due_on,assignee.name,notes,permalink_url,memberships.section.name,memberships.section.gid",
|
|
97
97
|
completed_since: completed ? "" : "now",
|
|
98
98
|
},
|
|
99
99
|
});
|
|
100
100
|
return result?.data || [];
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
export async function createTask(token, { workspaceGid, name, notes = "", projectGid, assignee, dueOn } = {}) {
|
|
103
|
+
export async function createTask(token, { workspaceGid, name, notes = "", projectGid, sectionGid, assignee, dueOn } = {}) {
|
|
104
104
|
const payload = { name, workspace: workspaceGid };
|
|
105
105
|
if (notes) payload.notes = notes;
|
|
106
106
|
if (projectGid) payload.projects = [projectGid];
|
|
107
107
|
if (assignee) payload.assignee = assignee;
|
|
108
108
|
if (dueOn) payload.due_on = dueOn;
|
|
109
109
|
const result = await request(token, "POST", "/tasks", { payload });
|
|
110
|
-
|
|
110
|
+
const task = result?.data || {};
|
|
111
|
+
if (sectionGid && task.gid) {
|
|
112
|
+
await request(token, "POST", `/sections/${sectionGid}/addTask`, { payload: { task: task.gid } });
|
|
113
|
+
}
|
|
114
|
+
return task;
|
|
111
115
|
}
|
|
112
116
|
|
|
113
117
|
export async function updateTask(token, taskGid, { name, notes, completed, dueOn, assignee } = {}) {
|
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
// Google Calendar integration plugin — user OAuth, so an agent can act AS you.
|
|
2
|
+
//
|
|
3
|
+
// This plugin used to authenticate with a service account: paste a JSON key,
|
|
4
|
+
// share your calendar with a robot email, done. It worked for reading and for
|
|
5
|
+
// creating plain events, but a service account acts as ITSELF, and Google bars
|
|
6
|
+
// it from inviting other people or creating a Meet link without Domain-Wide
|
|
7
|
+
// Delegation — a Workspace feature a personal @gmail.com does not have. So
|
|
8
|
+
// "agendá con Carlos y mandale el Meet" was simply impossible.
|
|
9
|
+
//
|
|
10
|
+
// User OAuth acts as YOU. You consent once in the browser and Google hands back
|
|
11
|
+
// a refresh token; from then on APX reads your agenda, creates and moves events,
|
|
12
|
+
// SENDS INVITATIONS, and creates Meet links — because it is you doing it, on your
|
|
13
|
+
// own calendar. The only setup left is a one-time OAuth client in Google Cloud
|
|
14
|
+
// Console (client_id + secret). No key file, no calendar sharing, no Workspace.
|
|
15
|
+
//
|
|
16
|
+
// The OAuth mechanics (consent URL, code exchange, refresh, state signing) live
|
|
17
|
+
// in ./_google-oauth.js. This file is the calendar REST client + the plugin
|
|
18
|
+
// lifecycle the daemon and web panel drive.
|
|
19
|
+
import crypto from "node:crypto";
|
|
20
|
+
import {
|
|
21
|
+
buildAuthUrl,
|
|
22
|
+
callbackUrl,
|
|
23
|
+
signState,
|
|
24
|
+
exchangeCode,
|
|
25
|
+
accessTokenFor,
|
|
26
|
+
} from "./_google-oauth.js";
|
|
27
|
+
|
|
28
|
+
const API = "https://www.googleapis.com/calendar/v3";
|
|
29
|
+
|
|
30
|
+
// Full calendar when the owner allows writes (create/move events, invite people,
|
|
31
|
+
// mint Meet links, free/busy); read-only otherwise. `openid email` rides along
|
|
32
|
+
// so we can show which account is connected. Kept broad-but-standard on purpose:
|
|
33
|
+
// narrower per-feature scopes make invites and free/busy fragile for no real gain
|
|
34
|
+
// on a single-user tool.
|
|
35
|
+
export const SCOPE_READ = "openid email https://www.googleapis.com/auth/calendar.readonly";
|
|
36
|
+
export const SCOPE_WRITE = "openid email https://www.googleapis.com/auth/calendar";
|
|
37
|
+
|
|
38
|
+
function scopeFor(config) {
|
|
39
|
+
return config?.write_access ? SCOPE_WRITE : SCOPE_READ;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ─── access tokens ────────────────────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
/** A live access token for the stored connection, or a clear error. */
|
|
45
|
+
export async function getAccessToken(config = {}, opts = {}) {
|
|
46
|
+
const { client_id, client_secret, refresh_token } = config || {};
|
|
47
|
+
if (!client_id || !client_secret) {
|
|
48
|
+
throw new Error("Falta el OAuth client (client_id / client_secret). Cargalos en el panel.");
|
|
49
|
+
}
|
|
50
|
+
if (!refresh_token) {
|
|
51
|
+
throw new Error("El calendario no está autorizado todavía. Conectá con Google en el panel.");
|
|
52
|
+
}
|
|
53
|
+
return accessTokenFor({ clientId: client_id, clientSecret: client_secret, refreshToken: refresh_token }, opts);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ─── REST client ────────────────────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
async function call(config, urlPath, { method = "GET", query, body, fetchImpl = fetch } = {}) {
|
|
59
|
+
const token = await getAccessToken(config, { fetchImpl });
|
|
60
|
+
const url = new URL(API + urlPath);
|
|
61
|
+
for (const [k, v] of Object.entries(query || {})) {
|
|
62
|
+
if (v !== undefined && v !== null && v !== "") url.searchParams.set(k, String(v));
|
|
63
|
+
}
|
|
64
|
+
const res = await fetchImpl(url.toString(), {
|
|
65
|
+
method,
|
|
66
|
+
headers: {
|
|
67
|
+
authorization: `Bearer ${token}`,
|
|
68
|
+
...(body ? { "content-type": "application/json" } : {}),
|
|
69
|
+
},
|
|
70
|
+
...(body ? { body: JSON.stringify(body) } : {}),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const data = await res.json().catch(() => ({}));
|
|
74
|
+
if (!res.ok) {
|
|
75
|
+
const msg = data?.error?.message || `HTTP ${res.status}`;
|
|
76
|
+
if (res.status === 401 || res.status === 403) {
|
|
77
|
+
throw new Error(`${msg} — puede que haga falta reconectar con Google en el panel.`);
|
|
78
|
+
}
|
|
79
|
+
throw new Error(msg);
|
|
80
|
+
}
|
|
81
|
+
return data;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Calendars the connected account can see — used only for the account probe. */
|
|
85
|
+
export async function listCalendars(config, opts = {}) {
|
|
86
|
+
const data = await call(config, "/users/me/calendarList", { ...opts });
|
|
87
|
+
return (data.items || []).map((c) => ({
|
|
88
|
+
id: c.id,
|
|
89
|
+
summary: c.summary || c.id,
|
|
90
|
+
timeZone: c.timeZone || null,
|
|
91
|
+
accessRole: c.accessRole || null,
|
|
92
|
+
primary: !!c.primary,
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** One event, flattened to what a prompt actually needs. */
|
|
97
|
+
function flattenEvent(e) {
|
|
98
|
+
return {
|
|
99
|
+
id: e.id,
|
|
100
|
+
title: e.summary || "(sin título)",
|
|
101
|
+
start: e.start?.dateTime || e.start?.date || null,
|
|
102
|
+
end: e.end?.dateTime || e.end?.date || null,
|
|
103
|
+
all_day: !!e.start?.date,
|
|
104
|
+
location: e.location || null,
|
|
105
|
+
attendees: (e.attendees || []).map((a) => a.email).filter(Boolean),
|
|
106
|
+
status: e.status || null,
|
|
107
|
+
link: e.htmlLink || null,
|
|
108
|
+
meet_link: e.hangoutLink || null,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export async function listEvents(config, { calendarId = "primary", timeMin, timeMax, q, maxResults = 25 } = {}, opts = {}) {
|
|
113
|
+
const data = await call(config, `/calendars/${encodeURIComponent(calendarId)}/events`, {
|
|
114
|
+
query: { timeMin, timeMax, q, maxResults, singleEvents: true, orderBy: "startTime" },
|
|
115
|
+
...opts,
|
|
116
|
+
});
|
|
117
|
+
return (data.items || []).map(flattenEvent);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Create an event. Because we act as the user now, two things that were
|
|
122
|
+
* impossible with a service account just work:
|
|
123
|
+
* - attendees get a real invitation (`sendUpdates=all`)
|
|
124
|
+
* - `meet: true` mints a Google Meet link (`conferenceData` + v1)
|
|
125
|
+
*/
|
|
126
|
+
export async function createEvent(
|
|
127
|
+
config,
|
|
128
|
+
{ calendarId = "primary", title, start, end, description, location, attendees, meet = false } = {},
|
|
129
|
+
opts = {},
|
|
130
|
+
) {
|
|
131
|
+
const hasAttendees = Array.isArray(attendees) && attendees.length > 0;
|
|
132
|
+
const body = {
|
|
133
|
+
summary: title,
|
|
134
|
+
description: description || undefined,
|
|
135
|
+
location: location || undefined,
|
|
136
|
+
start: { dateTime: start },
|
|
137
|
+
end: { dateTime: end },
|
|
138
|
+
...(hasAttendees ? { attendees: attendees.map((email) => ({ email })) } : {}),
|
|
139
|
+
...(meet
|
|
140
|
+
? {
|
|
141
|
+
conferenceData: {
|
|
142
|
+
createRequest: {
|
|
143
|
+
requestId: crypto.randomUUID(),
|
|
144
|
+
conferenceSolutionKey: { type: "hangoutsMeet" },
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
}
|
|
148
|
+
: {}),
|
|
149
|
+
};
|
|
150
|
+
const data = await call(config, `/calendars/${encodeURIComponent(calendarId)}/events`, {
|
|
151
|
+
method: "POST",
|
|
152
|
+
body,
|
|
153
|
+
query: {
|
|
154
|
+
...(meet ? { conferenceDataVersion: 1 } : {}),
|
|
155
|
+
...(hasAttendees ? { sendUpdates: "all" } : {}),
|
|
156
|
+
},
|
|
157
|
+
...opts,
|
|
158
|
+
});
|
|
159
|
+
return flattenEvent(data);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export async function updateEvent(config, { calendarId = "primary", eventId, ...fields } = {}, opts = {}) {
|
|
163
|
+
const body = {};
|
|
164
|
+
if (fields.title !== undefined) body.summary = fields.title;
|
|
165
|
+
if (fields.description !== undefined) body.description = fields.description;
|
|
166
|
+
if (fields.location !== undefined) body.location = fields.location;
|
|
167
|
+
if (fields.start !== undefined) body.start = { dateTime: fields.start };
|
|
168
|
+
if (fields.end !== undefined) body.end = { dateTime: fields.end };
|
|
169
|
+
const hasAttendees = Array.isArray(fields.attendees) && fields.attendees.length > 0;
|
|
170
|
+
if (fields.attendees !== undefined) body.attendees = (fields.attendees || []).map((email) => ({ email }));
|
|
171
|
+
const data = await call(config, `/calendars/${encodeURIComponent(calendarId)}/events/${encodeURIComponent(eventId)}`, {
|
|
172
|
+
method: "PATCH",
|
|
173
|
+
body,
|
|
174
|
+
query: { ...(hasAttendees ? { sendUpdates: "all" } : {}) },
|
|
175
|
+
...opts,
|
|
176
|
+
});
|
|
177
|
+
return flattenEvent(data);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* The first gaps of at least `minutes` between timeMin and timeMax, from
|
|
182
|
+
* Google's freeBusy view. Pure arithmetic once the busy blocks are in.
|
|
183
|
+
*/
|
|
184
|
+
export async function findSlots(config, { calendarId = "primary", timeMin, timeMax, minutes = 30, limit = 5 } = {}, opts = {}) {
|
|
185
|
+
const token = await getAccessToken(config, opts);
|
|
186
|
+
const fetchImpl = opts.fetchImpl || fetch;
|
|
187
|
+
const res = await fetchImpl(`${API}/freeBusy`, {
|
|
188
|
+
method: "POST",
|
|
189
|
+
headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
|
|
190
|
+
body: JSON.stringify({ timeMin, timeMax, items: [{ id: calendarId }] }),
|
|
191
|
+
});
|
|
192
|
+
const data = await res.json().catch(() => ({}));
|
|
193
|
+
if (!res.ok) throw new Error(data?.error?.message || `HTTP ${res.status}`);
|
|
194
|
+
|
|
195
|
+
const busy = (data.calendars?.[calendarId]?.busy || [])
|
|
196
|
+
.map((b) => [Date.parse(b.start), Date.parse(b.end)])
|
|
197
|
+
.filter(([s, e]) => Number.isFinite(s) && Number.isFinite(e))
|
|
198
|
+
.sort((a, b) => a[0] - b[0]);
|
|
199
|
+
|
|
200
|
+
const needed = minutes * 60_000;
|
|
201
|
+
const slots = [];
|
|
202
|
+
let cursor = Date.parse(timeMin);
|
|
203
|
+
const end = Date.parse(timeMax);
|
|
204
|
+
|
|
205
|
+
for (const [bStart, bEnd] of busy) {
|
|
206
|
+
if (bStart - cursor >= needed) {
|
|
207
|
+
slots.push({ start: new Date(cursor).toISOString(), end: new Date(bStart).toISOString() });
|
|
208
|
+
if (slots.length >= limit) return slots;
|
|
209
|
+
}
|
|
210
|
+
cursor = Math.max(cursor, bEnd);
|
|
211
|
+
}
|
|
212
|
+
if (end - cursor >= needed) {
|
|
213
|
+
slots.push({ start: new Date(cursor).toISOString(), end: new Date(end).toISOString() });
|
|
214
|
+
}
|
|
215
|
+
return slots.slice(0, limit);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// ─── plugin lifecycle ───────────────────────────────────────────────────────
|
|
219
|
+
|
|
220
|
+
function asBool(v, fallback = false) {
|
|
221
|
+
if (v === undefined || v === null) return fallback;
|
|
222
|
+
return v === true || v === "true" || v === "on" || v === 1 || v === "1";
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export const calendarPlugin = {
|
|
226
|
+
slug: "calendar",
|
|
227
|
+
name: "Google Calendar",
|
|
228
|
+
type: "calendar",
|
|
229
|
+
description:
|
|
230
|
+
"Conectá tu Google Calendar con OAuth para que los agentes lean tu agenda, agenden, inviten y armen Meet",
|
|
231
|
+
auth: "oauth",
|
|
232
|
+
tools: [
|
|
233
|
+
{ slug: "calendar_list_events", desc: "Ver qué hay en la agenda" },
|
|
234
|
+
{ slug: "calendar_find_slot", desc: "Buscar huecos libres" },
|
|
235
|
+
{ slug: "calendar_create_event", desc: "Agendar un evento (con invitados y Meet)" },
|
|
236
|
+
{ slug: "calendar_update_event", desc: "Mover o editar un evento" },
|
|
237
|
+
],
|
|
238
|
+
// Structure only — display text lives in web i18n (integrations.calendar.*).
|
|
239
|
+
ui: {
|
|
240
|
+
accent: "sky",
|
|
241
|
+
// Presence of `oauth` tells the web component to run the consent flow:
|
|
242
|
+
// save client_id/secret, then a "Conectar con Google" button. `redirectPath`
|
|
243
|
+
// is the URI the user registers in the console (shown in the UI).
|
|
244
|
+
oauth: { action: "authorize", redirectPath: "/api/integrations/oauth/callback" },
|
|
245
|
+
configFields: [
|
|
246
|
+
{
|
|
247
|
+
key: "client_id",
|
|
248
|
+
type: "text",
|
|
249
|
+
placeholder: "123-abc.apps.googleusercontent.com",
|
|
250
|
+
help_url: "https://console.cloud.google.com/apis/credentials",
|
|
251
|
+
help_url_label: "console.cloud.google.com",
|
|
252
|
+
},
|
|
253
|
+
{ key: "client_secret", type: "password", placeholder: "GOCSPX-…" },
|
|
254
|
+
{ key: "write_access", type: "toggle", default: true },
|
|
255
|
+
{ key: "meet", type: "toggle", default: true },
|
|
256
|
+
],
|
|
257
|
+
connectedFields: ["account_email", "calendar_name"],
|
|
258
|
+
},
|
|
259
|
+
|
|
260
|
+
// Save the OAuth client + preferences. This never mints tokens — authorization
|
|
261
|
+
// happens in the browser (authorize action → callback → completeOAuth).
|
|
262
|
+
configure(record, body = {}) {
|
|
263
|
+
const prev = record?.config || {};
|
|
264
|
+
const clientId = String(body.client_id ?? prev.client_id ?? "").trim();
|
|
265
|
+
const clientSecret = String(body.client_secret ?? prev.client_secret ?? "").trim();
|
|
266
|
+
|
|
267
|
+
// A live connection flipping a preference (write/meet) shouldn't need the
|
|
268
|
+
// secret re-typed — merge over what's stored.
|
|
269
|
+
const config = {
|
|
270
|
+
...(clientId ? { client_id: clientId } : {}),
|
|
271
|
+
...(clientSecret ? { client_secret: clientSecret } : {}),
|
|
272
|
+
write_access: asBool(body.write_access, prev.write_access ?? true),
|
|
273
|
+
meet: asBool(body.meet, prev.meet ?? true),
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
if (!clientId && !prev.client_id) {
|
|
277
|
+
throw new Error("Cargá el client_id del OAuth client de Google.");
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const patch = { name: this.name, type: this.type, description: this.description, config };
|
|
281
|
+
// A changed write scope needs a re-consent (the granted scope no longer
|
|
282
|
+
// matches). Everything else keeps the current connection.
|
|
283
|
+
if (config.write_access !== prev.write_access && prev.refresh_token) {
|
|
284
|
+
patch.status = "pending_validation";
|
|
285
|
+
patch.config.needs_reauth = true;
|
|
286
|
+
}
|
|
287
|
+
return { patch };
|
|
288
|
+
},
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Build the Google consent URL. Called by the web panel (authorize action);
|
|
292
|
+
* `ctx.origin` is the browser origin, so the redirect URI matches what the
|
|
293
|
+
* user registered and what the callback reconstructs.
|
|
294
|
+
*/
|
|
295
|
+
buildAuthorizeUrl(record, { origin, pid, scope } = {}) {
|
|
296
|
+
const config = record?.config || {};
|
|
297
|
+
if (!config.client_id) throw new Error("Cargá primero el client_id.");
|
|
298
|
+
if (!origin) throw new Error("No pude determinar el origin del panel para el redirect.");
|
|
299
|
+
const redirectUri = callbackUrl(origin);
|
|
300
|
+
const state = signState({ slug: this.slug, pid: String(pid ?? ""), scope: scope || "project" });
|
|
301
|
+
const auth_url = buildAuthUrl({
|
|
302
|
+
clientId: config.client_id,
|
|
303
|
+
redirectUri,
|
|
304
|
+
scope: scopeFor(config),
|
|
305
|
+
state,
|
|
306
|
+
});
|
|
307
|
+
return { auth_url, redirect_uri: redirectUri };
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Finish the OAuth dance: trade the code for a refresh token and activate.
|
|
312
|
+
* Called by the daemon's callback route. Returns a patch to persist.
|
|
313
|
+
*/
|
|
314
|
+
async completeOAuth(record, { code, redirectUri } = {}) {
|
|
315
|
+
const config = record?.config || {};
|
|
316
|
+
if (!config.client_id || !config.client_secret) {
|
|
317
|
+
throw new Error("Falta el OAuth client guardado para completar la conexión.");
|
|
318
|
+
}
|
|
319
|
+
const tokens = await exchangeCode({
|
|
320
|
+
clientId: config.client_id,
|
|
321
|
+
clientSecret: config.client_secret,
|
|
322
|
+
code,
|
|
323
|
+
redirectUri,
|
|
324
|
+
});
|
|
325
|
+
return {
|
|
326
|
+
patch: {
|
|
327
|
+
status: "active",
|
|
328
|
+
is_enabled: true,
|
|
329
|
+
config: {
|
|
330
|
+
refresh_token: tokens.refresh_token,
|
|
331
|
+
account_email: tokens.email || config.account_email || null,
|
|
332
|
+
calendar_id: "primary",
|
|
333
|
+
calendar_name: tokens.email || "primary",
|
|
334
|
+
needs_reauth: false,
|
|
335
|
+
last_error: null,
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
};
|
|
339
|
+
},
|
|
340
|
+
|
|
341
|
+
// Re-check a stored connection (used when flipping toggles once connected).
|
|
342
|
+
async validate(record) {
|
|
343
|
+
const config = record?.config || {};
|
|
344
|
+
if (!config.refresh_token) {
|
|
345
|
+
const detail = "Autorizá con Google en el panel para conectar el calendario.";
|
|
346
|
+
return {
|
|
347
|
+
patch: { status: "pending_validation", is_enabled: false, config: { last_error: detail } },
|
|
348
|
+
result: { ok: false, error: detail, needs_auth: true },
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
try {
|
|
352
|
+
// A cheap call that proves the refresh token still works.
|
|
353
|
+
await call(config, "/users/me/calendarList", { query: { maxResults: 1 } });
|
|
354
|
+
} catch (e) {
|
|
355
|
+
return {
|
|
356
|
+
patch: { status: "error", is_enabled: false, config: { last_error: String(e.message || e) } },
|
|
357
|
+
result: { ok: false, error: String(e.message || e) },
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
return {
|
|
361
|
+
patch: { status: "active", is_enabled: true, config: { calendar_id: "primary", needs_reauth: false, last_error: null } },
|
|
362
|
+
result: { ok: true, account_email: config.account_email || null },
|
|
363
|
+
};
|
|
364
|
+
},
|
|
365
|
+
|
|
366
|
+
status(record) {
|
|
367
|
+
const c = record?.config || {};
|
|
368
|
+
// No refresh token → not connected, whatever the stored status says. This
|
|
369
|
+
// also demotes a leftover service-account record from the old auth model so
|
|
370
|
+
// it can't masquerade as "active" after the OAuth migration.
|
|
371
|
+
const authorized = !!c.refresh_token;
|
|
372
|
+
let st = record?.status || "disconnected";
|
|
373
|
+
if (!authorized && st === "active") st = "disconnected";
|
|
374
|
+
return {
|
|
375
|
+
slug: this.slug,
|
|
376
|
+
status: st,
|
|
377
|
+
is_enabled: authorized && !!record?.is_enabled,
|
|
378
|
+
account_email: c.account_email || null,
|
|
379
|
+
calendar_id: c.calendar_id || (c.refresh_token ? "primary" : null),
|
|
380
|
+
calendar_name: c.calendar_name || (c.refresh_token ? c.account_email || "primary" : null),
|
|
381
|
+
write_access: !!c.write_access,
|
|
382
|
+
meet: !!c.meet,
|
|
383
|
+
client_id_set: !!c.client_id,
|
|
384
|
+
needs_reauth: !!c.needs_reauth,
|
|
385
|
+
};
|
|
386
|
+
},
|
|
387
|
+
|
|
388
|
+
deactivate() {
|
|
389
|
+
return { patch: { status: "inactive", is_enabled: false } };
|
|
390
|
+
},
|
|
391
|
+
|
|
392
|
+
actions: {
|
|
393
|
+
// Kick off OAuth: the web panel opens the returned auth_url in a popup.
|
|
394
|
+
async authorize(record, ctx = {}) {
|
|
395
|
+
return calendarPlugin.buildAuthorizeUrl(record, {
|
|
396
|
+
origin: ctx.origin,
|
|
397
|
+
pid: ctx.project?.id ?? 0,
|
|
398
|
+
scope: ctx.scope,
|
|
399
|
+
});
|
|
400
|
+
},
|
|
401
|
+
},
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
export default calendarPlugin;
|
|
@@ -73,6 +73,21 @@ function lastMemoryEntries(memoryPath, n) {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
// A recalled tool row is indexed as `[tool result: <name>] <name>({…args})`.
|
|
77
|
+
// Stripping the prefix — which is what this did — left the bare call shape
|
|
78
|
+
// sitting in the prompt, the exact worked example that teaches a model to
|
|
79
|
+
// WRITE calls instead of making them (see tools/tool-call-parser.js). The
|
|
80
|
+
// name and the arguments are what makes the bullet useful; the parentheses
|
|
81
|
+
// and braces are what makes it dangerous, so only those go.
|
|
82
|
+
function deFangToolRow(text) {
|
|
83
|
+
const m = String(text ?? "").match(/^\[tool result:\s*([^\]\n]+)\]\s*([\s\S]*)$/);
|
|
84
|
+
if (!m) return text;
|
|
85
|
+
const name = m[1].trim();
|
|
86
|
+
let body = m[2].trim();
|
|
87
|
+
if (body.startsWith(`${name}(`) && body.endsWith(")")) body = body.slice(name.length + 1, -1);
|
|
88
|
+
return `${name} → ${body.replace(/[{}]/g, "")}`.trim();
|
|
89
|
+
}
|
|
90
|
+
|
|
76
91
|
function bulletFor({ date, channel, text }) {
|
|
77
92
|
const d = date ? `[${date}]` : "";
|
|
78
93
|
const c = channel && channel !== "memory" ? `[${channel}]` : channel === "memory" ? "[memory]" : "";
|
|
@@ -129,7 +144,7 @@ export async function buildMemoryBlock(message, opts = {}) {
|
|
|
129
144
|
push({
|
|
130
145
|
date: dateOf(h.ts),
|
|
131
146
|
channel: h.tag === "memory" ? "memory" : h.channel,
|
|
132
|
-
text: h.text
|
|
147
|
+
text: deFangToolRow(h.text),
|
|
133
148
|
});
|
|
134
149
|
}
|
|
135
150
|
for (const e of memEntries) {
|