@agentprojectcontext/apx 1.25.0 → 1.27.2
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 +42 -12
- package/skills/apx/SKILL.md +50 -119
- package/skills/apx-agency-agents/SKILL.md +141 -0
- package/skills/apx-agent/SKILL.md +100 -0
- package/skills/apx-mcp/SKILL.md +114 -0
- package/skills/apx-mcp-builder/SKILL.md +186 -0
- package/skills/apx-project/SKILL.md +100 -0
- package/skills/apx-routine/SKILL.md +138 -0
- package/skills/apx-runtime/SKILL.md +115 -0
- package/skills/apx-sessions/SKILL.md +281 -0
- package/skills/apx-skill-builder/SKILL.md +149 -0
- package/skills/apx-task/SKILL.md +95 -0
- package/skills/apx-telegram/SKILL.md +115 -0
- package/skills/apx-voice/SKILL.md +135 -0
- package/src/core/agent/constants.js +3 -0
- package/src/core/agent/ghost-guard.js +24 -0
- package/src/core/agent/index.js +35 -0
- package/src/core/agent/model-router.js +257 -0
- package/src/core/agent/prompt-builder.js +313 -0
- package/src/core/agent/prompts/channels/api.md +7 -0
- package/src/core/agent/prompts/channels/cli.md +6 -0
- package/src/core/agent/prompts/channels/code.md +20 -0
- package/src/core/agent/prompts/channels/deck.md +6 -0
- package/src/core/agent/prompts/channels/desktop.md +24 -0
- package/src/core/agent/prompts/channels/routine.md +9 -0
- package/src/core/agent/prompts/channels/telegram.md +9 -0
- package/src/core/agent/prompts/channels/terminal.md +16 -0
- package/src/core/agent/prompts/channels/web.md +7 -0
- package/src/core/agent/prompts/channels/web_sidebar.md +7 -0
- package/src/core/agent/prompts/modes/voice.md +4 -0
- package/src/core/agent/prompts/super-agent-base.md +42 -0
- package/src/core/agent/pseudo-tools.js +40 -0
- package/src/core/agent/retry.js +85 -0
- package/src/core/agent/run-agent.js +423 -0
- package/src/core/agent/self-memory.js +155 -0
- package/src/{daemon → core/agent}/tool-call-parser.js +83 -10
- package/src/core/agent/tools-overlap.js +66 -0
- package/src/core/apc-skill-sync.js +97 -0
- package/src/core/code-sessions-store.js +150 -0
- package/src/core/config.js +473 -11
- package/src/core/desktop/autostart.js +162 -0
- package/src/core/engines/_health.js +63 -0
- package/src/{daemon → core}/engines/anthropic.js +16 -0
- package/src/core/engines/gemini.js +168 -0
- package/src/core/engines/groq.js +8 -0
- package/src/{daemon → core}/engines/index.js +3 -1
- package/src/{daemon → core}/engines/mock.js +22 -0
- package/src/{daemon → core}/engines/ollama.js +35 -0
- package/src/core/engines/openai-compatible.js +145 -0
- package/src/core/engines/openai.js +8 -0
- package/src/core/engines/openrouter.js +8 -0
- package/src/core/git-baseline.js +147 -0
- package/src/core/identity.js +21 -0
- package/src/core/logging.js +1 -1
- package/src/core/mcp/index.js +14 -0
- package/src/{daemon/mcp-runner.js → core/mcp/runner.js} +18 -6
- package/src/core/mcp/sources.js +246 -0
- package/src/core/memory/active-threads.js +124 -0
- package/src/core/memory/broker.js +144 -0
- package/src/core/memory/compactor.js +186 -0
- package/src/core/memory/embed-engines/gemini.js +62 -0
- package/src/core/memory/embed-engines/index.js +148 -0
- package/src/core/memory/embed-engines/ollama.js +55 -0
- package/src/core/memory/embed-engines/openai.js +64 -0
- package/src/core/memory/embed-engines/tf.js +20 -0
- package/src/core/memory/embeddings.js +132 -0
- package/src/core/memory/index.js +161 -0
- package/src/core/memory/indexer.js +257 -0
- package/src/core/memory/store.js +231 -0
- package/src/core/messages-store.js +143 -25
- package/src/core/parser.js +78 -16
- package/src/core/scaffold.js +175 -79
- package/src/core/tasks-store.js +264 -0
- package/src/core/telegram-identity.js +126 -0
- package/src/core/tools/index.js +6 -0
- package/src/core/voice/engines/elevenlabs.js +96 -0
- package/src/core/voice/engines/gemini.js +148 -0
- package/src/core/voice/engines/index.js +144 -0
- package/src/core/voice/engines/mock.js +59 -0
- package/src/core/voice/engines/openai.js +82 -0
- package/src/core/voice/engines/piper.js +93 -0
- package/src/core/voice/index.js +3 -0
- package/src/core/voice/tts.js +89 -0
- package/src/{daemon → host/daemon}/apc-runtime-context.js +1 -1
- package/src/host/daemon/api/admin-config.js +159 -0
- package/src/host/daemon/api/admin.js +72 -0
- package/src/host/daemon/api/agents.js +284 -0
- package/src/host/daemon/api/artifacts.js +52 -0
- package/src/host/daemon/api/code.js +351 -0
- package/src/host/daemon/api/config.js +104 -0
- package/src/host/daemon/api/connections.js +42 -0
- package/src/host/daemon/api/conversations.js +161 -0
- package/src/host/daemon/api/deck.js +511 -0
- package/src/host/daemon/api/desktop.js +71 -0
- package/src/host/daemon/api/embeddings.js +65 -0
- package/src/host/daemon/api/engines.js +80 -0
- package/src/host/daemon/api/exec.js +193 -0
- package/src/host/daemon/api/health.js +10 -0
- package/src/host/daemon/api/identity.js +36 -0
- package/src/host/daemon/api/mcps.js +205 -0
- package/src/host/daemon/api/messages.js +83 -0
- package/src/host/daemon/api/pairing.js +194 -0
- package/src/host/daemon/api/plugins.js +19 -0
- package/src/host/daemon/api/projects.js +35 -0
- package/src/host/daemon/api/routines.js +84 -0
- package/src/host/daemon/api/run.js +55 -0
- package/src/host/daemon/api/runtimes.js +219 -0
- package/src/host/daemon/api/sessions-search.js +177 -0
- package/src/host/daemon/api/sessions.js +115 -0
- package/src/host/daemon/api/shared.js +217 -0
- package/src/host/daemon/api/super-agent.js +208 -0
- package/src/host/daemon/api/tasks.js +118 -0
- package/src/host/daemon/api/telegram.js +325 -0
- package/src/host/daemon/api/tools.js +21 -0
- package/src/host/daemon/api/top-level.js +131 -0
- package/src/host/daemon/api/transcribe.js +35 -0
- package/src/host/daemon/api/tts.js +44 -0
- package/src/host/daemon/api/voice.js +519 -0
- package/src/host/daemon/api/web.js +123 -0
- package/src/host/daemon/api.js +152 -0
- package/src/{daemon → host/daemon}/compact.js +1 -1
- package/src/{daemon → host/daemon}/db.js +19 -5
- package/src/{daemon/overlay-ws.js → host/daemon/desktop-ws.js} +7 -7
- package/src/host/daemon/engine-sessions.js +245 -0
- package/src/{daemon → host/daemon}/index.js +27 -10
- package/src/{daemon/plugins/overlay.js → host/daemon/plugins/desktop.js} +36 -28
- package/src/{daemon → host/daemon}/plugins/index.js +2 -2
- package/src/{daemon → host/daemon}/plugins/telegram.js +165 -33
- package/src/{daemon → host/daemon}/project-config.js +31 -7
- package/src/{daemon → host/daemon}/routines.js +27 -8
- package/src/{daemon → host/daemon}/skills-loader.js +4 -2
- package/src/{daemon → host/daemon}/smoke.js +9 -5
- package/src/{daemon → host/daemon}/super-agent-tools/helpers.js +1 -1
- package/src/host/daemon/super-agent-tools/index.js +157 -0
- package/src/{daemon → host/daemon}/super-agent-tools/registry-bridge.js +1 -1
- package/src/{daemon → host/daemon}/super-agent-tools/tools/add-project.js +2 -2
- package/src/{daemon → host/daemon}/super-agent-tools/tools/ask-questions.js +4 -0
- package/src/{daemon → host/daemon}/super-agent-tools/tools/call-agent.js +5 -2
- package/src/{daemon → host/daemon}/super-agent-tools/tools/call-runtime.js +117 -8
- package/src/host/daemon/super-agent-tools/tools/create-task.js +52 -0
- package/src/{daemon → host/daemon}/super-agent-tools/tools/import-agent.js +2 -3
- package/src/{daemon → host/daemon}/super-agent-tools/tools/list-agents.js +1 -1
- package/src/host/daemon/super-agent-tools/tools/list-tasks.js +52 -0
- package/src/{daemon → host/daemon}/super-agent-tools/tools/list-vault-agents.js +1 -1
- package/src/host/daemon/super-agent-tools/tools/read-self-memory.js +21 -0
- package/src/host/daemon/super-agent-tools/tools/remember.js +40 -0
- package/src/{daemon → host/daemon}/super-agent-tools/tools/search-messages.js +1 -1
- package/src/host/daemon/super-agent-tools/tools/search-sessions.js +134 -0
- package/src/{daemon → host/daemon}/super-agent-tools/tools/send-telegram.js +2 -2
- package/src/{daemon → host/daemon}/super-agent-tools/tools/set-identity.js +1 -1
- package/src/{daemon → host/daemon}/super-agent-tools/tools/set-permission-mode.js +1 -1
- package/src/{daemon → host/daemon}/super-agent-tools/tools/tail-messages.js +1 -1
- package/src/host/daemon/super-agent.js +129 -0
- package/src/host/daemon/token-store.js +118 -0
- package/src/host/daemon/tool-call-parser.js +2 -0
- package/src/{daemon → host/daemon}/transcription.js +1 -1
- package/src/{daemon → host/daemon}/wakeup.js +2 -2
- package/src/interfaces/cli/claude-permissions.js +33 -0
- package/src/{cli → interfaces/cli}/commands/agent.js +43 -8
- package/src/{cli → interfaces/cli}/commands/command.js +1 -1
- package/src/{cli → interfaces/cli}/commands/config.js +1 -1
- package/src/{cli → interfaces/cli}/commands/daemon.js +67 -0
- package/src/interfaces/cli/commands/desktop.js +335 -0
- package/src/interfaces/cli/commands/exec.js +92 -0
- package/src/{cli → interfaces/cli}/commands/identity.js +6 -63
- package/src/{cli → interfaces/cli}/commands/init.js +1 -1
- package/src/{cli → interfaces/cli}/commands/mcp.js +69 -10
- package/src/{cli → interfaces/cli}/commands/memory.js +2 -2
- package/src/interfaces/cli/commands/model.js +136 -0
- package/src/interfaces/cli/commands/pair.js +170 -0
- package/src/interfaces/cli/commands/project-config.js +131 -0
- package/src/{cli → interfaces/cli}/commands/project.js +1 -1
- package/src/{cli → interfaces/cli}/commands/search.js +1 -1
- package/src/interfaces/cli/commands/session.js +892 -0
- package/src/interfaces/cli/commands/sessions.js +997 -0
- package/src/{cli → interfaces/cli}/commands/setup.js +98 -4
- package/src/{cli → interfaces/cli}/commands/skills.js +117 -9
- package/src/{cli → interfaces/cli}/commands/status.js +9 -1
- package/src/{cli → interfaces/cli}/commands/sys.js +96 -17
- package/src/interfaces/cli/commands/task.js +179 -0
- package/src/interfaces/cli/commands/telegram.js +366 -0
- package/src/{cli → interfaces/cli}/commands/update.js +1 -1
- package/src/interfaces/cli/commands/voice.js +258 -0
- package/src/{cli → interfaces/cli}/http.js +6 -2
- package/src/{cli → interfaces/cli}/index.js +955 -63
- package/src/interfaces/cli/postinstall.js +34 -0
- package/src/interfaces/desktop/assets/app-icon-180.png +0 -0
- package/src/interfaces/desktop/assets/app-icon-32.png +0 -0
- package/src/interfaces/desktop/assets/app-icon.png +0 -0
- package/src/interfaces/desktop/assets/apx-logo.png +0 -0
- package/src/interfaces/desktop/assets/superagent.png +0 -0
- package/src/interfaces/desktop/assets/tray-icon.png +0 -0
- package/src/interfaces/desktop/index.html +18 -0
- package/src/interfaces/desktop/main.js +652 -0
- package/src/interfaces/desktop/preload.js +48 -0
- package/src/interfaces/desktop/renderer.js +1006 -0
- package/src/interfaces/desktop/style.css +400 -0
- package/src/{mcp → interfaces/mcp-server}/index.js +2 -2
- package/src/interfaces/tui/_shims/util-which.ts +53 -0
- package/src/{tui → interfaces/tui}/app.tsx +2 -2
- package/src/{tui → interfaces/tui}/component/prompt/index.tsx +4 -1
- package/src/{tui → interfaces/tui}/context/sdk-apx.tsx +84 -16
- package/src/interfaces/tui/context/sync-apx.tsx +398 -0
- package/src/interfaces/tui/routes/session/index.tsx +368 -0
- package/src/interfaces/tui/routes/session/message-actions.tsx +58 -0
- package/src/interfaces/tui/routes/session/sidebar-apx.tsx +114 -0
- package/src/{tui → interfaces/tui}/tsconfig.json +1 -0
- package/src/{tui → interfaces/tui}/util/clipboard.ts +1 -1
- package/src/interfaces/web/README.md +102 -0
- package/src/interfaces/web/coming-soon.html +65 -0
- package/src/interfaces/web/components.json +25 -0
- package/src/interfaces/web/dist/assets/index-BDUsA6L6.css +1 -0
- package/src/interfaces/web/dist/assets/index-CfWyjPBa.js +548 -0
- package/src/interfaces/web/dist/assets/index-CfWyjPBa.js.map +1 -0
- package/src/interfaces/web/dist/favicon/dark/android-chrome-192x192.png +0 -0
- package/src/interfaces/web/dist/favicon/dark/android-chrome-512x512.png +0 -0
- package/src/interfaces/web/dist/favicon/dark/apple-touch-icon.png +0 -0
- package/src/interfaces/web/dist/favicon/dark/favicon-16x16.png +0 -0
- package/src/interfaces/web/dist/favicon/dark/favicon-32x32.png +0 -0
- package/src/interfaces/web/dist/favicon/dark/favicon-48x48.png +0 -0
- package/src/interfaces/web/dist/favicon/dark/favicon.ico +0 -0
- package/src/interfaces/web/dist/favicon/dark/favicon.webp +0 -0
- package/src/interfaces/web/dist/favicon/dark/site.webmanifest +18 -0
- package/src/interfaces/web/dist/favicon/white/android-chrome-192x192.png +0 -0
- package/src/interfaces/web/dist/favicon/white/android-chrome-512x512.png +0 -0
- package/src/interfaces/web/dist/favicon/white/apple-touch-icon.png +0 -0
- package/src/interfaces/web/dist/favicon/white/favicon-16x16.png +0 -0
- package/src/interfaces/web/dist/favicon/white/favicon-32x32.png +0 -0
- package/src/interfaces/web/dist/favicon/white/favicon-48x48.png +0 -0
- package/src/interfaces/web/dist/favicon/white/favicon.ico +0 -0
- package/src/interfaces/web/dist/favicon/white/favicon.webp +0 -0
- package/src/interfaces/web/dist/favicon/white/site.webmanifest +18 -0
- package/src/interfaces/web/dist/index.html +27 -0
- package/src/interfaces/web/dist/logo/logo_dark.webp +0 -0
- package/src/interfaces/web/dist/logo/logo_only_dark.webp +0 -0
- package/src/interfaces/web/dist/logo/logo_only_white.webp +0 -0
- package/src/interfaces/web/dist/logo/logo_vertical_dark.webp +0 -0
- package/src/interfaces/web/dist/logo/logo_vertical_white.webp +0 -0
- package/src/interfaces/web/dist/logo/logo_white.webp +0 -0
- package/src/interfaces/web/dist/modules/superagent.png +0 -0
- package/src/interfaces/web/index.html +26 -0
- package/src/interfaces/web/package-lock.json +4253 -0
- package/src/interfaces/web/package.json +55 -0
- package/src/interfaces/web/playwright.config.ts +45 -0
- package/src/interfaces/web/pnpm-lock.yaml +2946 -0
- package/src/interfaces/web/public/favicon/dark/android-chrome-192x192.png +0 -0
- package/src/interfaces/web/public/favicon/dark/android-chrome-512x512.png +0 -0
- package/src/interfaces/web/public/favicon/dark/apple-touch-icon.png +0 -0
- package/src/interfaces/web/public/favicon/dark/favicon-16x16.png +0 -0
- package/src/interfaces/web/public/favicon/dark/favicon-32x32.png +0 -0
- package/src/interfaces/web/public/favicon/dark/favicon-48x48.png +0 -0
- package/src/interfaces/web/public/favicon/dark/favicon.ico +0 -0
- package/src/interfaces/web/public/favicon/dark/favicon.webp +0 -0
- package/src/interfaces/web/public/favicon/dark/site.webmanifest +18 -0
- package/src/interfaces/web/public/favicon/white/android-chrome-192x192.png +0 -0
- package/src/interfaces/web/public/favicon/white/android-chrome-512x512.png +0 -0
- package/src/interfaces/web/public/favicon/white/apple-touch-icon.png +0 -0
- package/src/interfaces/web/public/favicon/white/favicon-16x16.png +0 -0
- package/src/interfaces/web/public/favicon/white/favicon-32x32.png +0 -0
- package/src/interfaces/web/public/favicon/white/favicon-48x48.png +0 -0
- package/src/interfaces/web/public/favicon/white/favicon.ico +0 -0
- package/src/interfaces/web/public/favicon/white/favicon.webp +0 -0
- package/src/interfaces/web/public/favicon/white/site.webmanifest +18 -0
- package/src/interfaces/web/public/logo/logo_dark.webp +0 -0
- package/src/interfaces/web/public/logo/logo_only_dark.webp +0 -0
- package/src/interfaces/web/public/logo/logo_only_white.webp +0 -0
- package/src/interfaces/web/public/logo/logo_vertical_dark.webp +0 -0
- package/src/interfaces/web/public/logo/logo_vertical_white.webp +0 -0
- package/src/interfaces/web/public/logo/logo_white.webp +0 -0
- package/src/interfaces/web/public/modules/superagent.png +0 -0
- package/src/interfaces/web/src/App.tsx +199 -0
- package/src/interfaces/web/src/components/AddProjectDialog.tsx +121 -0
- package/src/interfaces/web/src/components/ModelCombobox.tsx +96 -0
- package/src/interfaces/web/src/components/RobyBubble.tsx +213 -0
- package/src/interfaces/web/src/components/Section.tsx +44 -0
- package/src/interfaces/web/src/components/TelegramChannelDialog.tsx +97 -0
- package/src/interfaces/web/src/components/TelegramSendDialog.tsx +48 -0
- package/src/interfaces/web/src/components/Toast.tsx +84 -0
- package/src/interfaces/web/src/components/UiSelect.tsx +74 -0
- package/src/interfaces/web/src/components/chat/Composer.tsx +43 -0
- package/src/interfaces/web/src/components/chat/ContextBar.tsx +111 -0
- package/src/interfaces/web/src/components/chat/MessageBubble.tsx +95 -0
- package/src/interfaces/web/src/components/chat/MessageList.tsx +35 -0
- package/src/interfaces/web/src/components/chat/ModelPicker.tsx +145 -0
- package/src/interfaces/web/src/components/chat/ToolCall.tsx +141 -0
- package/src/interfaces/web/src/components/code/CodeChangesTab.tsx +87 -0
- package/src/interfaces/web/src/components/code/CodeComposer.tsx +87 -0
- package/src/interfaces/web/src/components/code/CodeContextTab.tsx +83 -0
- package/src/interfaces/web/src/components/code/CodeProjectPicker.tsx +39 -0
- package/src/interfaces/web/src/components/code/CodeSessionList.tsx +97 -0
- package/src/interfaces/web/src/components/code/CodeSidePanel.tsx +44 -0
- package/src/interfaces/web/src/components/code/CodeToolTrail.tsx +29 -0
- package/src/interfaces/web/src/components/code/DiffView.tsx +67 -0
- package/src/interfaces/web/src/components/common/Qr.tsx +27 -0
- package/src/interfaces/web/src/components/common/TabLayout.tsx +46 -0
- package/src/interfaces/web/src/components/common/TabNav.tsx +113 -0
- package/src/interfaces/web/src/components/config/ConfigTabsEditor.tsx +202 -0
- package/src/interfaces/web/src/components/config/GlobalConfigEditor.tsx +42 -0
- package/src/interfaces/web/src/components/config/global-config-sections.ts +60 -0
- package/src/interfaces/web/src/components/config/project-config-sections.ts +58 -0
- package/src/interfaces/web/src/components/deck/DaemonCard.tsx +58 -0
- package/src/interfaces/web/src/components/deck/DesktopGroup.tsx +33 -0
- package/src/interfaces/web/src/components/deck/WidgetRow.tsx +100 -0
- package/src/interfaces/web/src/components/layout/Logo.tsx +59 -0
- package/src/interfaces/web/src/components/layout/ProjectAvatar.tsx +116 -0
- package/src/interfaces/web/src/components/layout/ProjectSidebar.tsx +151 -0
- package/src/interfaces/web/src/components/settings/AdvancedPanel.tsx +45 -0
- package/src/interfaces/web/src/components/settings/AppearancePanel.tsx +72 -0
- package/src/interfaces/web/src/components/settings/DefaultRouterCard.tsx +232 -0
- package/src/interfaces/web/src/components/settings/DevicesPanel.tsx +60 -0
- package/src/interfaces/web/src/components/settings/EnginesPanel.tsx +127 -0
- package/src/interfaces/web/src/components/settings/IdentityPanel.tsx +69 -0
- package/src/interfaces/web/src/components/settings/MemoryPanel.tsx +226 -0
- package/src/interfaces/web/src/components/settings/PairDeviceDialog.tsx +175 -0
- package/src/interfaces/web/src/components/settings/SuperAgentPanel.tsx +93 -0
- package/src/interfaces/web/src/components/settings/TelegramChannelsPanel.tsx +90 -0
- package/src/interfaces/web/src/components/settings/TelegramContactsPanel.tsx +101 -0
- package/src/interfaces/web/src/components/settings/TelegramGlobalPanel.tsx +100 -0
- package/src/interfaces/web/src/components/settings/TelegramRolesPanel.tsx +108 -0
- package/src/interfaces/web/src/components/settings/TelegramSettingsTabs.tsx +55 -0
- package/src/interfaces/web/src/components/settings/providers/ProviderCard.tsx +95 -0
- package/src/interfaces/web/src/components/settings/providers/ProviderModal.tsx +405 -0
- package/src/interfaces/web/src/components/settings/providers/typeStyles.ts +155 -0
- package/src/interfaces/web/src/components/settings/providers/types.ts +26 -0
- package/src/interfaces/web/src/components/ui/accordion.tsx +72 -0
- package/src/interfaces/web/src/components/ui/alert-dialog.tsx +187 -0
- package/src/interfaces/web/src/components/ui/alert.tsx +76 -0
- package/src/interfaces/web/src/components/ui/aspect-ratio.tsx +22 -0
- package/src/interfaces/web/src/components/ui/avatar.tsx +107 -0
- package/src/interfaces/web/src/components/ui/badge.tsx +52 -0
- package/src/interfaces/web/src/components/ui/breadcrumb.tsx +125 -0
- package/src/interfaces/web/src/components/ui/button-group.tsx +87 -0
- package/src/interfaces/web/src/components/ui/button.tsx +58 -0
- package/src/interfaces/web/src/components/ui/calendar.tsx +221 -0
- package/src/interfaces/web/src/components/ui/card.tsx +103 -0
- package/src/interfaces/web/src/components/ui/carousel.tsx +242 -0
- package/src/interfaces/web/src/components/ui/chart.tsx +371 -0
- package/src/interfaces/web/src/components/ui/chat-input.tsx +122 -0
- package/src/interfaces/web/src/components/ui/checkbox.tsx +29 -0
- package/src/interfaces/web/src/components/ui/collapsible.tsx +19 -0
- package/src/interfaces/web/src/components/ui/combobox.tsx +295 -0
- package/src/interfaces/web/src/components/ui/command.tsx +196 -0
- package/src/interfaces/web/src/components/ui/context-menu.tsx +271 -0
- package/src/interfaces/web/src/components/ui/dialog.tsx +158 -0
- package/src/interfaces/web/src/components/ui/direction.tsx +4 -0
- package/src/interfaces/web/src/components/ui/drawer.tsx +134 -0
- package/src/interfaces/web/src/components/ui/dropdown-menu.tsx +266 -0
- package/src/interfaces/web/src/components/ui/empty.tsx +104 -0
- package/src/interfaces/web/src/components/ui/field.tsx +236 -0
- package/src/interfaces/web/src/components/ui/hover-card.tsx +51 -0
- package/src/interfaces/web/src/components/ui/input-group.tsx +158 -0
- package/src/interfaces/web/src/components/ui/input-otp.tsx +85 -0
- package/src/interfaces/web/src/components/ui/input.tsx +20 -0
- package/src/interfaces/web/src/components/ui/item.tsx +201 -0
- package/src/interfaces/web/src/components/ui/kbd.tsx +26 -0
- package/src/interfaces/web/src/components/ui/label.tsx +20 -0
- package/src/interfaces/web/src/components/ui/menubar.tsx +280 -0
- package/src/interfaces/web/src/components/ui/native-select.tsx +61 -0
- package/src/interfaces/web/src/components/ui/navigation-menu.tsx +168 -0
- package/src/interfaces/web/src/components/ui/pagination.tsx +130 -0
- package/src/interfaces/web/src/components/ui/popover.tsx +88 -0
- package/src/interfaces/web/src/components/ui/progress.tsx +83 -0
- package/src/interfaces/web/src/components/ui/radio-group.tsx +36 -0
- package/src/interfaces/web/src/components/ui/resizable.tsx +50 -0
- package/src/interfaces/web/src/components/ui/scroll-area.tsx +53 -0
- package/src/interfaces/web/src/components/ui/select.tsx +201 -0
- package/src/interfaces/web/src/components/ui/separator.tsx +23 -0
- package/src/interfaces/web/src/components/ui/sheet.tsx +138 -0
- package/src/interfaces/web/src/components/ui/sidebar.tsx +723 -0
- package/src/interfaces/web/src/components/ui/skeleton.tsx +13 -0
- package/src/interfaces/web/src/components/ui/slider.tsx +52 -0
- package/src/interfaces/web/src/components/ui/sonner.tsx +49 -0
- package/src/interfaces/web/src/components/ui/spinner.tsx +10 -0
- package/src/interfaces/web/src/components/ui/switch.tsx +30 -0
- package/src/interfaces/web/src/components/ui/table.tsx +116 -0
- package/src/interfaces/web/src/components/ui/tabs.tsx +72 -0
- package/src/interfaces/web/src/components/ui/textarea.tsx +18 -0
- package/src/interfaces/web/src/components/ui/tip.tsx +21 -0
- package/src/interfaces/web/src/components/ui/toggle-group.tsx +87 -0
- package/src/interfaces/web/src/components/ui/toggle.tsx +45 -0
- package/src/interfaces/web/src/components/ui/tooltip.tsx +64 -0
- package/src/interfaces/web/src/components/ui.tsx +211 -0
- package/src/interfaces/web/src/components/voice/VoiceProviderList.tsx +197 -0
- package/src/interfaces/web/src/components/voice/VoiceProviderModal.tsx +213 -0
- package/src/interfaces/web/src/components/voice/VoiceSttCard.tsx +72 -0
- package/src/interfaces/web/src/components/voice/VoiceTestCard.tsx +112 -0
- package/src/interfaces/web/src/components/voice/useTtsPlayer.ts +59 -0
- package/src/interfaces/web/src/constants/index.ts +91 -0
- package/src/interfaces/web/src/hooks/use-mobile.ts +19 -0
- package/src/interfaces/web/src/hooks/useChat.ts +276 -0
- package/src/interfaces/web/src/hooks/useDaemonStatus.ts +12 -0
- package/src/interfaces/web/src/hooks/useDevices.ts +12 -0
- package/src/interfaces/web/src/hooks/useEngines.ts +10 -0
- package/src/interfaces/web/src/hooks/useGlobalConfig.ts +24 -0
- package/src/interfaces/web/src/hooks/useIdentity.ts +16 -0
- package/src/interfaces/web/src/hooks/useProjects.ts +27 -0
- package/src/interfaces/web/src/hooks/useTelegram.ts +35 -0
- package/src/interfaces/web/src/hooks/useTheme.tsx +57 -0
- package/src/interfaces/web/src/hooks/useTokenBootstrap.ts +122 -0
- package/src/interfaces/web/src/i18n/en.ts +767 -0
- package/src/interfaces/web/src/i18n/es.ts +770 -0
- package/src/interfaces/web/src/i18n/index.ts +86 -0
- package/src/interfaces/web/src/lib/api/admin.ts +30 -0
- package/src/interfaces/web/src/lib/api/agents.ts +46 -0
- package/src/interfaces/web/src/lib/api/code.ts +122 -0
- package/src/interfaces/web/src/lib/api/conversations.ts +16 -0
- package/src/interfaces/web/src/lib/api/deck.ts +106 -0
- package/src/interfaces/web/src/lib/api/desktop.ts +54 -0
- package/src/interfaces/web/src/lib/api/embeddings.ts +44 -0
- package/src/interfaces/web/src/lib/api/engines.ts +17 -0
- package/src/interfaces/web/src/lib/api/filesystem.ts +12 -0
- package/src/interfaces/web/src/lib/api/health.ts +6 -0
- package/src/interfaces/web/src/lib/api/identity.ts +7 -0
- package/src/interfaces/web/src/lib/api/mcps.ts +29 -0
- package/src/interfaces/web/src/lib/api/messages.ts +24 -0
- package/src/interfaces/web/src/lib/api/projects.ts +29 -0
- package/src/interfaces/web/src/lib/api/routines.ts +14 -0
- package/src/interfaces/web/src/lib/api/sessions.ts +16 -0
- package/src/interfaces/web/src/lib/api/super_agent.ts +29 -0
- package/src/interfaces/web/src/lib/api/tasks.ts +19 -0
- package/src/interfaces/web/src/lib/api/telegram.ts +57 -0
- package/src/interfaces/web/src/lib/api/tools.ts +13 -0
- package/src/interfaces/web/src/lib/api/voice.ts +169 -0
- package/src/interfaces/web/src/lib/api.ts +48 -0
- package/src/interfaces/web/src/lib/cn.ts +6 -0
- package/src/interfaces/web/src/lib/code-context.ts +83 -0
- package/src/interfaces/web/src/lib/config-values.ts +29 -0
- package/src/interfaces/web/src/lib/device.ts +10 -0
- package/src/interfaces/web/src/lib/http.ts +104 -0
- package/src/interfaces/web/src/lib/secrets.ts +15 -0
- package/src/interfaces/web/src/lib/utils.ts +6 -0
- package/src/interfaces/web/src/main.tsx +16 -0
- package/src/interfaces/web/src/screens/ApxAdminScreen.tsx +174 -0
- package/src/interfaces/web/src/screens/PairingScreen.tsx +105 -0
- package/src/interfaces/web/src/screens/ProjectScreen.tsx +178 -0
- package/src/interfaces/web/src/screens/SettingsScreen.tsx +111 -0
- package/src/interfaces/web/src/screens/base/AgentDefaultsTab.tsx +274 -0
- package/src/interfaces/web/src/screens/base/ComingSoon.tsx +16 -0
- package/src/interfaces/web/src/screens/base/GlobalTasksTab.tsx +53 -0
- package/src/interfaces/web/src/screens/base/LogsTab.tsx +188 -0
- package/src/interfaces/web/src/screens/base/ModelsTab.tsx +13 -0
- package/src/interfaces/web/src/screens/base/SessionsTab.tsx +58 -0
- package/src/interfaces/web/src/screens/base/WorkspacesTab.tsx +49 -0
- package/src/interfaces/web/src/screens/modules/CodeScreen.tsx +295 -0
- package/src/interfaces/web/src/screens/modules/DeckScreen.tsx +173 -0
- package/src/interfaces/web/src/screens/modules/DesktopScreen.tsx +304 -0
- package/src/interfaces/web/src/screens/modules/VoiceScreen.tsx +174 -0
- package/src/interfaces/web/src/screens/project/AgentBrainGraph.tsx +152 -0
- package/src/interfaces/web/src/screens/project/AgentDetailScreen.tsx +455 -0
- package/src/interfaces/web/src/screens/project/AgentsTab.tsx +364 -0
- package/src/interfaces/web/src/screens/project/ChatTab.tsx +198 -0
- package/src/interfaces/web/src/screens/project/ConfigTab.tsx +94 -0
- package/src/interfaces/web/src/screens/project/McpsTab.tsx +149 -0
- package/src/interfaces/web/src/screens/project/MemoriesTab.tsx +134 -0
- package/src/interfaces/web/src/screens/project/Overview.tsx +37 -0
- package/src/interfaces/web/src/screens/project/RoutinesTab.tsx +386 -0
- package/src/interfaces/web/src/screens/project/TasksTab.tsx +116 -0
- package/src/interfaces/web/src/screens/project/TelegramTab.tsx +126 -0
- package/src/interfaces/web/src/screens/project/ThreadsTab.tsx +100 -0
- package/src/interfaces/web/src/styles.css +128 -0
- package/src/interfaces/web/src/types/daemon.ts +289 -0
- package/src/interfaces/web/tailwind.config.js +53 -0
- package/src/interfaces/web/tsconfig.json +24 -0
- package/src/interfaces/web/vite.config.ts +50 -0
- package/src/cli/commands/exec.js +0 -56
- package/src/cli/commands/overlay.js +0 -253
- package/src/cli/commands/session.js +0 -395
- package/src/cli/commands/sessions.js +0 -517
- package/src/cli/commands/telegram.js +0 -77
- package/src/cli/postinstall.js +0 -75
- package/src/cli-ts/commands/agent.ts +0 -173
- package/src/cli-ts/commands/chat.ts +0 -119
- package/src/cli-ts/commands/daemon.ts +0 -112
- package/src/cli-ts/commands/exec.ts +0 -109
- package/src/cli-ts/commands/mcp.ts +0 -235
- package/src/cli-ts/commands/session.ts +0 -224
- package/src/cli-ts/commands/status.ts +0 -61
- package/src/cli-ts/http.ts +0 -36
- package/src/cli-ts/index.ts +0 -73
- package/src/cli-ts/ui.ts +0 -107
- package/src/daemon/api.js +0 -1558
- package/src/daemon/engines/gemini.js +0 -56
- package/src/daemon/engines/openai.js +0 -79
- package/src/daemon/mcp-sources.js +0 -114
- package/src/daemon/super-agent-tools/index.js +0 -84
- package/src/daemon/super-agent-tools.js +0 -1
- package/src/daemon/super-agent.js +0 -541
- package/src/overlay/index.html +0 -44
- package/src/overlay/main.js +0 -480
- package/src/overlay/preload.js +0 -34
- package/src/overlay/renderer.js +0 -371
- package/src/overlay/style.css +0 -250
- package/src/tui/context/sync-apx.tsx +0 -284
- package/src/tui/routes/session/index.tsx +0 -274
- package/src/tui/routes/session/sidebar-apx.tsx +0 -90
- /package/src/{daemon → core}/tools/browser.js +0 -0
- /package/src/{daemon → core}/tools/fetch.js +0 -0
- /package/src/{daemon → core}/tools/glob.js +0 -0
- /package/src/{daemon → core}/tools/grep.js +0 -0
- /package/src/{daemon → core}/tools/registry.js +0 -0
- /package/src/{daemon → core}/tools/search.js +0 -0
- /package/src/{daemon → host/daemon}/conversations.js +0 -0
- /package/src/{daemon → host/daemon}/env-detect.js +0 -0
- /package/src/{daemon → host/daemon}/runtimes/_spawn.js +0 -0
- /package/src/{daemon → host/daemon}/runtimes/aider.js +0 -0
- /package/src/{daemon → host/daemon}/runtimes/claude-code.js +0 -0
- /package/src/{daemon → host/daemon}/runtimes/codex.js +0 -0
- /package/src/{daemon → host/daemon}/runtimes/cursor-agent.js +0 -0
- /package/src/{daemon → host/daemon}/runtimes/gemini-cli.js +0 -0
- /package/src/{daemon → host/daemon}/runtimes/index.js +0 -0
- /package/src/{daemon → host/daemon}/runtimes/opencode.js +0 -0
- /package/src/{daemon → host/daemon}/runtimes/qwen-code.js +0 -0
- /package/src/{daemon → host/daemon}/super-agent-tools/tools/call-mcp.js +0 -0
- /package/src/{daemon → host/daemon}/super-agent-tools/tools/edit-file.js +0 -0
- /package/src/{daemon → host/daemon}/super-agent-tools/tools/list-files.js +0 -0
- /package/src/{daemon → host/daemon}/super-agent-tools/tools/list-mcps.js +0 -0
- /package/src/{daemon → host/daemon}/super-agent-tools/tools/list-projects.js +0 -0
- /package/src/{daemon → host/daemon}/super-agent-tools/tools/list-skills.js +0 -0
- /package/src/{daemon → host/daemon}/super-agent-tools/tools/load-skill.js +0 -0
- /package/src/{daemon → host/daemon}/super-agent-tools/tools/read-agent-memory.js +0 -0
- /package/src/{daemon → host/daemon}/super-agent-tools/tools/read-file.js +0 -0
- /package/src/{daemon → host/daemon}/super-agent-tools/tools/run-shell.js +0 -0
- /package/src/{daemon → host/daemon}/super-agent-tools/tools/search-files.js +0 -0
- /package/src/{daemon → host/daemon}/super-agent-tools/tools/transcribe-audio.js +0 -0
- /package/src/{daemon → host/daemon}/super-agent-tools/tools/write-file.js +0 -0
- /package/src/{daemon → host/daemon}/thinking.js +0 -0
- /package/src/{daemon → host/daemon}/whisper-server.py +0 -0
- /package/src/{daemon → host/daemon}/whisper-transcribe.py +0 -0
- /package/src/{cli → interfaces/cli}/commands/a2a.js +0 -0
- /package/src/{cli → interfaces/cli}/commands/artifact.js +0 -0
- /package/src/{cli → interfaces/cli}/commands/chat.js +0 -0
- /package/src/{cli → interfaces/cli}/commands/log.js +0 -0
- /package/src/{cli → interfaces/cli}/commands/messages.js +0 -0
- /package/src/{cli → interfaces/cli}/commands/plugins.js +0 -0
- /package/src/{cli → interfaces/cli}/commands/routine.js +0 -0
- /package/src/{cli → interfaces/cli}/commands/runtime.js +0 -0
- /package/src/{cli → interfaces/cli}/terminal-chat/renderer.js +0 -0
- /package/src/{overlay → interfaces/desktop}/package.json +0 -0
- /package/src/{tui → interfaces/tui}/_shims/cli-error.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/cli-logo.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/cli-ui.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/config-console-state.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/core-any.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/core-binary.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/core-flag.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/core-log.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/lsp-language.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/opencode-any.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/opencode-sdk-v2.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/plugin-tui.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/prompt-display.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/provider-provider.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/session-retry.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/session-schema.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/session-session.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/snapshot.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/tool-any.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/util-error.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/util-filesystem.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/util-format.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/util-iife.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/util-locale.ts +0 -0
- /package/src/{tui → interfaces/tui}/_shims/util-process.ts +0 -0
- /package/src/{tui → interfaces/tui}/asset/charge.wav +0 -0
- /package/src/{tui → interfaces/tui}/asset/pulse-a.wav +0 -0
- /package/src/{tui → interfaces/tui}/asset/pulse-b.wav +0 -0
- /package/src/{tui → interfaces/tui}/asset/pulse-c.wav +0 -0
- /package/src/{tui → interfaces/tui}/attach.ts +0 -0
- /package/src/{tui → interfaces/tui}/component/bg-pulse-render.ts +0 -0
- /package/src/{tui → interfaces/tui}/component/bg-pulse.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/border.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/dialog-agent.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/dialog-console-org.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/dialog-mcp.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/dialog-model.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/dialog-provider.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/dialog-retry-action.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/dialog-session-delete-failed.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/dialog-session-list.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/dialog-session-rename.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/dialog-skill.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/dialog-stash.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/dialog-status.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/dialog-tag.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/dialog-theme-list.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/dialog-variant.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/dialog-workspace-create.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/dialog-workspace-file-changes.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/dialog-workspace-unavailable.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/error-component.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/logo.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/plugin-route-missing.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/prompt/autocomplete.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/prompt/cwd.ts +0 -0
- /package/src/{tui → interfaces/tui}/component/prompt/frecency.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/prompt/history.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/prompt/part.ts +0 -0
- /package/src/{tui → interfaces/tui}/component/prompt/stash.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/prompt/traits.ts +0 -0
- /package/src/{tui → interfaces/tui}/component/spinner.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/startup-loading.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/todo-item.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/use-connected.tsx +0 -0
- /package/src/{tui → interfaces/tui}/component/workspace-label.tsx +0 -0
- /package/src/{tui → interfaces/tui}/config/cwd.ts +0 -0
- /package/src/{tui → interfaces/tui}/config/keybind.ts +0 -0
- /package/src/{tui → interfaces/tui}/config/tui-migrate.ts +0 -0
- /package/src/{tui → interfaces/tui}/config/tui-schema.ts +0 -0
- /package/src/{tui → interfaces/tui}/config/tui.ts +0 -0
- /package/src/{tui → interfaces/tui}/context/aggregate-failures.ts +0 -0
- /package/src/{tui → interfaces/tui}/context/args.tsx +0 -0
- /package/src/{tui → interfaces/tui}/context/command-palette.tsx +0 -0
- /package/src/{tui → interfaces/tui}/context/directory.ts +0 -0
- /package/src/{tui → interfaces/tui}/context/editor-zed.ts +0 -0
- /package/src/{tui → interfaces/tui}/context/editor.ts +0 -0
- /package/src/{tui → interfaces/tui}/context/event-apx.ts +0 -0
- /package/src/{tui → interfaces/tui}/context/event.ts +0 -0
- /package/src/{tui → interfaces/tui}/context/exit.tsx +0 -0
- /package/src/{tui → interfaces/tui}/context/helper.tsx +0 -0
- /package/src/{tui → interfaces/tui}/context/kv.tsx +0 -0
- /package/src/{tui → interfaces/tui}/context/local.tsx +0 -0
- /package/src/{tui → interfaces/tui}/context/path-format.tsx +0 -0
- /package/src/{tui → interfaces/tui}/context/project-apx.tsx +0 -0
- /package/src/{tui → interfaces/tui}/context/project.tsx +0 -0
- /package/src/{tui → interfaces/tui}/context/prompt.tsx +0 -0
- /package/src/{tui → interfaces/tui}/context/route.tsx +0 -0
- /package/src/{tui → interfaces/tui}/context/sdk.tsx +0 -0
- /package/src/{tui → interfaces/tui}/context/sync-v2.tsx +0 -0
- /package/src/{tui → interfaces/tui}/context/sync.tsx +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/aura.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/ayu.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/carbonfox.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/catppuccin-frappe.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/catppuccin-macchiato.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/catppuccin.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/cobalt2.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/cursor.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/dracula.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/everforest.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/flexoki.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/github.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/gruvbox.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/kanagawa.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/lucent-orng.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/material.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/matrix.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/mercury.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/monokai.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/nightowl.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/nord.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/one-dark.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/opencode.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/orng.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/osaka-jade.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/palenight.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/rosepine.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/solarized.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/synthwave84.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/tokyonight.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/vercel.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/vesper.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme/zenburn.json +0 -0
- /package/src/{tui → interfaces/tui}/context/theme.tsx +0 -0
- /package/src/{tui → interfaces/tui}/context/tui-config.tsx +0 -0
- /package/src/{tui → interfaces/tui}/event.ts +0 -0
- /package/src/{tui → interfaces/tui}/feature-plugins/home/footer.tsx +0 -0
- /package/src/{tui → interfaces/tui}/feature-plugins/home/tips-view.tsx +0 -0
- /package/src/{tui → interfaces/tui}/feature-plugins/home/tips.tsx +0 -0
- /package/src/{tui → interfaces/tui}/feature-plugins/sidebar/context.tsx +0 -0
- /package/src/{tui → interfaces/tui}/feature-plugins/sidebar/files.tsx +0 -0
- /package/src/{tui → interfaces/tui}/feature-plugins/sidebar/footer.tsx +0 -0
- /package/src/{tui → interfaces/tui}/feature-plugins/sidebar/lsp.tsx +0 -0
- /package/src/{tui → interfaces/tui}/feature-plugins/sidebar/mcp.tsx +0 -0
- /package/src/{tui → interfaces/tui}/feature-plugins/sidebar/todo.tsx +0 -0
- /package/src/{tui → interfaces/tui}/feature-plugins/system/plugins.tsx +0 -0
- /package/src/{tui → interfaces/tui}/feature-plugins/system/session-v2.tsx +0 -0
- /package/src/{tui → interfaces/tui}/feature-plugins/system/which-key.tsx +0 -0
- /package/src/{tui → interfaces/tui}/keymap.tsx +0 -0
- /package/src/{tui → interfaces/tui}/layer.ts +0 -0
- /package/src/{tui → interfaces/tui}/plugin/api.tsx +0 -0
- /package/src/{tui → interfaces/tui}/plugin/command-shim.ts +0 -0
- /package/src/{tui → interfaces/tui}/plugin/internal.ts +0 -0
- /package/src/{tui → interfaces/tui}/plugin/runtime.ts +0 -0
- /package/src/{tui → interfaces/tui}/plugin/slots.tsx +0 -0
- /package/src/{tui → interfaces/tui}/routes/home.tsx +0 -0
- /package/src/{tui → interfaces/tui}/routes/session/dialog-fork-from-timeline.tsx +0 -0
- /package/src/{tui → interfaces/tui}/routes/session/dialog-message.tsx +0 -0
- /package/src/{tui → interfaces/tui}/routes/session/dialog-subagent.tsx +0 -0
- /package/src/{tui → interfaces/tui}/routes/session/dialog-timeline.tsx +0 -0
- /package/src/{tui → interfaces/tui}/routes/session/footer.tsx +0 -0
- /package/src/{tui → interfaces/tui}/routes/session/permission.tsx +0 -0
- /package/src/{tui → interfaces/tui}/routes/session/question.tsx +0 -0
- /package/src/{tui → interfaces/tui}/routes/session/sidebar.tsx +0 -0
- /package/src/{tui → interfaces/tui}/routes/session/subagent-footer.tsx +0 -0
- /package/src/{tui → interfaces/tui}/run.ts +0 -0
- /package/src/{tui → interfaces/tui}/thread.ts +0 -0
- /package/src/{tui → interfaces/tui}/ui/dialog-alert.tsx +0 -0
- /package/src/{tui → interfaces/tui}/ui/dialog-confirm.tsx +0 -0
- /package/src/{tui → interfaces/tui}/ui/dialog-export-options.tsx +0 -0
- /package/src/{tui → interfaces/tui}/ui/dialog-help.tsx +0 -0
- /package/src/{tui → interfaces/tui}/ui/dialog-prompt.tsx +0 -0
- /package/src/{tui → interfaces/tui}/ui/dialog-select.tsx +0 -0
- /package/src/{tui → interfaces/tui}/ui/dialog.tsx +0 -0
- /package/src/{tui → interfaces/tui}/ui/link.tsx +0 -0
- /package/src/{tui → interfaces/tui}/ui/spinner.ts +0 -0
- /package/src/{tui → interfaces/tui}/ui/toast.tsx +0 -0
- /package/src/{tui → interfaces/tui}/util/editor.ts +0 -0
- /package/src/{tui → interfaces/tui}/util/model.ts +0 -0
- /package/src/{tui → interfaces/tui}/util/provider-origin.ts +0 -0
- /package/src/{tui → interfaces/tui}/util/revert-diff.ts +0 -0
- /package/src/{tui → interfaces/tui}/util/scroll.ts +0 -0
- /package/src/{tui → interfaces/tui}/util/selection.ts +0 -0
- /package/src/{tui → interfaces/tui}/util/signal.ts +0 -0
- /package/src/{tui → interfaces/tui}/util/sound.ts +0 -0
- /package/src/{tui → interfaces/tui}/util/transcript.ts +0 -0
- /package/src/{tui → interfaces/tui}/validate-session.ts +0 -0
- /package/src/{tui → interfaces/tui}/win32.ts +0 -0
- /package/src/{tui → interfaces/tui}/worker.ts +0 -0
|
@@ -0,0 +1,892 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { spawn } from "node:child_process";
|
|
4
|
+
import { findApfRoot, readAgents } from "../../../core/parser.js";
|
|
5
|
+
import { getOrCreateApxId } from "../../../core/scaffold.js";
|
|
6
|
+
import { generateSessionId } from "../../../core/session-store.js";
|
|
7
|
+
import { projectStorageRoot, ensureProjectStorage } from "../../../core/config.js";
|
|
8
|
+
import { http } from "../http.js";
|
|
9
|
+
import { resolveProjectId } from "./project.js";
|
|
10
|
+
import {
|
|
11
|
+
ENGINES,
|
|
12
|
+
findSessionAcrossEngines,
|
|
13
|
+
findSessionInEngine,
|
|
14
|
+
} from "./sessions.js";
|
|
15
|
+
|
|
16
|
+
const STALE_HOURS = 1;
|
|
17
|
+
|
|
18
|
+
function requireRoot() {
|
|
19
|
+
const root = findApfRoot();
|
|
20
|
+
if (!root) throw new Error("not inside an APC project (run `apx init` first)");
|
|
21
|
+
return root;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function requireStorageRoot(root) {
|
|
25
|
+
const apxId = getOrCreateApxId(root);
|
|
26
|
+
if (!apxId) throw new Error("could not resolve APX project storage id");
|
|
27
|
+
return projectStorageRoot(apxId);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const nowIso = () => new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
31
|
+
|
|
32
|
+
function readStdinSync() {
|
|
33
|
+
const chunks = [];
|
|
34
|
+
const buf = Buffer.alloc(65536);
|
|
35
|
+
try {
|
|
36
|
+
while (true) {
|
|
37
|
+
const bytes = fs.readSync(0, buf, 0, buf.length);
|
|
38
|
+
if (!bytes) break;
|
|
39
|
+
chunks.push(buf.slice(0, bytes).toString("utf8"));
|
|
40
|
+
}
|
|
41
|
+
} catch {}
|
|
42
|
+
return chunks.join("");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function parseFrontmatter(text) {
|
|
46
|
+
if (!text.startsWith("---\n")) return { fm: {}, bodyStart: 0 };
|
|
47
|
+
const end = text.indexOf("\n---", 4);
|
|
48
|
+
if (end === -1) return { fm: {}, bodyStart: 0 };
|
|
49
|
+
const fmText = text.slice(4, end);
|
|
50
|
+
const fm = {};
|
|
51
|
+
for (const line of fmText.split("\n")) {
|
|
52
|
+
const m = line.match(/^([a-zA-Z_]+):\s*(.*)$/);
|
|
53
|
+
if (m) fm[m[1]] = m[2].trim();
|
|
54
|
+
}
|
|
55
|
+
return { fm, bodyStart: end + 4 };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function setFrontmatterField(text, field, value) {
|
|
59
|
+
if (!text.startsWith("---\n")) return text;
|
|
60
|
+
const end = text.indexOf("\n---", 4);
|
|
61
|
+
if (end === -1) return text;
|
|
62
|
+
const fmText = text.slice(4, end);
|
|
63
|
+
const lines = fmText.split("\n");
|
|
64
|
+
let found = false;
|
|
65
|
+
const out = lines.map((line) => {
|
|
66
|
+
if (line.match(new RegExp(`^${field}:`))) {
|
|
67
|
+
found = true;
|
|
68
|
+
return `${field}: ${value}`;
|
|
69
|
+
}
|
|
70
|
+
return line;
|
|
71
|
+
});
|
|
72
|
+
if (!found) out.push(`${field}: ${value}`);
|
|
73
|
+
return `---\n${out.join("\n")}\n---${text.slice(end + 4)}`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function listAllSessions(root) {
|
|
77
|
+
const agentsDir = path.join(requireStorageRoot(root), "agents");
|
|
78
|
+
if (!fs.existsSync(agentsDir)) return [];
|
|
79
|
+
const out = [];
|
|
80
|
+
for (const slug of fs.readdirSync(agentsDir)) {
|
|
81
|
+
const dir = path.join(agentsDir, slug, "sessions");
|
|
82
|
+
if (!fs.existsSync(dir)) continue;
|
|
83
|
+
for (const f of fs.readdirSync(dir)) {
|
|
84
|
+
if (!f.endsWith(".md")) continue;
|
|
85
|
+
const filepath = path.join(dir, f);
|
|
86
|
+
const body = fs.readFileSync(filepath, "utf8");
|
|
87
|
+
const { fm } = parseFrontmatter(body);
|
|
88
|
+
out.push({
|
|
89
|
+
agent: slug,
|
|
90
|
+
filename: f,
|
|
91
|
+
path: filepath,
|
|
92
|
+
id: fm.id || f.replace(/\.md$/, ""),
|
|
93
|
+
title: fm.title || "(no title)",
|
|
94
|
+
status: fm.status || "",
|
|
95
|
+
started: fm.started || "",
|
|
96
|
+
completed: fm.completed || "",
|
|
97
|
+
result: fm.result || "",
|
|
98
|
+
task_ref: fm.task_ref || "",
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return out;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function findSessionById(root, id) {
|
|
106
|
+
for (const s of listAllSessions(root)) {
|
|
107
|
+
if (s.id === id || s.filename.replace(/\.md$/, "") === id) return s;
|
|
108
|
+
}
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function statusEmoji(status) {
|
|
113
|
+
if (/complete/i.test(status)) return "✅";
|
|
114
|
+
if (/in.progress/i.test(status)) return "🔄";
|
|
115
|
+
if (/stale|closed/i.test(status)) return "⚠️";
|
|
116
|
+
return "❓";
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function hoursSince(iso) {
|
|
120
|
+
if (!iso) return Infinity;
|
|
121
|
+
const t = Date.parse(iso);
|
|
122
|
+
if (isNaN(t)) return Infinity;
|
|
123
|
+
return (Date.now() - t) / 3600_000;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ---------------------------------------------------------------------
|
|
127
|
+
|
|
128
|
+
export function cmdSessionNew(args) {
|
|
129
|
+
const slug = args._[0];
|
|
130
|
+
if (!slug) throw new Error("apx session new: missing <agent-slug>");
|
|
131
|
+
const title = args.flags.title === true ? null : args.flags.title;
|
|
132
|
+
if (!title) throw new Error("apx session new: --title required");
|
|
133
|
+
|
|
134
|
+
const root = requireRoot();
|
|
135
|
+
const agents = readAgents(root);
|
|
136
|
+
if (!agents.find((a) => a.slug === slug)) {
|
|
137
|
+
throw new Error(`agent "${slug}" not found in AGENTS.md`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const storageRoot = requireStorageRoot(root);
|
|
141
|
+
const id = generateSessionId(storageRoot, slug);
|
|
142
|
+
const filename = `${id}.md`;
|
|
143
|
+
const filepath = path.join(storageRoot, "agents", slug, "sessions", filename);
|
|
144
|
+
fs.mkdirSync(path.dirname(filepath), { recursive: true });
|
|
145
|
+
|
|
146
|
+
const taskRef = args.flags["task-ref"] === true ? "" : (args.flags["task-ref"] || "");
|
|
147
|
+
let body = "";
|
|
148
|
+
if (args.flags.body === "-") body = readStdinSync();
|
|
149
|
+
else if (args.flags.body && args.flags.body !== true) body = String(args.flags.body);
|
|
150
|
+
|
|
151
|
+
const started = nowIso();
|
|
152
|
+
const content =
|
|
153
|
+
`---\n` +
|
|
154
|
+
`id: ${id}\n` +
|
|
155
|
+
`agent: ${slug}\n` +
|
|
156
|
+
`title: ${title}\n` +
|
|
157
|
+
`description: \n` +
|
|
158
|
+
`task_ref: ${taskRef}\n` +
|
|
159
|
+
`status: open\n` +
|
|
160
|
+
`date: ${started.slice(0, 10)}\n` +
|
|
161
|
+
`started: ${started}\n` +
|
|
162
|
+
`completed: \n` +
|
|
163
|
+
`---\n\n` +
|
|
164
|
+
`# ${title}\n\n${body}\n`;
|
|
165
|
+
|
|
166
|
+
fs.writeFileSync(filepath, content);
|
|
167
|
+
console.log(`✅ Session created: ${id}`);
|
|
168
|
+
console.log(` Agent: ${slug}`);
|
|
169
|
+
console.log(` Title: ${title}`);
|
|
170
|
+
console.log(` File: ${path.relative(process.cwd(), filepath)}`);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function cmdSessionList(args) {
|
|
174
|
+
const root = requireRoot();
|
|
175
|
+
const slug = args._[0];
|
|
176
|
+
const limit = args.flags.last ? parseInt(args.flags.last, 10) : null;
|
|
177
|
+
|
|
178
|
+
let sessions = listAllSessions(root);
|
|
179
|
+
if (slug) sessions = sessions.filter((s) => s.agent === slug);
|
|
180
|
+
sessions.sort((a, b) => b.filename.localeCompare(a.filename));
|
|
181
|
+
if (limit) sessions = sessions.slice(0, limit);
|
|
182
|
+
|
|
183
|
+
if (sessions.length === 0) {
|
|
184
|
+
console.log("(no sessions)");
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
console.log(
|
|
189
|
+
`${"ID".padEnd(16)} ${"S".padEnd(2)} ${"AGENT".padEnd(12)} TITLE`
|
|
190
|
+
);
|
|
191
|
+
console.log(
|
|
192
|
+
`${"─".repeat(14).padEnd(16)} ${"─".repeat(1).padEnd(2)} ${"─".repeat(10).padEnd(12)} ${"─".repeat(40)}`
|
|
193
|
+
);
|
|
194
|
+
for (const s of sessions) {
|
|
195
|
+
console.log(
|
|
196
|
+
`${s.id.padEnd(16)} ${statusEmoji(s.status).padEnd(2)} ${s.agent.padEnd(12)} ${s.title.slice(0, 60)}`
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* `apx session get <id>` — single-record fetch.
|
|
203
|
+
*
|
|
204
|
+
* - Default: search the current APC project's local sessions (legacy
|
|
205
|
+
* behaviour, fast, no daemon, no engine scan).
|
|
206
|
+
* - --engine <id> : look only inside that engine's storage (apx, claude,
|
|
207
|
+
* codex). Useful when you want the raw transcript of a
|
|
208
|
+
* Claude/Codex session by id.
|
|
209
|
+
* - --any : search across every detected engine, complain on
|
|
210
|
+
* collisions. Equivalent to how resume auto-detects.
|
|
211
|
+
* - --body : print full file body (markdown for apx, JSONL for
|
|
212
|
+
* engines). With --engine or --any you also get the tail
|
|
213
|
+
* of the external transcript when present.
|
|
214
|
+
* - --tail N : print last N bytes of the transcript.
|
|
215
|
+
* - --full : print the entire transcript (overrides --tail).
|
|
216
|
+
* - --json : print metadata as JSON (machine-readable).
|
|
217
|
+
*/
|
|
218
|
+
export function cmdSessionGet(args) {
|
|
219
|
+
const id = args._[0];
|
|
220
|
+
if (!id) throw new Error("apx session get: missing <id>");
|
|
221
|
+
|
|
222
|
+
const engineFlag = args.flags.engine;
|
|
223
|
+
const wantAny = !!args.flags.any || !!args.flags.all;
|
|
224
|
+
|
|
225
|
+
// Engine / any modes — search engine storage directly, no APC root needed.
|
|
226
|
+
if (engineFlag || wantAny) {
|
|
227
|
+
let hits;
|
|
228
|
+
if (engineFlag && engineFlag !== true) {
|
|
229
|
+
const hit = findSessionInEngine(String(engineFlag), id);
|
|
230
|
+
hits = hit ? [hit] : [];
|
|
231
|
+
} else {
|
|
232
|
+
hits = findSessionAcrossEngines(id);
|
|
233
|
+
}
|
|
234
|
+
if (hits.length === 0) {
|
|
235
|
+
throw new Error(`session "${id}" not found in any detected engine`);
|
|
236
|
+
}
|
|
237
|
+
if (hits.length > 1) {
|
|
238
|
+
console.error(`⚠️ session id "${id}" exists in multiple engines:`);
|
|
239
|
+
for (const h of hits) console.error(` - ${h.engine}: ${h.path}`);
|
|
240
|
+
throw new Error(`use --engine <id> to disambiguate`);
|
|
241
|
+
}
|
|
242
|
+
return printEngineSession(hits[0], args);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Legacy / default — local APC project session lookup.
|
|
246
|
+
const root = requireRoot();
|
|
247
|
+
const s = findSessionById(root, id);
|
|
248
|
+
if (!s) {
|
|
249
|
+
throw new Error(
|
|
250
|
+
`session "${id}" not found in this APC project — try \`apx session get ${id} --any\` to search every engine`
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
if (args.flags.json) {
|
|
254
|
+
console.log(
|
|
255
|
+
JSON.stringify(
|
|
256
|
+
{
|
|
257
|
+
id: s.id,
|
|
258
|
+
agent: s.agent,
|
|
259
|
+
title: s.title,
|
|
260
|
+
status: s.status,
|
|
261
|
+
started: s.started,
|
|
262
|
+
completed: s.completed,
|
|
263
|
+
task_ref: s.task_ref,
|
|
264
|
+
result: s.result,
|
|
265
|
+
path: s.path,
|
|
266
|
+
},
|
|
267
|
+
null,
|
|
268
|
+
2
|
|
269
|
+
)
|
|
270
|
+
);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
if (args.flags.body || args.flags.full) {
|
|
274
|
+
process.stdout.write(fs.readFileSync(s.path, "utf8"));
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
console.log(`id: ${s.id}`);
|
|
278
|
+
console.log(`agent: ${s.agent}`);
|
|
279
|
+
console.log(`title: ${s.title}`);
|
|
280
|
+
console.log(`status: ${s.status}`);
|
|
281
|
+
console.log(`started: ${s.started}`);
|
|
282
|
+
console.log(`completed: ${s.completed}`);
|
|
283
|
+
console.log(`task_ref: ${s.task_ref}`);
|
|
284
|
+
console.log(`result: ${s.result}`);
|
|
285
|
+
console.log(`file: ${path.relative(process.cwd(), s.path)}`);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Print one engine session (apx | claude | codex). Shared by both
|
|
289
|
+
// `apx session get --engine ...` and `apx session resume <id>`.
|
|
290
|
+
function printEngineSession(meta, args) {
|
|
291
|
+
const engine = ENGINES[meta.engine];
|
|
292
|
+
const tailBytes = parseTailBytes(args.flags.tail);
|
|
293
|
+
const reading = engine.readSession(meta, { tailBytes: tailBytes || 64 * 1024 });
|
|
294
|
+
|
|
295
|
+
if (args.flags.json) {
|
|
296
|
+
console.log(
|
|
297
|
+
JSON.stringify(
|
|
298
|
+
{
|
|
299
|
+
engine: meta.engine,
|
|
300
|
+
id: meta.id,
|
|
301
|
+
path: meta.path,
|
|
302
|
+
cwd: meta.cwd,
|
|
303
|
+
mtime: meta.mtime,
|
|
304
|
+
title: meta.title,
|
|
305
|
+
agent_slug: meta.agentSlug || null,
|
|
306
|
+
format: reading.format || null,
|
|
307
|
+
size: reading.size || 0,
|
|
308
|
+
external: reading.external
|
|
309
|
+
? { path: reading.external.path, size: reading.external.size }
|
|
310
|
+
: null,
|
|
311
|
+
},
|
|
312
|
+
null,
|
|
313
|
+
2
|
|
314
|
+
)
|
|
315
|
+
);
|
|
316
|
+
if (args.flags.body || args.flags.full) process.stdout.write(reading.raw || "");
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
console.log(`# session ${meta.id} (engine: ${meta.engine})`);
|
|
321
|
+
console.log(`path: ${meta.path}`);
|
|
322
|
+
if (meta.cwd) console.log(`cwd: ${meta.cwd}`);
|
|
323
|
+
if (meta.title) console.log(`title: ${meta.title}`);
|
|
324
|
+
if (meta.agentSlug) console.log(`agent: ${meta.agentSlug}`);
|
|
325
|
+
console.log("");
|
|
326
|
+
if (!reading.found) {
|
|
327
|
+
console.log("(transcript file no longer exists on disk)");
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
const wantFull = !!args.flags.full || !!args.flags.body;
|
|
331
|
+
const explicitTail = tailBytes !== null && tailBytes !== undefined;
|
|
332
|
+
if (wantFull) {
|
|
333
|
+
console.log("--- transcript (full) ---");
|
|
334
|
+
process.stdout.write(reading.raw);
|
|
335
|
+
} else if (explicitTail) {
|
|
336
|
+
console.log(`--- transcript (last ${reading.tail.length} bytes) ---`);
|
|
337
|
+
process.stdout.write(reading.tail);
|
|
338
|
+
} else {
|
|
339
|
+
// Default summary view: counts + hint, no body dump.
|
|
340
|
+
console.log(`format: ${reading.format} (${reading.size} bytes)`);
|
|
341
|
+
if (reading.external) {
|
|
342
|
+
console.log(
|
|
343
|
+
`external: ${reading.external.path} (${reading.external.size} bytes)`
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
console.log(
|
|
347
|
+
`(use --body / --full to dump the transcript, or --tail N for last N bytes)`
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Parse --tail value. "--tail" alone → default 16KB. "--tail 32k" / "--tail
|
|
353
|
+
// 8000" / "--tail 1M" → explicit byte count. Returns null when --tail absent,
|
|
354
|
+
// undefined when --tail is true (no value).
|
|
355
|
+
function parseTailBytes(flag) {
|
|
356
|
+
if (flag === undefined) return null;
|
|
357
|
+
if (flag === true) return 16 * 1024;
|
|
358
|
+
const s = String(flag).trim().toLowerCase();
|
|
359
|
+
const m = s.match(/^(\d+)\s*([kmg]?)$/);
|
|
360
|
+
if (!m) {
|
|
361
|
+
const n = parseInt(s, 10);
|
|
362
|
+
return Number.isFinite(n) ? n : 16 * 1024;
|
|
363
|
+
}
|
|
364
|
+
const n = parseInt(m[1], 10);
|
|
365
|
+
const unit = m[2];
|
|
366
|
+
if (unit === "k") return n * 1024;
|
|
367
|
+
if (unit === "m") return n * 1024 * 1024;
|
|
368
|
+
if (unit === "g") return n * 1024 * 1024 * 1024;
|
|
369
|
+
return n;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
export function cmdSessionUpdate(args) {
|
|
373
|
+
const id = args._[0];
|
|
374
|
+
if (!id) throw new Error("apx session update: missing <id>");
|
|
375
|
+
const root = requireRoot();
|
|
376
|
+
const s = findSessionById(root, id);
|
|
377
|
+
if (!s) throw new Error(`session "${id}" not found`);
|
|
378
|
+
|
|
379
|
+
let text = fs.readFileSync(s.path, "utf8");
|
|
380
|
+
const fields = ["status", "result", "title", "task_ref", "completed"];
|
|
381
|
+
let touched = [];
|
|
382
|
+
for (const k of fields) {
|
|
383
|
+
if (args.flags[k] !== undefined && args.flags[k] !== true) {
|
|
384
|
+
text = setFrontmatterField(text, k, args.flags[k]);
|
|
385
|
+
touched.push(k);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
if (touched.length === 0) throw new Error("apx session update: no fields provided");
|
|
389
|
+
fs.writeFileSync(s.path, text);
|
|
390
|
+
console.log(`updated ${s.id}: ${touched.join(", ")}`);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export function cmdSessionClose(args) {
|
|
394
|
+
const id = args._[0];
|
|
395
|
+
if (!id) throw new Error("apx session close: missing <id>");
|
|
396
|
+
const root = requireRoot();
|
|
397
|
+
const s = findSessionById(root, id);
|
|
398
|
+
if (!s) throw new Error(`session "${id}" not found`);
|
|
399
|
+
|
|
400
|
+
let text = fs.readFileSync(s.path, "utf8");
|
|
401
|
+
text = setFrontmatterField(text, "status", "✅ Completed");
|
|
402
|
+
text = setFrontmatterField(text, "completed", nowIso());
|
|
403
|
+
if (args.flags.result && args.flags.result !== true) {
|
|
404
|
+
text = setFrontmatterField(text, "result", String(args.flags.result));
|
|
405
|
+
}
|
|
406
|
+
fs.writeFileSync(s.path, text);
|
|
407
|
+
console.log(`✅ Session ${s.id} closed`);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
export function cmdSessionCheck() {
|
|
411
|
+
const root = requireRoot();
|
|
412
|
+
const sessions = listAllSessions(root).filter((s) =>
|
|
413
|
+
/in.progress/i.test(s.status)
|
|
414
|
+
);
|
|
415
|
+
|
|
416
|
+
if (sessions.length === 0) {
|
|
417
|
+
console.log("✅ No active sessions. Safe to proceed.");
|
|
418
|
+
process.exit(0);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
let active = 0;
|
|
422
|
+
let stale = [];
|
|
423
|
+
for (const s of sessions) {
|
|
424
|
+
const h = hoursSince(s.started);
|
|
425
|
+
if (h >= STALE_HOURS) {
|
|
426
|
+
stale.push({ ...s, hours: h });
|
|
427
|
+
} else {
|
|
428
|
+
console.log(`🔄 ACTIVE: ${s.id} (${s.hours = h.toFixed(1)}h ago)`);
|
|
429
|
+
console.log(` Agent: ${s.agent}`);
|
|
430
|
+
console.log(` Title: ${s.title}`);
|
|
431
|
+
active++;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
if (stale.length) {
|
|
435
|
+
console.log(`\nStale sessions (>${STALE_HOURS}h, can be auto-closed):`);
|
|
436
|
+
for (const s of stale) {
|
|
437
|
+
console.log(`⚠️ ${s.id} (${s.hours.toFixed(1)}h) — ${s.agent} — ${s.title}`);
|
|
438
|
+
}
|
|
439
|
+
console.log(` → Run: apx session close-stale`);
|
|
440
|
+
}
|
|
441
|
+
if (active === 0) {
|
|
442
|
+
console.log("✅ Safe to proceed (only stale sessions).");
|
|
443
|
+
process.exit(0);
|
|
444
|
+
}
|
|
445
|
+
console.log("\n⛔ Another agent is working. Wait or coordinate.");
|
|
446
|
+
process.exit(1);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* `apx session resume <id>` — locate a session by id across every detected
|
|
451
|
+
* engine (apx | claude | codex), then optionally:
|
|
452
|
+
*
|
|
453
|
+
* --engine <id> restrict the search to one engine.
|
|
454
|
+
* --summary run the super-agent over the transcript tail (needs
|
|
455
|
+
* the daemon + super-agent configured).
|
|
456
|
+
* --tail N|--full print the transcript (last N bytes, or everything).
|
|
457
|
+
* --continue spawn the native CLI to resume the session
|
|
458
|
+
* interactively (claude --resume, codex resume, …).
|
|
459
|
+
* --into apx[:slug] create a *new* APX session whose body is the summary
|
|
460
|
+
* of <id>, so a fresh chat can pick up the thread.
|
|
461
|
+
*
|
|
462
|
+
* No --engine + multiple matches → list collisions and exit non-zero, so the
|
|
463
|
+
* caller can re-run with --engine.
|
|
464
|
+
*/
|
|
465
|
+
// Resolve a single session by id across engines (or one engine via --engine).
|
|
466
|
+
// Throws on zero matches; on a multi-engine collision it prints the candidates
|
|
467
|
+
// and exits with code 2 (shared by resume / summary / ask).
|
|
468
|
+
function resolveSingleSessionMeta(id, args, { verb = "resume" } = {}) {
|
|
469
|
+
if (!id) throw new Error(`apx session ${verb}: missing <session-id>`);
|
|
470
|
+
const engineFlag = args.flags.engine;
|
|
471
|
+
let hits;
|
|
472
|
+
if (engineFlag && engineFlag !== true) {
|
|
473
|
+
const hit = findSessionInEngine(String(engineFlag), id);
|
|
474
|
+
hits = hit ? [hit] : [];
|
|
475
|
+
} else {
|
|
476
|
+
hits = findSessionAcrossEngines(id);
|
|
477
|
+
}
|
|
478
|
+
if (hits.length === 0) {
|
|
479
|
+
throw new Error(
|
|
480
|
+
`session "${id}" not found in any detected engine` +
|
|
481
|
+
(engineFlag ? ` (engine="${engineFlag}")` : "")
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
if (hits.length > 1) {
|
|
485
|
+
console.error(`⚠️ session id "${id}" exists in multiple engines:`);
|
|
486
|
+
for (const h of hits) {
|
|
487
|
+
console.error(` - ${h.engine.padEnd(7)} ${h.path}${h.cwd ? ` (cwd: ${h.cwd})` : ""}`);
|
|
488
|
+
}
|
|
489
|
+
console.error(`→ re-run with --engine <id> to pick one (apx | claude | codex)`);
|
|
490
|
+
process.exit(2);
|
|
491
|
+
}
|
|
492
|
+
return hits[0];
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
export async function cmdSessionResume(args) {
|
|
496
|
+
const id = args._[0];
|
|
497
|
+
|
|
498
|
+
// ── 1. Resolve which engine owns this id ─────────────────────────────────
|
|
499
|
+
const meta = resolveSingleSessionMeta(id, args, { verb: "resume" });
|
|
500
|
+
|
|
501
|
+
// ── 2. Print metadata + optional transcript dump ─────────────────────────
|
|
502
|
+
printEngineSession(meta, args);
|
|
503
|
+
|
|
504
|
+
// ── 3. Optional super-agent summary ──────────────────────────────────────
|
|
505
|
+
let summaryText = null;
|
|
506
|
+
if (args.flags.summary || args.flags.summarize) {
|
|
507
|
+
try {
|
|
508
|
+
summaryText = await summarizeSession(meta, args);
|
|
509
|
+
if (summaryText) {
|
|
510
|
+
console.log("");
|
|
511
|
+
console.log("## summary (super-agent)");
|
|
512
|
+
console.log(summaryText);
|
|
513
|
+
}
|
|
514
|
+
} catch (e) {
|
|
515
|
+
console.log("");
|
|
516
|
+
console.log(`## summary: (failed — ${e.message})`);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// ── 4. Optional spawn of native CLI to continue ──────────────────────────
|
|
521
|
+
if (args.flags.continue) {
|
|
522
|
+
const spec = spawnContinueSpec(meta);
|
|
523
|
+
if (!spec) {
|
|
524
|
+
console.log("");
|
|
525
|
+
console.log(`(--continue not supported for engine "${meta.engine}")`);
|
|
526
|
+
} else {
|
|
527
|
+
console.log("");
|
|
528
|
+
console.log(`→ launching: ${spec.bin} ${spec.args.join(" ")}`);
|
|
529
|
+
if (spec.cwd) console.log(` cwd: ${spec.cwd}`);
|
|
530
|
+
const child = spawn(spec.bin, spec.args, {
|
|
531
|
+
cwd: spec.cwd || process.cwd(),
|
|
532
|
+
stdio: "inherit",
|
|
533
|
+
});
|
|
534
|
+
await new Promise((resolve) => {
|
|
535
|
+
child.on("exit", (code) => {
|
|
536
|
+
if (code !== 0) console.log(`(native CLI exited with code ${code})`);
|
|
537
|
+
resolve();
|
|
538
|
+
});
|
|
539
|
+
child.on("error", (e) => {
|
|
540
|
+
console.log(`(failed to launch ${spec.bin}: ${e.message})`);
|
|
541
|
+
resolve();
|
|
542
|
+
});
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// ── 5. Optional --into apx[:slug] : seed a new APX session with the summary ─
|
|
548
|
+
if (args.flags.into) {
|
|
549
|
+
const intoSpec = String(args.flags.into);
|
|
550
|
+
if (!intoSpec.startsWith("apx")) {
|
|
551
|
+
console.log("");
|
|
552
|
+
console.log(`(--into "${intoSpec}" not supported — only "apx" or "apx:<slug>")`);
|
|
553
|
+
} else {
|
|
554
|
+
const slug = intoSpec.includes(":") ? intoSpec.split(":")[1] : null;
|
|
555
|
+
try {
|
|
556
|
+
const summary = summaryText || (await summarizeSession(meta, args).catch(() => null));
|
|
557
|
+
const created = createApxFollowupSession(meta, slug, summary, args);
|
|
558
|
+
console.log("");
|
|
559
|
+
console.log(`✅ new APX session: ${created.id}`);
|
|
560
|
+
console.log(` agent: ${created.agent}`);
|
|
561
|
+
console.log(` file: ${path.relative(process.cwd(), created.path)}`);
|
|
562
|
+
console.log(` parent: ${meta.engine}:${meta.id}`);
|
|
563
|
+
} catch (e) {
|
|
564
|
+
console.log("");
|
|
565
|
+
console.log(`(--into failed: ${e.message})`);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// Ask the super-agent on the daemon to summarize a session. The daemon already
|
|
572
|
+
// exposes /projects/:pid/sessions/:id/resume?summarize=true for native APX
|
|
573
|
+
// sessions; we re-use that path when possible, and fall back to the project-
|
|
574
|
+
// agnostic summarizer for claude/codex.
|
|
575
|
+
async function summarizeSession(meta, args) {
|
|
576
|
+
if (meta.engine === "apx") {
|
|
577
|
+
const pid = await resolveProjectId(args?.flags?.project);
|
|
578
|
+
const r = await http.get(
|
|
579
|
+
`/projects/${pid}/sessions/${meta.id}/resume?summarize=true`
|
|
580
|
+
);
|
|
581
|
+
return r.summary || null;
|
|
582
|
+
}
|
|
583
|
+
// Non-apx: map-reduce the whole (binary-stripped) transcript. A byte-tail is
|
|
584
|
+
// unreliable here — the end of these JSONL transcripts is token-count
|
|
585
|
+
// bookkeeping, not conversation, so it has nothing to summarize.
|
|
586
|
+
const label = `${meta.engine} session "${meta.title || "(untitled)"}"`;
|
|
587
|
+
const head =
|
|
588
|
+
`Title: ${meta.title || "(none)"}\nCwd: ${meta.cwd || "(unknown)"}\n`;
|
|
589
|
+
const { text } = await mapReduceSession(meta, {
|
|
590
|
+
note: "summary",
|
|
591
|
+
args,
|
|
592
|
+
oneShot: (t) =>
|
|
593
|
+
`Summarize what happened in this ${label} in 4 concrete bullets, then list ` +
|
|
594
|
+
`the next 1-2 obvious next steps. Reply in the user's language.\n\n${head}\n` +
|
|
595
|
+
`--- transcript ---\n${t}`,
|
|
596
|
+
mapInstruction: (chunk, i, n) =>
|
|
597
|
+
`Extract the key actions, decisions, file changes, and outcomes from part ` +
|
|
598
|
+
`${i}/${n} of a ${label} transcript. If this part is only bookkeeping/noise, ` +
|
|
599
|
+
`reply exactly "(nada relevante)". Be terse.\n\n--- part ${i}/${n} ---\n${chunk}`,
|
|
600
|
+
reduceInstruction: (notes) =>
|
|
601
|
+
`From these notes extracted across a ${label}, write 4 concrete bullets of what ` +
|
|
602
|
+
`happened, then 1-2 obvious next steps. Reply in the user's language.\n\n${head}\n` +
|
|
603
|
+
`Notes:\n\n${notes.join("\n\n")}`,
|
|
604
|
+
});
|
|
605
|
+
return text || null;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// `apx session summary <id>` — discoverable alias for `resume <id> --summary`.
|
|
609
|
+
// Resolves the engine, then prints just the LLM summary (no metadata noise).
|
|
610
|
+
export async function cmdSessionSummary(args) {
|
|
611
|
+
const id = args._[0];
|
|
612
|
+
const meta = resolveSingleSessionMeta(id, args, { verb: "summary" });
|
|
613
|
+
const summary = await summarizeSession(meta, args);
|
|
614
|
+
if (!summary) {
|
|
615
|
+
throw new Error(
|
|
616
|
+
"no summary produced — is the daemon up with super_agent.enabled in ~/.apx/config.json?"
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
console.log(`# summary — ${meta.engine}:${meta.id}`);
|
|
620
|
+
if (meta.title) console.log(`> ${meta.title}`);
|
|
621
|
+
console.log("");
|
|
622
|
+
console.log(summary);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// Pick the richest transcript text available for a session: prefer an attached
|
|
626
|
+
// external JSONL (apx sessions that wrap another engine) over the .md/raw body.
|
|
627
|
+
function sessionFullText(meta) {
|
|
628
|
+
const engine = ENGINES[meta.engine];
|
|
629
|
+
const reading = engine.readSession(meta, { tailBytes: 1 << 30 });
|
|
630
|
+
if (!reading.found) return null;
|
|
631
|
+
return reading.external?.raw || reading.raw || null;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// Transcripts (especially Codex/Claude JSONL) embed base64 image payloads and
|
|
635
|
+
// other binary blobs that are pure noise for an LLM and waste chunk budget.
|
|
636
|
+
// Drop data: URIs and any long unbroken base64-ish run, leaving a "[binary
|
|
637
|
+
// omitted]" marker so the surrounding JSON structure stays readable.
|
|
638
|
+
function stripBinaryNoise(text) {
|
|
639
|
+
if (!text) return text;
|
|
640
|
+
return text
|
|
641
|
+
.replace(/data:[\w.+-]+\/[\w.+-]+;base64,[A-Za-z0-9+/=]+/g, "[binary omitted]")
|
|
642
|
+
.replace(/[A-Za-z0-9+/]{200,}={0,2}/g, "[binary omitted]");
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// Split a long string into byte-bounded chunks for the map step.
|
|
646
|
+
function chunkText(text, chunkBytes) {
|
|
647
|
+
const chunks = [];
|
|
648
|
+
for (let i = 0; i < text.length; i += chunkBytes) {
|
|
649
|
+
chunks.push(text.slice(i, i + chunkBytes));
|
|
650
|
+
}
|
|
651
|
+
return chunks;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// We ask the summarize endpoint for a larger output budget than the
|
|
655
|
+
// super-agent's 512 default: "thinking" models (gemini-2.5-flash) burn output
|
|
656
|
+
// tokens reasoning over dense input and return empty text when the cap is too
|
|
657
|
+
// low. With room to answer, ~48 KB chunks summarize reliably. Most sessions
|
|
658
|
+
// fit in a handful of chunks; huge transcripts are capped by MR_MAX_CHUNKS
|
|
659
|
+
// (raise with --max-chunks).
|
|
660
|
+
const MR_CHUNK_BYTES = 48 * 1024;
|
|
661
|
+
const MR_MAX_CHUNKS = 20;
|
|
662
|
+
const MR_MAX_OUTPUT_TOKENS = 2048;
|
|
663
|
+
|
|
664
|
+
// Generic map-reduce over a session transcript via the project-agnostic
|
|
665
|
+
// /super-agent/summarize endpoint. Small (sanitized) transcripts go in one
|
|
666
|
+
// shot; large ones are split into parts, each mined with `mapInstruction`, and
|
|
667
|
+
// the surviving notes are synthesized with `reduceInstruction`. Both `ask` and
|
|
668
|
+
// the non-apx `summary` path build on this — the byte-tail approach fails on
|
|
669
|
+
// these JSONL transcripts because the tail is just token-count bookkeeping.
|
|
670
|
+
async function mapReduceSession(meta, { mapInstruction, reduceInstruction, oneShot, note, args }) {
|
|
671
|
+
const text = stripBinaryNoise(sessionFullText(meta));
|
|
672
|
+
if (!text) throw new Error(`could not read transcript for ${meta.engine}:${meta.id}`);
|
|
673
|
+
|
|
674
|
+
const maxChunksFlag = args?.flags?.["max-chunks"];
|
|
675
|
+
const maxChunks =
|
|
676
|
+
maxChunksFlag && maxChunksFlag !== true
|
|
677
|
+
? Math.max(1, parseInt(maxChunksFlag, 10))
|
|
678
|
+
: MR_MAX_CHUNKS;
|
|
679
|
+
|
|
680
|
+
if (text.length <= MR_CHUNK_BYTES) {
|
|
681
|
+
const r = await http.post(`/super-agent/summarize`, {
|
|
682
|
+
prompt: `${oneShot(text)}`,
|
|
683
|
+
context_note: `${note} (one-shot) ${meta.engine}:${meta.id}`,
|
|
684
|
+
max_tokens: MR_MAX_OUTPUT_TOKENS,
|
|
685
|
+
});
|
|
686
|
+
return { text: r?.text || null, chunks: 1, truncated: false };
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
const allChunks = chunkText(text, MR_CHUNK_BYTES);
|
|
690
|
+
const truncated = allChunks.length > maxChunks;
|
|
691
|
+
const chunks = allChunks.slice(0, maxChunks);
|
|
692
|
+
|
|
693
|
+
const notes = [];
|
|
694
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
695
|
+
const r = await http.post(`/super-agent/summarize`, {
|
|
696
|
+
prompt: mapInstruction(chunks[i], i + 1, chunks.length),
|
|
697
|
+
context_note: `${note} map ${i + 1}/${chunks.length} ${meta.engine}:${meta.id}`,
|
|
698
|
+
max_tokens: MR_MAX_OUTPUT_TOKENS,
|
|
699
|
+
});
|
|
700
|
+
const n = (r?.text || "").trim();
|
|
701
|
+
if (n && !/^\(nada relevante\)\.?$/i.test(n)) notes.push(`[part ${i + 1}] ${n}`);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
if (notes.length === 0) {
|
|
705
|
+
return { text: "(no relevant content found in the transcript)", chunks: chunks.length, truncated };
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
const r = await http.post(`/super-agent/summarize`, {
|
|
709
|
+
prompt: reduceInstruction(notes),
|
|
710
|
+
context_note: `${note} reduce ${meta.engine}:${meta.id}`,
|
|
711
|
+
max_tokens: MR_MAX_OUTPUT_TOKENS,
|
|
712
|
+
});
|
|
713
|
+
return { text: r?.text || null, chunks: chunks.length, truncated };
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// `apx session ask <id> "<question>"` — RAG-lite Q&A over a session transcript.
|
|
717
|
+
export async function cmdSessionAsk(args) {
|
|
718
|
+
const id = args._[0];
|
|
719
|
+
const question = (args._.slice(1) || []).join(" ").trim();
|
|
720
|
+
if (!question) {
|
|
721
|
+
throw new Error(
|
|
722
|
+
'apx session ask: missing question — e.g. apx session ask <id> "¿qué decidimos sobre el sidebar?"'
|
|
723
|
+
);
|
|
724
|
+
}
|
|
725
|
+
const meta = resolveSingleSessionMeta(id, args, { verb: "ask" });
|
|
726
|
+
const label = `${meta.engine} session "${meta.title || "(untitled)"}"`;
|
|
727
|
+
const { text, chunks, truncated } = await mapReduceSession(meta, {
|
|
728
|
+
note: "ask",
|
|
729
|
+
args,
|
|
730
|
+
oneShot: (t) =>
|
|
731
|
+
`Answer the question about this ${label}.\nQuestion: ${question}\n\n` +
|
|
732
|
+
`If the transcript doesn't contain the answer, say so plainly. ` +
|
|
733
|
+
`Reply concisely in the user's language.\n\n--- transcript ---\n${t}`,
|
|
734
|
+
mapInstruction: (chunk, i, n) =>
|
|
735
|
+
`You are mining part ${i}/${n} of a ${label} transcript to help answer a question.\n` +
|
|
736
|
+
`Question: ${question}\n\n` +
|
|
737
|
+
`Extract ONLY facts, decisions, code changes, file paths, or context from THIS part ` +
|
|
738
|
+
`that help answer it. If nothing here is relevant, reply exactly "(nada relevante)". ` +
|
|
739
|
+
`Be terse.\n\n--- part ${i}/${n} ---\n${chunk}`,
|
|
740
|
+
reduceInstruction: (notes) =>
|
|
741
|
+
`Answer the user's question using notes extracted from a ${label}.\n` +
|
|
742
|
+
`Question: ${question}\n\nNotes from ${notes.length} part(s):\n\n${notes.join("\n\n")}\n\n` +
|
|
743
|
+
`Give a direct, concise answer. If the notes don't answer it, say so. Reply in the user's language.`,
|
|
744
|
+
});
|
|
745
|
+
if (!text) {
|
|
746
|
+
throw new Error(
|
|
747
|
+
"no answer produced — is the daemon up with super_agent.enabled in ~/.apx/config.json?"
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
console.log(`# ${meta.engine}:${meta.id} — ${meta.title || "(untitled)"}`);
|
|
751
|
+
console.log(`> Q: ${question}`);
|
|
752
|
+
console.log("");
|
|
753
|
+
console.log(text);
|
|
754
|
+
if (truncated) {
|
|
755
|
+
console.log("");
|
|
756
|
+
console.log(
|
|
757
|
+
`⚠️ transcript exceeded ${chunks} chunks — answered over the first ` +
|
|
758
|
+
`${chunks} part(s). Raise with --max-chunks N for fuller coverage.`
|
|
759
|
+
);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// Map (engine, id, cwd) → how to spawn the engine's native CLI in resume mode.
|
|
764
|
+
function spawnContinueSpec(meta) {
|
|
765
|
+
if (meta.engine === "claude") {
|
|
766
|
+
return {
|
|
767
|
+
bin: "claude",
|
|
768
|
+
args: ["--resume", meta.id],
|
|
769
|
+
cwd: meta.cwd && fs.existsSync(meta.cwd) ? meta.cwd : null,
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
if (meta.engine === "codex") {
|
|
773
|
+
return {
|
|
774
|
+
bin: "codex",
|
|
775
|
+
args: ["resume", meta.id],
|
|
776
|
+
cwd: meta.cwd && fs.existsSync(meta.cwd) ? meta.cwd : null,
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
// For apx-native sessions there's no "native CLI" to resume — use --into.
|
|
780
|
+
return null;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// Create a new APX session whose body is the summary of an existing session.
|
|
784
|
+
// Used by `apx session resume <id> --into apx[:slug]`. Picks a sensible
|
|
785
|
+
// default agent slug when none is given.
|
|
786
|
+
function createApxFollowupSession(meta, slugArg, summary, args) {
|
|
787
|
+
const root = requireRoot();
|
|
788
|
+
const agents = readAgents(root);
|
|
789
|
+
if (agents.length === 0) {
|
|
790
|
+
throw new Error("no agents in AGENTS.md — `apx agent add <slug>` first");
|
|
791
|
+
}
|
|
792
|
+
let slug = slugArg || meta.agentSlug || agents[0].slug;
|
|
793
|
+
if (!agents.find((a) => a.slug === slug)) {
|
|
794
|
+
throw new Error(
|
|
795
|
+
`agent "${slug}" not in AGENTS.md (known: ${agents.map((a) => a.slug).join(", ")})`
|
|
796
|
+
);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
const storageRoot = requireStorageRoot(root);
|
|
800
|
+
const id = generateSessionId(storageRoot, slug);
|
|
801
|
+
const filename = `${id}.md`;
|
|
802
|
+
const filepath = path.join(storageRoot, "agents", slug, "sessions", filename);
|
|
803
|
+
fs.mkdirSync(path.dirname(filepath), { recursive: true });
|
|
804
|
+
|
|
805
|
+
const title = `Continued from ${meta.engine}:${meta.id}`;
|
|
806
|
+
const started = nowIso();
|
|
807
|
+
const body =
|
|
808
|
+
`> Spawned from \`${meta.engine}\` session \`${meta.id}\`\n` +
|
|
809
|
+
`> Original cwd: ${meta.cwd || "(unknown)"}\n` +
|
|
810
|
+
`> Original path: ${meta.path}\n\n` +
|
|
811
|
+
(summary
|
|
812
|
+
? `## Summary of prior session\n\n${summary}\n`
|
|
813
|
+
: `(no summary available — re-run with the daemon up and \`super_agent.enabled = true\` to get one)\n`);
|
|
814
|
+
|
|
815
|
+
const content =
|
|
816
|
+
`---\n` +
|
|
817
|
+
`id: ${id}\n` +
|
|
818
|
+
`agent: ${slug}\n` +
|
|
819
|
+
`title: ${title}\n` +
|
|
820
|
+
`description: \n` +
|
|
821
|
+
`task_ref: \n` +
|
|
822
|
+
`status: open\n` +
|
|
823
|
+
`date: ${started.slice(0, 10)}\n` +
|
|
824
|
+
`started: ${started}\n` +
|
|
825
|
+
`completed: \n` +
|
|
826
|
+
`parent_session: ${meta.engine}:${meta.id}\n` +
|
|
827
|
+
`parent_session_path: ${meta.path}\n` +
|
|
828
|
+
`---\n\n` +
|
|
829
|
+
`# ${title}\n\n${body}\n`;
|
|
830
|
+
|
|
831
|
+
fs.writeFileSync(filepath, content);
|
|
832
|
+
return { id, agent: slug, path: filepath };
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
export function cmdSessionCloseStale() {
|
|
836
|
+
const root = requireRoot();
|
|
837
|
+
const sessions = listAllSessions(root).filter((s) =>
|
|
838
|
+
/in.progress/i.test(s.status)
|
|
839
|
+
);
|
|
840
|
+
let closed = 0;
|
|
841
|
+
for (const s of sessions) {
|
|
842
|
+
const h = hoursSince(s.started);
|
|
843
|
+
if (h < STALE_HOURS) continue;
|
|
844
|
+
let text = fs.readFileSync(s.path, "utf8");
|
|
845
|
+
text = setFrontmatterField(
|
|
846
|
+
text,
|
|
847
|
+
"status",
|
|
848
|
+
`⚠️ Automatically closed (stale >${STALE_HOURS}h)`
|
|
849
|
+
);
|
|
850
|
+
text = setFrontmatterField(text, "completed", nowIso());
|
|
851
|
+
text = setFrontmatterField(
|
|
852
|
+
text,
|
|
853
|
+
"result",
|
|
854
|
+
`Auto-closed by apx (stale >${h.toFixed(1)}h without completion)`
|
|
855
|
+
);
|
|
856
|
+
fs.writeFileSync(s.path, text);
|
|
857
|
+
console.log(`⚠️ Closed stale: ${s.id} (${h.toFixed(1)}h old)`);
|
|
858
|
+
closed++;
|
|
859
|
+
}
|
|
860
|
+
if (closed === 0) console.log("No stale sessions found.");
|
|
861
|
+
else console.log(`Closed ${closed} stale session(s).`);
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
export async function cmdSessionCompact(args) {
|
|
865
|
+
const slug = args._[0];
|
|
866
|
+
if (!slug) throw new Error("apx session compact: missing <agent-slug>");
|
|
867
|
+
const convId = args.flags.conversation === true ? null : (args.flags.conversation || null);
|
|
868
|
+
const model = args.flags.model === true ? null : (args.flags.model || null);
|
|
869
|
+
|
|
870
|
+
const pid = await resolveProjectId(args?.flags?.project);
|
|
871
|
+
|
|
872
|
+
const url = convId
|
|
873
|
+
? `/projects/${pid}/agents/${slug}/conversations/${convId}/compact`
|
|
874
|
+
: `/projects/${pid}/agents/${slug}/compact`;
|
|
875
|
+
|
|
876
|
+
const body = model ? { model } : {};
|
|
877
|
+
|
|
878
|
+
console.log(`Compacting conversation for ${slug}${convId ? ` (${convId})` : " (latest)"}...`);
|
|
879
|
+
const result = await http.post(url, body);
|
|
880
|
+
|
|
881
|
+
console.log(`✅ Compacted ${result.compacted_turns} turns → ${result.filename}`);
|
|
882
|
+
console.log(` Kept last ${result.kept_turns} turns verbatim`);
|
|
883
|
+
console.log(` Model: ${result.model}`);
|
|
884
|
+
if (result.usage) {
|
|
885
|
+
const u = result.usage;
|
|
886
|
+
console.log(` Tokens: ${u.input_tokens ?? u.prompt_tokens ?? "?"} in / ${u.output_tokens ?? u.completion_tokens ?? "?"} out`);
|
|
887
|
+
}
|
|
888
|
+
console.log("");
|
|
889
|
+
console.log("Summary:");
|
|
890
|
+
console.log("─".repeat(60));
|
|
891
|
+
console.log(result.summary);
|
|
892
|
+
}
|