@agentprojectcontext/apx 1.77.3 → 1.79.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -9
- package/package.json +12 -12
- package/src/core/agent/build-agent-system.js +3 -2
- package/src/core/agent/constants.js +3 -2
- package/src/core/agent/loop/greeting-guard.js +55 -0
- package/src/core/agent/loop/side-effects.js +52 -0
- package/src/core/agent/prompt-builder.js +49 -8
- package/src/core/agent/run-agent.js +43 -53
- package/src/core/agent/security.js +1 -1
- package/src/core/agent/self-memory.js +4 -2
- package/src/core/agent/skills/index-store.js +2 -2
- package/src/core/agent/skills/loader.js +3 -22
- package/src/core/agent/super-agent.js +0 -2
- package/src/core/agent/tool-summary.js +65 -0
- package/src/core/agent/tools/handlers/call-runtime.js +4 -4
- package/src/core/agent/tools/handlers/list-commitments.js +80 -0
- package/src/core/agent/tools/handlers/list-tasks.js +66 -27
- package/src/core/agent/tools/handlers/record-commitment.js +68 -0
- package/src/core/agent/tools/handlers/search-sessions.js +1 -1
- package/src/core/agent/tools/handlers/send-telegram.js +68 -2
- package/src/core/agent/tools/handlers/set-permission-mode.js +11 -4
- package/src/core/agent/tools/names.js +64 -0
- package/src/core/agent/tools/registry.js +9 -0
- package/src/core/agent/tools/tool-call-parser.js +70 -1
- package/src/core/apc/context-copy.js +1 -1
- package/src/core/apc/frontmatter.js +85 -0
- package/src/core/apc/parser.js +9 -21
- package/src/core/apc/paths.js +8 -8
- package/src/core/apc/scaffold.js +5 -4
- package/src/core/channels/telegram/ask-callbacks.js +35 -0
- package/src/core/channels/telegram/config.js +201 -0
- package/src/core/channels/telegram/dispatch.js +3 -0
- package/src/core/channels/telegram/reply.js +30 -5
- package/src/core/config/index.js +25 -183
- package/src/core/config/paths.js +57 -1
- package/src/core/config/redact.js +22 -0
- package/src/core/confirmation/adapters/web.js +1 -1
- package/src/core/daemon/service.js +238 -0
- package/src/core/deck/manifest.js +12 -12
- package/src/core/desktop/autostart.js +3 -2
- package/src/core/desktop/process.js +4 -4
- package/src/core/engines/gemini.js +322 -60
- package/src/core/engines/openai-compatible.js +21 -2
- package/src/core/engines/presets.js +2 -2
- package/src/core/http-tools/browser.js +1 -1
- package/src/core/http-tools/catalog.js +551 -0
- package/src/core/http-tools/fetch.js +1 -1
- package/src/core/http-tools/glob.js +3 -3
- package/src/core/http-tools/grep.js +2 -9
- package/src/core/http-tools/inline-handlers.js +59 -0
- package/src/core/http-tools/registry.js +31 -615
- package/src/core/http-tools/search.js +2 -2
- package/src/core/identity/self.js +6 -7
- package/src/core/identity/telegram.js +3 -3
- package/src/core/logging.js +6 -5
- package/src/core/mcp/sources.js +12 -16
- package/src/core/memory/consolidate.js +225 -0
- package/src/core/memory/indexer.js +2 -5
- package/src/core/nudge/index.js +192 -0
- package/src/core/nudge/policy.js +143 -0
- package/src/core/nudge/store.js +141 -0
- package/src/core/profiles/bundled/secretary/PROFILE.md +8 -9
- package/src/core/profiles/bundled/secretary/config.schema.json +33 -3
- package/src/core/profiles/bundled/secretary/routines/day-close.json +7 -3
- package/src/core/profiles/bundled/secretary/routines/day-open.json +7 -3
- package/src/core/profiles/bundled/secretary/routines/watch.json +13 -0
- package/src/core/profiles/lifecycle.js +0 -2
- package/src/core/profiles/store.js +2 -7
- package/src/core/routines/runner.js +103 -4
- package/src/core/routines/signals.js +270 -0
- package/src/core/runtime-skills/apx-agency-agents/SKILL.md +2 -2
- package/src/core/runtime-skills/apx-profile/SKILL.md +3 -3
- package/src/core/runtime-skills/apx-project/SKILL.md +1 -1
- package/src/core/runtime-skills/apx-task/SKILL.md +8 -8
- package/src/core/runtime-skills/apx-telegram/SKILL.md +4 -4
- package/src/core/runtime-skills/apx-voice/SKILL.md +4 -4
- package/src/core/runtimes/detect.js +2 -2
- package/src/core/sessions/index.js +800 -0
- package/src/core/stores/code-sessions.js +3 -14
- package/src/core/stores/commitments.js +331 -0
- package/src/core/stores/engine-sessions.js +0 -4
- package/src/core/stores/messages.js +4 -5
- package/src/core/stores/organization.js +9 -11
- package/src/core/stores/routines.js +23 -14
- package/src/core/stores/runtime-callbacks.js +2 -1
- package/src/core/util/json-file.js +128 -0
- package/src/core/util/thinking.js +51 -0
- package/src/core/vars/sources.js +14 -21
- package/src/core/voice/stt-models.js +1 -1
- package/src/core/voice/tts.js +5 -4
- package/src/host/daemon/api/admin-config.js +5 -5
- package/src/host/daemon/api/admin.js +8 -7
- package/src/host/daemon/api/agents.js +16 -16
- package/src/host/daemon/api/artifact-preview.js +8 -8
- package/src/host/daemon/api/artifacts.js +7 -7
- package/src/host/daemon/api/code.js +8 -8
- package/src/host/daemon/api/commitments.js +135 -0
- package/src/host/daemon/api/config.js +6 -6
- package/src/host/daemon/api/confirm.js +2 -2
- package/src/host/daemon/api/connections.js +2 -2
- package/src/host/daemon/api/conversations.js +12 -12
- package/src/host/daemon/api/deck.js +6 -6
- package/src/host/daemon/api/desktop.js +8 -8
- package/src/host/daemon/api/embeddings.js +4 -4
- package/src/host/daemon/api/engines.js +8 -7
- package/src/host/daemon/api/exec.js +5 -4
- package/src/host/daemon/api/files-project.js +6 -6
- package/src/host/daemon/api/health.js +2 -2
- package/src/host/daemon/api/identity.js +3 -3
- package/src/host/daemon/api/inbox.js +2 -2
- package/src/host/daemon/api/integrations.js +23 -19
- package/src/host/daemon/api/mcps.js +16 -12
- package/src/host/daemon/api/messages.js +5 -5
- package/src/host/daemon/api/nudges.js +112 -0
- package/src/host/daemon/api/organization.js +8 -8
- package/src/host/daemon/api/pairing.js +6 -6
- package/src/host/daemon/api/plugins.js +3 -3
- package/src/host/daemon/api/prefix.js +20 -0
- package/src/host/daemon/api/profiles.js +9 -9
- package/src/host/daemon/api/projects.js +5 -5
- package/src/host/daemon/api/routines.js +32 -8
- package/src/host/daemon/api/run.js +2 -2
- package/src/host/daemon/api/runtimes.js +6 -6
- package/src/host/daemon/api/self-memory.js +50 -0
- package/src/host/daemon/api/sessions-search.js +18 -11
- package/src/host/daemon/api/sessions.js +6 -6
- package/src/host/daemon/api/shared.js +59 -13
- package/src/host/daemon/api/skills.js +12 -12
- package/src/host/daemon/api/super-agent.js +4 -4
- package/src/host/daemon/api/tasks.js +11 -11
- package/src/host/daemon/api/telegram.js +61 -24
- package/src/host/daemon/api/tools.js +7 -7
- package/src/host/daemon/api/top-level.js +7 -7
- package/src/host/daemon/api/transcribe.js +6 -6
- package/src/host/daemon/api/tts.js +3 -3
- package/src/host/daemon/api/vars.js +11 -8
- package/src/host/daemon/api/voice.js +9 -7
- package/src/host/daemon/api/web.js +28 -32
- package/src/host/daemon/api.js +83 -48
- package/src/host/daemon/callback-reconciler.js +16 -0
- package/src/host/daemon/db.js +1 -1
- package/src/host/daemon/desktop-ws.js +7 -3
- package/src/host/daemon/index.js +11 -5
- package/src/host/daemon/plugins/desktop/index.js +8 -2
- package/src/host/daemon/plugins/telegram/index.js +7 -2
- package/src/host/daemon/stt-venv.js +20 -81
- package/src/host/daemon/wakeup.js +18 -4
- package/src/interfaces/acp/index.js +3 -3
- package/src/interfaces/acp/session.js +2 -2
- package/src/interfaces/cli/commands/a2a.js +2 -2
- package/src/interfaces/cli/commands/agent.js +3 -3
- package/src/interfaces/cli/commands/artifact.js +13 -13
- package/src/interfaces/cli/commands/chat.js +3 -3
- package/src/interfaces/cli/commands/command.js +2 -2
- package/src/interfaces/cli/commands/commitment.js +154 -0
- package/src/interfaces/cli/commands/config.js +4 -4
- package/src/interfaces/cli/commands/daemon.js +74 -18
- package/src/interfaces/cli/commands/desktop.js +7 -14
- package/src/interfaces/cli/commands/exec.js +2 -2
- package/src/interfaces/cli/commands/log.js +3 -4
- package/src/interfaces/cli/commands/mcp.js +9 -9
- package/src/interfaces/cli/commands/memory.js +75 -2
- package/src/interfaces/cli/commands/messages.js +5 -5
- package/src/interfaces/cli/commands/model.js +0 -18
- package/src/interfaces/cli/commands/nudge.js +130 -0
- package/src/interfaces/cli/commands/obsidian.js +5 -5
- package/src/interfaces/cli/commands/org.js +5 -5
- package/src/interfaces/cli/commands/pair.js +6 -6
- package/src/interfaces/cli/commands/plugins.js +2 -2
- package/src/interfaces/cli/commands/profile.js +10 -10
- package/src/interfaces/cli/commands/project-config.js +6 -6
- package/src/interfaces/cli/commands/project.js +10 -10
- package/src/interfaces/cli/commands/routine.js +8 -9
- package/src/interfaces/cli/commands/runtime.js +2 -2
- package/src/interfaces/cli/commands/search.js +0 -1
- package/src/interfaces/cli/commands/session.js +12 -40
- package/src/interfaces/cli/commands/sessions.js +21 -798
- package/src/interfaces/cli/commands/setup.js +16 -6
- package/src/interfaces/cli/commands/skills.js +1 -2
- package/src/interfaces/cli/commands/status.js +3 -3
- package/src/interfaces/cli/commands/task.js +8 -8
- package/src/interfaces/cli/commands/telegram.js +21 -21
- package/src/interfaces/cli/commands/voice.js +6 -6
- package/src/interfaces/cli/help/index.js +2245 -0
- package/src/interfaces/cli/http.js +9 -4
- package/src/interfaces/cli/index.js +14 -2857
- package/src/interfaces/cli/routes/acp.js +13 -0
- package/src/interfaces/cli/routes/agent.js +27 -0
- package/src/interfaces/cli/routes/artifact.js +28 -0
- package/src/interfaces/cli/routes/chat.js +11 -0
- package/src/interfaces/cli/routes/code.js +11 -0
- package/src/interfaces/cli/routes/command.js +21 -0
- package/src/interfaces/cli/routes/commitment.js +19 -0
- package/src/interfaces/cli/routes/config.js +16 -0
- package/src/interfaces/cli/routes/connections.js +11 -0
- package/src/interfaces/cli/routes/conversations.js +21 -0
- package/src/interfaces/cli/routes/daemon.js +25 -0
- package/src/interfaces/cli/routes/desktop.js +20 -0
- package/src/interfaces/cli/routes/env.js +13 -0
- package/src/interfaces/cli/routes/exec.js +11 -0
- package/src/interfaces/cli/routes/identity.js +11 -0
- package/src/interfaces/cli/routes/index.js +75 -0
- package/src/interfaces/cli/routes/init.js +11 -0
- package/src/interfaces/cli/routes/log.js +20 -0
- package/src/interfaces/cli/routes/mcp.js +22 -0
- package/src/interfaces/cli/routes/memory.js +19 -0
- package/src/interfaces/cli/routes/messages.js +16 -0
- package/src/interfaces/cli/routes/model.js +11 -0
- package/src/interfaces/cli/routes/nudge.js +17 -0
- package/src/interfaces/cli/routes/obsidian.js +17 -0
- package/src/interfaces/cli/routes/org.js +34 -0
- package/src/interfaces/cli/routes/overlay.js +10 -0
- package/src/interfaces/cli/routes/pair.js +17 -0
- package/src/interfaces/cli/routes/panel.js +16 -0
- package/src/interfaces/cli/routes/permission.js +11 -0
- package/src/interfaces/cli/routes/plugins.js +21 -0
- package/src/interfaces/cli/routes/profile.js +27 -0
- package/src/interfaces/cli/routes/project.js +41 -0
- package/src/interfaces/cli/routes/restart.js +15 -0
- package/src/interfaces/cli/routes/routine.js +28 -0
- package/src/interfaces/cli/routes/run.js +11 -0
- package/src/interfaces/cli/routes/search.js +11 -0
- package/src/interfaces/cli/routes/send.js +11 -0
- package/src/interfaces/cli/routes/session.js +26 -0
- package/src/interfaces/cli/routes/sessions.js +15 -0
- package/src/interfaces/cli/routes/setup.js +18 -0
- package/src/interfaces/cli/routes/skills.js +20 -0
- package/src/interfaces/cli/routes/status.js +12 -0
- package/src/interfaces/cli/routes/task.js +26 -0
- package/src/interfaces/cli/routes/telegram.js +39 -0
- package/src/interfaces/cli/routes/update.js +24 -0
- package/src/interfaces/cli/routes/voice.js +17 -0
- package/src/interfaces/desktop/main.js +6 -7
- package/src/interfaces/desktop/renderer.js +0 -5
- package/src/interfaces/mcp-server/index.js +15 -14
- package/src/interfaces/tui/_shims/globals.d.ts +8 -0
- package/src/interfaces/tui/tsconfig.json +4 -1
- package/src/interfaces/web/README.md +6 -6
- package/src/interfaces/web/dist/assets/index-CvEoGtTf.js +849 -0
- package/src/interfaces/web/dist/assets/index-CvEoGtTf.js.map +1 -0
- package/src/interfaces/web/dist/assets/index-DzBBXFaO.css +1 -0
- package/src/interfaces/web/dist/index.html +2 -2
- package/src/interfaces/web/package-lock.json +11 -10
- package/src/interfaces/web/src/components/AddProjectDialog.tsx +1 -1
- package/src/interfaces/web/src/components/Section.tsx +18 -3
- package/src/interfaces/web/src/components/agents/AgentFormFields.tsx +1 -1
- package/src/interfaces/web/src/components/chat/ChatList.tsx +2 -2
- package/src/interfaces/web/src/components/chat/MessageBubble.tsx +13 -0
- package/src/interfaces/web/src/components/chat/SkillPicker.tsx +1 -1
- package/src/interfaces/web/src/components/code/CodeFileTree.tsx +1 -1
- package/src/interfaces/web/src/components/code/CodeTerminal.tsx +1 -1
- package/src/interfaces/web/src/components/cron/CronPicker.tsx +196 -0
- package/src/interfaces/web/src/components/desktop/DesktopStatusCard.tsx +1 -1
- package/src/interfaces/web/src/components/files/FileBrowser.tsx +2 -2
- package/src/interfaces/web/src/components/inbox/InboxList.tsx +145 -0
- package/src/interfaces/web/src/components/memory/MemoryBrowser.tsx +36 -6
- package/src/interfaces/web/src/components/routines/ExecutionsList.tsx +1 -1
- package/src/interfaces/web/src/components/routines/RoutineDetail.tsx +16 -4
- package/src/interfaces/web/src/components/routines/RoutineEditor.tsx +14 -4
- package/src/interfaces/web/src/components/routines/shared.ts +14 -5
- package/src/interfaces/web/src/components/settings/DesktopSettingsPanel.tsx +1 -1
- package/src/interfaces/web/src/components/settings/MemoryPanel.tsx +1 -1
- package/src/interfaces/web/src/components/settings/NudgePanel.tsx +183 -0
- package/src/interfaces/web/src/components/settings/ProfilePanel.tsx +36 -12
- package/src/interfaces/web/src/components/settings/SkillsInspectorPanel.tsx +1 -1
- package/src/interfaces/web/src/components/settings/SkillsManager.tsx +2 -2
- package/src/interfaces/web/src/components/tasks/TaskDetailPanel.tsx +1 -1
- package/src/interfaces/web/src/components/ui/filter-chips.tsx +47 -0
- package/src/interfaces/web/src/components/ui.tsx +1 -0
- package/src/interfaces/web/src/constants/index.ts +1 -0
- package/src/interfaces/web/src/hooks/useChat.ts +5 -1
- package/src/interfaces/web/src/hooks/useDaemonStatus.ts +1 -1
- package/src/interfaces/web/src/hooks/useDevices.ts +1 -1
- package/src/interfaces/web/src/hooks/useEngines.ts +1 -1
- package/src/interfaces/web/src/hooks/useGlobalConfig.ts +2 -2
- package/src/interfaces/web/src/hooks/useIdentity.ts +1 -1
- package/src/interfaces/web/src/hooks/useInbox.ts +1 -1
- package/src/interfaces/web/src/hooks/useNudges.ts +38 -0
- package/src/interfaces/web/src/hooks/useProfiles.ts +3 -3
- package/src/interfaces/web/src/hooks/useProjects.ts +1 -1
- package/src/interfaces/web/src/hooks/useTelegram.ts +3 -3
- package/src/interfaces/web/src/hooks/useTokenBootstrap.ts +3 -3
- package/src/interfaces/web/src/i18n/en.ts +127 -0
- package/src/interfaces/web/src/i18n/es.ts +127 -0
- package/src/interfaces/web/src/lib/api/admin.ts +11 -11
- package/src/interfaces/web/src/lib/api/agents.ts +14 -14
- package/src/interfaces/web/src/lib/api/artifacts.ts +11 -11
- package/src/interfaces/web/src/lib/api/code.ts +1 -1
- package/src/interfaces/web/src/lib/api/commitments.ts +57 -0
- package/src/interfaces/web/src/lib/api/conversations.ts +8 -8
- package/src/interfaces/web/src/lib/api/deck.ts +3 -3
- package/src/interfaces/web/src/lib/api/desktop.ts +8 -8
- package/src/interfaces/web/src/lib/api/embeddings.ts +3 -3
- package/src/interfaces/web/src/lib/api/engines.ts +3 -3
- package/src/interfaces/web/src/lib/api/filesystem.ts +2 -2
- package/src/interfaces/web/src/lib/api/health.ts +1 -1
- package/src/interfaces/web/src/lib/api/identity.ts +2 -2
- package/src/interfaces/web/src/lib/api/inbox.ts +1 -1
- package/src/interfaces/web/src/lib/api/integrations.ts +8 -8
- package/src/interfaces/web/src/lib/api/mcps.ts +6 -6
- package/src/interfaces/web/src/lib/api/messages.ts +3 -3
- package/src/interfaces/web/src/lib/api/notebook.ts +23 -0
- package/src/interfaces/web/src/lib/api/nudges.ts +53 -0
- package/src/interfaces/web/src/lib/api/organization.ts +7 -7
- package/src/interfaces/web/src/lib/api/profiles.ts +8 -8
- package/src/interfaces/web/src/lib/api/projectFiles.ts +5 -5
- package/src/interfaces/web/src/lib/api/projects.ts +12 -12
- package/src/interfaces/web/src/lib/api/routines.ts +7 -7
- package/src/interfaces/web/src/lib/api/sessions.ts +2 -2
- package/src/interfaces/web/src/lib/api/skills.ts +11 -11
- package/src/interfaces/web/src/lib/api/super_agent.ts +3 -3
- package/src/interfaces/web/src/lib/api/tasks.ts +12 -12
- package/src/interfaces/web/src/lib/api/telegram.ts +14 -14
- package/src/interfaces/web/src/lib/api/tools.ts +1 -1
- package/src/interfaces/web/src/lib/api/vars.ts +4 -4
- package/src/interfaces/web/src/lib/api/voice.ts +6 -6
- package/src/interfaces/web/src/lib/cron.ts +196 -0
- package/src/interfaces/web/src/lib/when.ts +32 -0
- package/src/interfaces/web/src/screens/InboxScreen.tsx +107 -77
- package/src/interfaces/web/src/screens/ProjectScreen.tsx +5 -2
- package/src/interfaces/web/src/screens/SettingsScreen.tsx +17 -3
- package/src/interfaces/web/src/screens/base/AgentDefaultsTab.tsx +1 -1
- package/src/interfaces/web/src/screens/base/CommitmentsTab.tsx +239 -0
- package/src/interfaces/web/src/screens/base/GlobalTasksTab.tsx +103 -20
- package/src/interfaces/web/src/screens/base/LogsTab.tsx +18 -3
- package/src/interfaces/web/src/screens/base/SessionsTab.tsx +1 -1
- package/src/interfaces/web/src/screens/modules/CodeScreen.tsx +1 -1
- package/src/interfaces/web/src/screens/modules/DeckScreen.tsx +1 -1
- package/src/interfaces/web/src/screens/modules/DesktopScreen.tsx +1 -1
- package/src/interfaces/web/src/screens/modules/VoiceScreen.tsx +1 -1
- package/src/interfaces/web/src/screens/project/AgentDetailScreen.tsx +8 -8
- package/src/interfaces/web/src/screens/project/AgentsTab.tsx +2 -2
- package/src/interfaces/web/src/screens/project/ChatTab.tsx +24 -6
- package/src/interfaces/web/src/screens/project/ConfigTab.tsx +1 -1
- package/src/interfaces/web/src/screens/project/McpsTab.tsx +3 -3
- package/src/interfaces/web/src/screens/project/Overview.tsx +6 -6
- package/src/interfaces/web/src/screens/project/RoutinesTab.tsx +15 -13
- package/src/interfaces/web/src/screens/project/StructureTab.tsx +1 -1
- package/src/interfaces/web/src/screens/project/TasksTab.tsx +1 -1
- package/src/interfaces/web/src/screens/project/VarsTab.tsx +1 -1
- package/src/interfaces/web/src/types/daemon.ts +10 -1
- package/src/interfaces/web/vite.config.ts +13 -18
- package/src/interfaces/web/dist/assets/index-BptlbKjU.js +0 -824
- package/src/interfaces/web/dist/assets/index-BptlbKjU.js.map +0 -1
- package/src/interfaces/web/dist/assets/index-D_EJEA1n.css +0 -1
- package/src/skills/apc-context/SKILL.md +0 -159
- /package/src/{host/daemon → core}/runtimes/_spawn.js +0 -0
- /package/src/{host/daemon → core}/runtimes/aider.js +0 -0
- /package/src/{host/daemon → core}/runtimes/antigravity.js +0 -0
- /package/src/{host/daemon → core}/runtimes/claude-code.js +0 -0
- /package/src/{host/daemon → core}/runtimes/codex.js +0 -0
- /package/src/{host/daemon → core}/runtimes/cursor-agent.js +0 -0
- /package/src/{host/daemon → core}/runtimes/gemini-cli.js +0 -0
- /package/src/{host/daemon → core}/runtimes/index.js +0 -0
- /package/src/{host/daemon → core}/runtimes/opencode.js +0 -0
- /package/src/{host/daemon → core}/runtimes/qwen-code.js +0 -0
|
@@ -16,15 +16,16 @@ import {
|
|
|
16
16
|
setEnabled as setRoutineEnabled,
|
|
17
17
|
runRoutineNow,
|
|
18
18
|
} from "#core/routines/index.js";
|
|
19
|
+
import { CHANNELS } from "#core/constants/channels.js";
|
|
19
20
|
|
|
20
|
-
export function register(
|
|
21
|
-
|
|
21
|
+
export function register(api, { projects, registries, plugins, project, config }) {
|
|
22
|
+
api.get("/projects/:pid/routines", (req, res) => {
|
|
22
23
|
const p = project(req, res);
|
|
23
24
|
if (!p) return;
|
|
24
25
|
res.json(listRoutines(p.storagePath));
|
|
25
26
|
});
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
api.get("/projects/:pid/routines/:name", (req, res) => {
|
|
28
29
|
const p = project(req, res);
|
|
29
30
|
if (!p) return;
|
|
30
31
|
const r = getRoutine(p.storagePath, req.params.name);
|
|
@@ -32,41 +33,64 @@ export function register(app, { projects, registries, plugins, project, config }
|
|
|
32
33
|
res.json(r);
|
|
33
34
|
});
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
api.post("/projects/:pid/routines", (req, res) => {
|
|
36
37
|
const p = project(req, res);
|
|
37
38
|
if (!p) return;
|
|
38
39
|
try {
|
|
39
40
|
// Accepts every field including the pipeline extensions
|
|
40
41
|
// (pre_commands, post_commands, skip_prompt_on).
|
|
42
|
+
const existed = !!getRoutine(p.storagePath, (req.body || {}).name);
|
|
41
43
|
const r = upsertRoutine(p.storagePath, req.body || {});
|
|
44
|
+
// Say it happened, where it happened. A routine appearing in a list on a
|
|
45
|
+
// screen nobody has open is not the same as being told one now exists —
|
|
46
|
+
// and "what did that just create?" is the question people actually ask
|
|
47
|
+
// after asking for something to be set up.
|
|
48
|
+
p.logMessage?.({
|
|
49
|
+
channel: CHANNELS.ROUTINE,
|
|
50
|
+
direction: "out",
|
|
51
|
+
type: "system",
|
|
52
|
+
actor_id: "apx:routine",
|
|
53
|
+
author: "apx",
|
|
54
|
+
body: existed
|
|
55
|
+
? `routine ${r.name} updated (${r.kind}, ${r.schedule})`
|
|
56
|
+
: `routine ${r.name} created (${r.kind}, ${r.schedule})`,
|
|
57
|
+
meta: {
|
|
58
|
+
event: existed ? "routine_updated" : "routine_created",
|
|
59
|
+
routine: r.name,
|
|
60
|
+
routine_id: r.id,
|
|
61
|
+
kind: r.kind,
|
|
62
|
+
schedule: r.schedule,
|
|
63
|
+
enabled: r.enabled !== false,
|
|
64
|
+
},
|
|
65
|
+
});
|
|
42
66
|
res.status(201).json(r);
|
|
43
67
|
} catch (e) {
|
|
44
68
|
res.status(400).json({ error: e.message });
|
|
45
69
|
}
|
|
46
70
|
});
|
|
47
71
|
|
|
48
|
-
|
|
72
|
+
api.delete("/projects/:pid/routines/:name", (req, res) => {
|
|
49
73
|
const p = project(req, res);
|
|
50
74
|
if (!p) return;
|
|
51
75
|
const ok = deleteRoutine(p.storagePath, req.params.name);
|
|
52
76
|
res.status(ok ? 204 : 404).end();
|
|
53
77
|
});
|
|
54
78
|
|
|
55
|
-
|
|
79
|
+
api.post("/projects/:pid/routines/:name/enable", (req, res) => {
|
|
56
80
|
const p = project(req, res);
|
|
57
81
|
if (!p) return;
|
|
58
82
|
setRoutineEnabled(p.storagePath, req.params.name, true);
|
|
59
83
|
res.json({ ok: true });
|
|
60
84
|
});
|
|
61
85
|
|
|
62
|
-
|
|
86
|
+
api.post("/projects/:pid/routines/:name/disable", (req, res) => {
|
|
63
87
|
const p = project(req, res);
|
|
64
88
|
if (!p) return;
|
|
65
89
|
setRoutineEnabled(p.storagePath, req.params.name, false);
|
|
66
90
|
res.json({ ok: true });
|
|
67
91
|
});
|
|
68
92
|
|
|
69
|
-
|
|
93
|
+
api.post("/projects/:pid/routines/:name/run", async (req, res) => {
|
|
70
94
|
const p = project(req, res);
|
|
71
95
|
if (!p) return;
|
|
72
96
|
const r = getRoutine(p.storagePath, req.params.name);
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { execFile } from "node:child_process";
|
|
6
6
|
|
|
7
|
-
export function register(
|
|
8
|
-
|
|
7
|
+
export function register(api, { projects }) {
|
|
8
|
+
api.post("/run", (req, res) => {
|
|
9
9
|
const {
|
|
10
10
|
cmd,
|
|
11
11
|
cwd: cwdOverride,
|
|
@@ -12,7 +12,7 @@ import { apcProjectFile, apcAgentsDir } from "#core/apc/paths.js";
|
|
|
12
12
|
import { readSessionFrontmatter } from "#core/stores/sessions.js";
|
|
13
13
|
import { buildAgentSystem } from "#core/agent/build-agent-system.js";
|
|
14
14
|
import { CHANNELS } from "#core/constants/channels.js";
|
|
15
|
-
import { getRuntime, RUNTIME_IDS } from "
|
|
15
|
+
import { getRuntime, RUNTIME_IDS } from "#core/runtimes/index.js";
|
|
16
16
|
import { detectAll } from "#core/runtimes/detect.js";
|
|
17
17
|
import { buildRuntimeBridgeHint as buildApfHint } from "#core/agent/runtime-bridge.js";
|
|
18
18
|
import {
|
|
@@ -22,17 +22,17 @@ import {
|
|
|
22
22
|
} from "#core/stores/runtime-sessions.js";
|
|
23
23
|
import { runSuperAgent, isSuperAgentEnabled } from "#core/agent/super-agent.js";
|
|
24
24
|
|
|
25
|
-
export function register(
|
|
26
|
-
|
|
25
|
+
export function register(api, { projects, registries, plugins, project, config }) {
|
|
26
|
+
api.get("/runtimes", (_req, res) =>
|
|
27
27
|
res.json({ runtimes: RUNTIME_IDS })
|
|
28
28
|
);
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
api.get("/env/detect", async (_req, res) => {
|
|
31
31
|
const detected = await detectAll();
|
|
32
32
|
res.json(detected);
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
api.post("/projects/:pid/agents/:slug/runtime", async (req, res) => {
|
|
36
36
|
const p = project(req, res);
|
|
37
37
|
if (!p) return;
|
|
38
38
|
const { runtime, prompt, timeoutMs } = req.body || {};
|
|
@@ -146,7 +146,7 @@ export function register(app, { projects, registries, plugins, project, config }
|
|
|
146
146
|
});
|
|
147
147
|
|
|
148
148
|
// ---- Session resume — reads APC session file + (optionally) external transcript ----
|
|
149
|
-
|
|
149
|
+
api.get("/projects/:pid/sessions/:id/resume", async (req, res) => {
|
|
150
150
|
const p = project(req, res);
|
|
151
151
|
if (!p) return;
|
|
152
152
|
const { id } = req.params;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// The super-agent's own notebook — ~/.apx/memory.md.
|
|
2
|
+
//
|
|
3
|
+
// GET /notebook → { body, path, size, approx_tokens, entries, consolidated }
|
|
4
|
+
// PUT /notebook { body }
|
|
5
|
+
//
|
|
6
|
+
// WHY THIS EXISTS. This file is the one memory that ships in EVERY prompt on
|
|
7
|
+
// every channel, and until now it was the only one with no screen. The Memories
|
|
8
|
+
// tab listed project memory and each agent's memory; the super-agent's own
|
|
9
|
+
// notebook was reachable from the model (read_self_memory / remember) and from
|
|
10
|
+
// the CLI, and nowhere a person could look. So "where is Roby's memory?" had no
|
|
11
|
+
// answer in the product, which is a fair thing to be confused by.
|
|
12
|
+
//
|
|
13
|
+
// It reports its own size because that size is a tax paid on every turn — see
|
|
14
|
+
// core/memory/consolidate.js.
|
|
15
|
+
import { readSelfMemory, SELF_MEMORY_PATH } from "#core/agent/self-memory.js";
|
|
16
|
+
import { notebookSize } from "#core/memory/consolidate.js";
|
|
17
|
+
import fs from "node:fs";
|
|
18
|
+
import path from "node:path";
|
|
19
|
+
|
|
20
|
+
const MAX_BODY = 256 * 1024; // a notebook past this is a symptom, not a note
|
|
21
|
+
|
|
22
|
+
export function register(api) {
|
|
23
|
+
api.get("/notebook", (_req, res) => {
|
|
24
|
+
try {
|
|
25
|
+
const body = readSelfMemory();
|
|
26
|
+
res.json({ body, path: SELF_MEMORY_PATH, ...notebookSize() });
|
|
27
|
+
} catch (e) {
|
|
28
|
+
res.status(500).json({ error: e.message });
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
api.put("/notebook", (req, res) => {
|
|
33
|
+
const { body } = req.body || {};
|
|
34
|
+
if (typeof body !== "string") {
|
|
35
|
+
return res.status(400).json({ error: "body (string) required" });
|
|
36
|
+
}
|
|
37
|
+
if (body.length > MAX_BODY) {
|
|
38
|
+
return res.status(413).json({
|
|
39
|
+
error: `notebook too large (${body.length} > ${MAX_BODY} bytes) — it ships in every prompt`,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
fs.mkdirSync(path.dirname(SELF_MEMORY_PATH), { recursive: true });
|
|
44
|
+
fs.writeFileSync(SELF_MEMORY_PATH, body);
|
|
45
|
+
res.json({ ok: true, path: SELF_MEMORY_PATH, ...notebookSize() });
|
|
46
|
+
} catch (e) {
|
|
47
|
+
res.status(500).json({ error: e.message });
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
@@ -2,23 +2,30 @@
|
|
|
2
2
|
// GET /sessions/search?q=…&project=…&limit=20
|
|
3
3
|
// POST /sessions/:id/compact resolves which project/agent owns the file
|
|
4
4
|
// then delegates to compactConversation.
|
|
5
|
-
import path from "node:path";
|
|
6
5
|
import { readAgents } from "#core/apc/parser.js";
|
|
7
6
|
import { compactConversation } from "#core/stores/conversations-compactor.js";
|
|
8
7
|
import { searchSessions, findSessionFile } from "#core/stores/sessions-search.js";
|
|
8
|
+
import { asyncRoute } from "./shared.js";
|
|
9
|
+
import { resolveProject } from "#core/apc/projects-helpers.js";
|
|
9
10
|
|
|
11
|
+
// Plural on purpose: no ref means "search every project". This is a different
|
|
12
|
+
// operation from core's resolveProject (which resolves exactly one and throws),
|
|
13
|
+
// but the *matching* must agree with it — this used to accept only an id or an
|
|
14
|
+
// exact path, so `?project=savia` matched nothing here while working on every
|
|
15
|
+
// other route.
|
|
10
16
|
function resolveProjects(projects, projectRef) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
return
|
|
17
|
+
if (projectRef == null || projectRef === "") {
|
|
18
|
+
return projects.list().map((p) => projects.get(p.id)).filter(Boolean);
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
return [resolveProject(projects, projectRef)];
|
|
22
|
+
} catch {
|
|
23
|
+
return []; // unknown or ambiguous ref → no results, not a 500
|
|
16
24
|
}
|
|
17
|
-
return all.map((p) => projects.get(p.id)).filter(Boolean);
|
|
18
25
|
}
|
|
19
26
|
|
|
20
|
-
export function register(
|
|
21
|
-
|
|
27
|
+
export function register(api, { projects, config }) {
|
|
28
|
+
api.get("/sessions/search", (req, res) => {
|
|
22
29
|
const { q, project: projectRef, limit = "20" } = req.query;
|
|
23
30
|
if (!q) return res.status(400).json({ error: "q required" });
|
|
24
31
|
const lim = Math.min(parseInt(limit, 10) || 20, 200);
|
|
@@ -27,7 +34,7 @@ export function register(app, { projects, config }) {
|
|
|
27
34
|
res.json({ q, count: results.length, results });
|
|
28
35
|
});
|
|
29
36
|
|
|
30
|
-
|
|
37
|
+
api.post("/sessions/:id/compact", asyncRoute(async (req, res) => {
|
|
31
38
|
const { id } = req.params;
|
|
32
39
|
const { model: modelOverride, project: projectRef } = req.body || {};
|
|
33
40
|
const candidates = resolveProjects(projects, projectRef);
|
|
@@ -57,5 +64,5 @@ export function register(app, { projects, config }) {
|
|
|
57
64
|
} catch (e) {
|
|
58
65
|
res.status(500).json({ error: e.message });
|
|
59
66
|
}
|
|
60
|
-
});
|
|
67
|
+
}));
|
|
61
68
|
}
|
|
@@ -12,16 +12,16 @@ import {
|
|
|
12
12
|
agentSessionsDir,
|
|
13
13
|
createAgentSessionFile,
|
|
14
14
|
} from "#core/stores/sessions.js";
|
|
15
|
-
import { collectAllSessions, filterSessionsByQuery } from "#
|
|
15
|
+
import { collectAllSessions, filterSessionsByQuery } from "#core/sessions/index.js";
|
|
16
16
|
import { pageEnvelope } from "./shared.js";
|
|
17
17
|
|
|
18
|
-
export function register(
|
|
18
|
+
export function register(api, { projects, project }) {
|
|
19
19
|
// Cross-engine sessions (apx · claude · codex), newest first. Returns a
|
|
20
20
|
// { meta, data } envelope (meta = pagination info, data = rows). Paginated
|
|
21
21
|
// via ?limit & ?offset; with no limit, data is the full set as one page.
|
|
22
22
|
// Optional ?q= filters via the same core as `apx session find` (title match,
|
|
23
23
|
// + transcript content when ?deep=1) so terminal and web search are identical.
|
|
24
|
-
|
|
24
|
+
api.get("/sessions", (req, res) => {
|
|
25
25
|
const engineId = req.query.engine ? String(req.query.engine) : null;
|
|
26
26
|
const q = req.query.q ? String(req.query.q) : "";
|
|
27
27
|
const deep = req.query.deep === "1" || req.query.deep === "true";
|
|
@@ -49,7 +49,7 @@ export function register(app, { projects, project }) {
|
|
|
49
49
|
res.json(pageEnvelope(rows, req.query));
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
api.get("/projects/:pid/agents/:slug/sessions", (req, res) => {
|
|
53
53
|
const p = project(req, res);
|
|
54
54
|
if (!p) return;
|
|
55
55
|
const agents = readAgents(p.path);
|
|
@@ -78,7 +78,7 @@ export function register(app, { projects, project }) {
|
|
|
78
78
|
res.json(sessions);
|
|
79
79
|
});
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
api.post("/projects/:pid/agents/:slug/sessions", (req, res) => {
|
|
82
82
|
const p = project(req, res);
|
|
83
83
|
if (!p) return;
|
|
84
84
|
const { title, body = "" } = req.body || {};
|
|
@@ -93,7 +93,7 @@ export function register(app, { projects, project }) {
|
|
|
93
93
|
});
|
|
94
94
|
|
|
95
95
|
// GET session by filename (sid may include or omit the .md extension)
|
|
96
|
-
|
|
96
|
+
api.get("/projects/:pid/sessions/:sid", (req, res) => {
|
|
97
97
|
const p = project(req, res);
|
|
98
98
|
if (!p) return;
|
|
99
99
|
const sid = req.params.sid;
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
//
|
|
3
3
|
// These were inlined in api.js (monolith). They are kept dependency-free so
|
|
4
4
|
// any route module can `import` them without pulling in the world.
|
|
5
|
-
import fs from "node:fs";
|
|
6
5
|
import path from "node:path";
|
|
7
6
|
import { randomUUID } from "node:crypto";
|
|
8
7
|
import { appendErrorTrace, previewText } from "#core/logging.js";
|
|
@@ -11,6 +10,7 @@ import { agentMemoryPath } from "#core/agent/memory.js";
|
|
|
11
10
|
import { apcMemoryFile } from "#core/apc/paths.js";
|
|
12
11
|
import { CHANNELS } from "#core/constants/channels.js";
|
|
13
12
|
import { isKnownSpaRoute } from "./web.js";
|
|
13
|
+
import { apiPath, isApiPath } from "./prefix.js";
|
|
14
14
|
|
|
15
15
|
export const nowIso = () =>
|
|
16
16
|
new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
@@ -20,6 +20,44 @@ export const nowIso = () =>
|
|
|
20
20
|
// full set as a single page (data = 100% of rows) so non-paginated callers get
|
|
21
21
|
// the same shape — meta just reports one page covering everything.
|
|
22
22
|
// meta: { total, offset, limit, pageSize, page, pageCount }
|
|
23
|
+
/**
|
|
24
|
+
* Wrap an async route handler so a rejected promise becomes a 500 instead of
|
|
25
|
+
* an unhandled rejection.
|
|
26
|
+
*
|
|
27
|
+
* Express 4 does not await handlers: if one throws asynchronously, the error
|
|
28
|
+
* never reaches the error middleware, the request hangs, and on Node >= 15 the
|
|
29
|
+
* unhandled rejection takes the whole daemon down. Several routes awaited work
|
|
30
|
+
* with no try/catch, so a single failing preview or engine probe could kill a
|
|
31
|
+
* process serving the SPA, Telegram polling and voice at the same time.
|
|
32
|
+
*
|
|
33
|
+
* api.get("/things", asyncRoute(async (req, res) => { ... }))
|
|
34
|
+
*/
|
|
35
|
+
export function asyncRoute(handler) {
|
|
36
|
+
return (req, res, next) => Promise.resolve(handler(req, res, next)).catch(next);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Terminal error middleware. Mounted after every route; turns anything that
|
|
41
|
+
* reached `next(err)` into a JSON `{ error }` with a real status code.
|
|
42
|
+
*/
|
|
43
|
+
export function errorMiddleware(log = () => {}) {
|
|
44
|
+
// eslint-disable-next-line no-unused-vars -- Express detects the 4-arg shape.
|
|
45
|
+
return (err, req, res, _next) => {
|
|
46
|
+
const status = Number(err?.status || err?.statusCode) || 500;
|
|
47
|
+
const message = err?.message || "internal error";
|
|
48
|
+
log(`error: ${req.method} ${req.originalUrl} → ${status}: ${err?.stack || message}`);
|
|
49
|
+
try {
|
|
50
|
+
appendErrorTrace({
|
|
51
|
+
where: `${req.method} ${req.originalUrl}`,
|
|
52
|
+
error: message,
|
|
53
|
+
trace_id: req.apxTraceId,
|
|
54
|
+
});
|
|
55
|
+
} catch { /* tracing must never mask the original error */ }
|
|
56
|
+
if (res.headersSent) return;
|
|
57
|
+
res.status(status).json({ error: message });
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
23
61
|
export function pageEnvelope(rows, query = {}) {
|
|
24
62
|
const total = rows.length;
|
|
25
63
|
const hasLimit = query.limit != null && query.limit !== "";
|
|
@@ -46,12 +84,19 @@ export function traceIdMiddleware(req, res, next) {
|
|
|
46
84
|
next();
|
|
47
85
|
}
|
|
48
86
|
|
|
49
|
-
// Paths that bypass auth: /health for liveness probes, /pair/* so a
|
|
50
|
-
// client can bootstrap a token without already having one, and
|
|
51
|
-
// /admin/web-token so the local same-origin admin panel can self-bootstrap.
|
|
52
|
-
// /pair/init and /admin/web-token both enforce localhost-only checks of
|
|
87
|
+
// Paths that bypass auth: /api/health for liveness probes, /api/pair/* so a
|
|
88
|
+
// fresh client can bootstrap a token without already having one, and
|
|
89
|
+
// /api/admin/web-token so the local same-origin admin panel can self-bootstrap.
|
|
90
|
+
// /api/pair/init and /api/admin/web-token both enforce localhost-only checks of
|
|
53
91
|
// their own — the auth middleware just gets out of their way.
|
|
54
|
-
|
|
92
|
+
//
|
|
93
|
+
// These are full paths: the middleware runs at app level (before the /api
|
|
94
|
+
// router), so req.path is the complete URL path.
|
|
95
|
+
const UNAUTHENTICATED_PREFIXES = [
|
|
96
|
+
apiPath("/health"),
|
|
97
|
+
apiPath("/pair/"),
|
|
98
|
+
apiPath("/admin/web-token"),
|
|
99
|
+
];
|
|
55
100
|
|
|
56
101
|
// Does this path look like a static asset (has a file extension)? Vite emits
|
|
57
102
|
// hashed, extension-bearing filenames (index-abc123.js, logo.svg, font.woff2),
|
|
@@ -62,18 +107,19 @@ function isStaticAssetPath(p) {
|
|
|
62
107
|
}
|
|
63
108
|
|
|
64
109
|
function isUnauthenticatedPath(p, method = "GET") {
|
|
65
|
-
if (p === "/health") return true;
|
|
66
|
-
if (p === "/admin/web-token") return true;
|
|
67
110
|
for (const prefix of UNAUTHENTICATED_PREFIXES) {
|
|
68
111
|
if (p === prefix.replace(/\/$/, "") || p.startsWith(prefix)) return true;
|
|
69
112
|
}
|
|
113
|
+
// Everything else under /api needs a token, full stop. Checked BEFORE the
|
|
114
|
+
// SPA-bootstrap exemption below, which would otherwise let a data route pass
|
|
115
|
+
// simply because its last segment happens to carry a file extension —
|
|
116
|
+
// GET /api/projects/0/artifacts/report.html is a data route, not an asset.
|
|
117
|
+
if (isApiPath(p)) return false;
|
|
70
118
|
// SPA bootstrap: the admin bundle loads before it holds a bearer, so a GET
|
|
71
119
|
// for a static asset or a known client-router route is served without auth —
|
|
72
|
-
// the bundle then fetches /admin/web-token.
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
// public just because someone forgot to register its prefix (the old
|
|
76
|
-
// denylist failure mode).
|
|
120
|
+
// the bundle then fetches /api/admin/web-token. Since every data route now
|
|
121
|
+
// lives under /api and returned false above, this exemption can only ever
|
|
122
|
+
// reach panel assets and client-router paths.
|
|
77
123
|
if (method === "GET" && (isStaticAssetPath(p) || isKnownSpaRoute(p))) return true;
|
|
78
124
|
return false;
|
|
79
125
|
}
|
|
@@ -113,8 +113,8 @@ function indexStatus() {
|
|
|
113
113
|
};
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
export function register(
|
|
117
|
-
|
|
116
|
+
export function register(api /*, ctx */) {
|
|
117
|
+
api.get("/skills", (req, res) => {
|
|
118
118
|
const projectPath = typeof req.query?.project_path === "string" && req.query.project_path
|
|
119
119
|
? req.query.project_path
|
|
120
120
|
: undefined;
|
|
@@ -149,7 +149,7 @@ export function register(app /*, ctx */) {
|
|
|
149
149
|
|
|
150
150
|
// ---- Full detail (viewer) ----------------------------------------------
|
|
151
151
|
|
|
152
|
-
|
|
152
|
+
api.get("/skills/:slug/detail", (req, res) => {
|
|
153
153
|
try {
|
|
154
154
|
const projectPath = typeof req.query?.project_path === "string" && req.query.project_path
|
|
155
155
|
? req.query.project_path
|
|
@@ -175,7 +175,7 @@ export function register(app /*, ctx */) {
|
|
|
175
175
|
|
|
176
176
|
// ---- Enable / disable per scope ----------------------------------------
|
|
177
177
|
|
|
178
|
-
|
|
178
|
+
api.put("/skills/enabled", (req, res) => {
|
|
179
179
|
try {
|
|
180
180
|
const { slug, enabled, scope, project_path } = req.body || {};
|
|
181
181
|
if (!slug || typeof slug !== "string") {
|
|
@@ -202,7 +202,7 @@ export function register(app /*, ctx */) {
|
|
|
202
202
|
// ---- Create / import user skills ---------------------------------------
|
|
203
203
|
|
|
204
204
|
// Online editor: write a SKILL.md from slug + description + body.
|
|
205
|
-
|
|
205
|
+
api.post("/skills", (req, res) => {
|
|
206
206
|
try {
|
|
207
207
|
const { slug, description, body, project_path } = req.body || {};
|
|
208
208
|
if (!slug || typeof slug !== "string" || !SLUG_RE.test(slug)) {
|
|
@@ -220,7 +220,7 @@ export function register(app /*, ctx */) {
|
|
|
220
220
|
});
|
|
221
221
|
|
|
222
222
|
// Import from an uploaded .zip (sent as base64 in JSON — skills are tiny).
|
|
223
|
-
|
|
223
|
+
api.post("/skills/import/zip", (req, res) => {
|
|
224
224
|
let tmp;
|
|
225
225
|
try {
|
|
226
226
|
const { data, project_path } = req.body || {};
|
|
@@ -257,7 +257,7 @@ export function register(app /*, ctx */) {
|
|
|
257
257
|
|
|
258
258
|
// Import by cloning a git repo. The repo root (or its single skill subdir)
|
|
259
259
|
// must contain a SKILL.md.
|
|
260
|
-
|
|
260
|
+
api.post("/skills/import/repo", (req, res) => {
|
|
261
261
|
let tmp;
|
|
262
262
|
try {
|
|
263
263
|
const { url, project_path } = req.body || {};
|
|
@@ -293,7 +293,7 @@ export function register(app /*, ctx */) {
|
|
|
293
293
|
}
|
|
294
294
|
});
|
|
295
295
|
|
|
296
|
-
|
|
296
|
+
api.delete("/skills/:slug", (req, res) => {
|
|
297
297
|
try {
|
|
298
298
|
const slug = req.params.slug;
|
|
299
299
|
if (!slug || !SLUG_RE.test(slug)) {
|
|
@@ -344,7 +344,7 @@ export function register(app /*, ctx */) {
|
|
|
344
344
|
|
|
345
345
|
// ---- Inspector config + status -----------------------------------------
|
|
346
346
|
|
|
347
|
-
|
|
347
|
+
api.get("/skills/inspector", (_req, res) => {
|
|
348
348
|
try {
|
|
349
349
|
const cfg = readConfig();
|
|
350
350
|
res.json({
|
|
@@ -358,7 +358,7 @@ export function register(app /*, ctx */) {
|
|
|
358
358
|
}
|
|
359
359
|
});
|
|
360
360
|
|
|
361
|
-
|
|
361
|
+
api.put("/skills/inspector", (req, res) => {
|
|
362
362
|
try {
|
|
363
363
|
const patch = req.body || {};
|
|
364
364
|
const cfg = readConfig();
|
|
@@ -388,7 +388,7 @@ export function register(app /*, ctx */) {
|
|
|
388
388
|
|
|
389
389
|
// ---- Index build --------------------------------------------------------
|
|
390
390
|
|
|
391
|
-
|
|
391
|
+
api.post("/skills/index", async (req, res) => {
|
|
392
392
|
try {
|
|
393
393
|
const { project_path, force } = req.body || {};
|
|
394
394
|
const cfg = readConfig();
|
|
@@ -423,7 +423,7 @@ export function register(app /*, ctx */) {
|
|
|
423
423
|
|
|
424
424
|
// ---- Dry-run ------------------------------------------------------------
|
|
425
425
|
|
|
426
|
-
|
|
426
|
+
api.post("/skills/inspect", async (req, res) => {
|
|
427
427
|
try {
|
|
428
428
|
const { prompt, project_path } = req.body || {};
|
|
429
429
|
if (!prompt || typeof prompt !== "string") {
|
|
@@ -91,8 +91,8 @@ function wrapOnEventForLog(send, { trace_id, channel }) {
|
|
|
91
91
|
};
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
export function register(
|
|
95
|
-
|
|
94
|
+
export function register(api, { projects, registries, plugins, project, config }) {
|
|
95
|
+
api.post("/projects/:pid/super-agent/chat/stream", async (req, res) => {
|
|
96
96
|
const p = project(req, res);
|
|
97
97
|
if (!p) return;
|
|
98
98
|
// Optional coding-surface knobs: the terminal Code TUI (apx code, Build
|
|
@@ -223,7 +223,7 @@ export function register(app, { projects, registries, plugins, project, config }
|
|
|
223
223
|
// <id>` when the session lives outside any registered APX project (e.g. a
|
|
224
224
|
// raw Claude/Codex session). Returns { text } so callers can format the
|
|
225
225
|
// summary however they want.
|
|
226
|
-
|
|
226
|
+
api.post("/super-agent/summarize", async (req, res) => {
|
|
227
227
|
const { prompt, context_note: contextNote = "", model, max_tokens } = req.body || {};
|
|
228
228
|
if (!prompt) return res.status(400).json({ error: "prompt required" });
|
|
229
229
|
try {
|
|
@@ -254,7 +254,7 @@ export function register(app, { projects, registries, plugins, project, config }
|
|
|
254
254
|
}
|
|
255
255
|
});
|
|
256
256
|
|
|
257
|
-
|
|
257
|
+
api.post("/projects/:pid/super-agent/chat", async (req, res) => {
|
|
258
258
|
const p = project(req, res);
|
|
259
259
|
if (!p) return;
|
|
260
260
|
const { prompt, previousMessages, model, maxIters, maxTokens, completionContract } =
|
|
@@ -24,11 +24,11 @@ import {
|
|
|
24
24
|
} from "#core/stores/tasks.js";
|
|
25
25
|
import { pageEnvelope } from "./shared.js";
|
|
26
26
|
|
|
27
|
-
export function register(
|
|
27
|
+
export function register(api, { project, projects }) {
|
|
28
28
|
// Global tasks across every project, newest first. Returns a { meta, data }
|
|
29
29
|
// envelope. Paginated via ?limit & ?offset; with no limit, data is the full
|
|
30
30
|
// set as one page.
|
|
31
|
-
|
|
31
|
+
api.get("/tasks", (req, res) => {
|
|
32
32
|
const { state, tag, agent, due_before, due_after, status, updated_since } = req.query;
|
|
33
33
|
|
|
34
34
|
// Resolve the registered projects to what core needs, dropping any the
|
|
@@ -63,7 +63,7 @@ export function register(app, { project, projects }) {
|
|
|
63
63
|
|
|
64
64
|
// Per-project tasks. Returns a { meta, data } envelope; with no ?limit the
|
|
65
65
|
// data array is the full filtered set (one page).
|
|
66
|
-
|
|
66
|
+
api.get("/projects/:pid/tasks", (req, res) => {
|
|
67
67
|
const p = project(req, res);
|
|
68
68
|
if (!p) return;
|
|
69
69
|
const { state, tag, agent, due_before, due_after, status, updated_since } = req.query;
|
|
@@ -79,7 +79,7 @@ export function register(app, { project, projects }) {
|
|
|
79
79
|
res.json(pageEnvelope(all, req.query));
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
api.post("/projects/:pid/tasks", (req, res) => {
|
|
83
83
|
const p = project(req, res);
|
|
84
84
|
if (!p) return;
|
|
85
85
|
try {
|
|
@@ -90,7 +90,7 @@ export function register(app, { project, projects }) {
|
|
|
90
90
|
}
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
api.get("/projects/:pid/tasks/:id", (req, res) => {
|
|
94
94
|
const p = project(req, res);
|
|
95
95
|
if (!p) return;
|
|
96
96
|
const task = getTask(p.storagePath, req.params.id);
|
|
@@ -98,7 +98,7 @@ export function register(app, { project, projects }) {
|
|
|
98
98
|
res.json(task);
|
|
99
99
|
});
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
api.patch("/projects/:pid/tasks/:id", (req, res) => {
|
|
102
102
|
const p = project(req, res);
|
|
103
103
|
if (!p) return;
|
|
104
104
|
const { patch } = req.body || {};
|
|
@@ -110,7 +110,7 @@ export function register(app, { project, projects }) {
|
|
|
110
110
|
res.json(updated);
|
|
111
111
|
});
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
api.post("/projects/:pid/tasks/:id/done", (req, res) => {
|
|
114
114
|
const p = project(req, res);
|
|
115
115
|
if (!p) return;
|
|
116
116
|
const { by = null } = req.body || {};
|
|
@@ -119,7 +119,7 @@ export function register(app, { project, projects }) {
|
|
|
119
119
|
res.json(updated);
|
|
120
120
|
});
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
api.post("/projects/:pid/tasks/:id/drop", (req, res) => {
|
|
123
123
|
const p = project(req, res);
|
|
124
124
|
if (!p) return;
|
|
125
125
|
const { by = null } = req.body || {};
|
|
@@ -128,7 +128,7 @@ export function register(app, { project, projects }) {
|
|
|
128
128
|
res.json(updated);
|
|
129
129
|
});
|
|
130
130
|
|
|
131
|
-
|
|
131
|
+
api.post("/projects/:pid/tasks/:id/reopen", (req, res) => {
|
|
132
132
|
const p = project(req, res);
|
|
133
133
|
if (!p) return;
|
|
134
134
|
const updated = reopenTask(p.storagePath, req.params.id);
|
|
@@ -137,7 +137,7 @@ export function register(app, { project, projects }) {
|
|
|
137
137
|
});
|
|
138
138
|
|
|
139
139
|
// Move an open task through its workflow (pending → running → in_review …).
|
|
140
|
-
|
|
140
|
+
api.post("/projects/:pid/tasks/:id/status", (req, res) => {
|
|
141
141
|
const p = project(req, res);
|
|
142
142
|
if (!p) return;
|
|
143
143
|
const { status } = req.body || {};
|
|
@@ -149,7 +149,7 @@ export function register(app, { project, projects }) {
|
|
|
149
149
|
});
|
|
150
150
|
|
|
151
151
|
// Lightweight summary endpoint for status displays.
|
|
152
|
-
|
|
152
|
+
api.get("/projects/:pid/tasks-summary", (req, res) => {
|
|
153
153
|
const p = project(req, res);
|
|
154
154
|
if (!p) return;
|
|
155
155
|
res.json(countTasks(p.storagePath));
|