@agentprojectcontext/apx 1.32.0 → 1.33.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/package.json +6 -1
- package/skills/apc-context/SKILL.md +5 -2
- package/skills/apx/SKILL.md +3 -3
- package/skills/apx-agency-agents/SKILL.md +5 -5
- package/skills/apx-agent/SKILL.md +7 -7
- package/skills/apx-mcp/SKILL.md +6 -4
- package/skills/apx-mcp-builder/SKILL.md +4 -7
- package/skills/apx-project/SKILL.md +4 -5
- package/skills/apx-routine/SKILL.md +14 -12
- package/skills/apx-runtime/SKILL.md +5 -3
- package/skills/apx-sessions/SKILL.md +5 -5
- package/skills/apx-skill-builder/SKILL.md +10 -6
- package/skills/apx-task/SKILL.md +8 -8
- package/skills/apx-telegram/SKILL.md +23 -7
- package/skills/apx-voice/SKILL.md +8 -6
- package/src/core/{agent-system.js → agent/build-agent-system.js} +10 -12
- package/src/core/agent/index.js +0 -2
- package/src/core/{agent-memory.js → agent/memory.js} +2 -2
- package/src/core/agent/model-router.js +21 -43
- package/src/core/agent/prompt-builder.js +17 -63
- package/src/core/agent/prompts/action-discipline.md +24 -0
- package/src/core/agent/prompts/channels/code.md +8 -12
- package/src/core/agent/prompts/channels/desktop.md +6 -4
- package/src/core/agent/prompts/channels/routine.md +10 -1
- package/src/core/agent/prompts/channels/telegram.md +10 -1
- package/src/core/agent/prompts/channels/web_code.md +20 -0
- package/src/core/agent/prompts/modes/voice.md +2 -2
- package/src/core/agent/prompts/super-agent-base.md +2 -2
- package/src/core/agent/run-agent.js +37 -35
- package/src/core/agent/runtime-bridge.js +42 -0
- package/src/core/agent/self-memory.js +19 -9
- package/src/core/agent/skills/catalog.js +65 -0
- package/src/core/agent/skills/index.js +6 -0
- package/src/{host/daemon/skills-loader.js → core/agent/skills/loader.js} +3 -3
- package/src/core/agent/skills/rag.js +91 -0
- package/src/core/agent/skills/trigger.js +71 -0
- package/src/{host/daemon → core/agent}/super-agent.js +5 -5
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/add-project.js +3 -4
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/call-agent.js +2 -2
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/call-mcp.js +1 -2
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/call-runtime.js +10 -11
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/create-task.js +1 -1
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/discover-tools.js +1 -1
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/edit-file.js +1 -2
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/import-agent.js +4 -5
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/list-agents.js +1 -1
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/list-skills.js +7 -2
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/list-tasks.js +1 -1
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/list-vault-agents.js +1 -1
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/load-skill.js +1 -1
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/read-agent-memory.js +1 -1
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/read-self-memory.js +1 -1
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/remember.js +1 -1
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/run-shell.js +1 -2
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/search-messages.js +1 -1
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/search-sessions.js +1 -1
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/send-telegram.js +0 -2
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/set-identity.js +1 -3
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/set-permission-mode.js +1 -3
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/tail-messages.js +1 -1
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/transcribe-audio.js +1 -1
- package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/write-file.js +1 -2
- package/src/core/agent/tools/helpers.js +74 -0
- package/src/{host/daemon/super-agent-tools → core/agent/tools}/registry-bridge.js +3 -3
- package/src/{host/daemon/super-agent-tools/index.js → core/agent/tools/registry.js} +31 -32
- package/src/core/apc/agents-vault.js +37 -0
- package/src/core/{scaffold.js → apc/scaffold.js} +4 -5
- package/src/core/{config.js → config/index.js} +21 -27
- package/src/core/config/paths.js +32 -0
- package/src/core/constants/actors.js +8 -0
- package/src/core/constants/channels.js +19 -0
- package/src/core/constants/index.js +5 -0
- package/src/core/constants/permissions.js +17 -0
- package/src/core/constants/roles.js +9 -0
- package/src/core/engines/_streaming.js +63 -0
- package/src/core/engines/anthropic.js +11 -22
- package/src/core/engines/ollama.js +7 -16
- package/src/core/identity/index.js +8 -0
- package/src/core/{identity.js → identity/self.js} +5 -5
- package/src/core/{telegram-identity.js → identity/telegram.js} +1 -1
- package/src/core/logging.js +1 -1
- package/src/core/mascot.js +1 -1
- package/src/core/memory/active-threads.js +10 -10
- package/src/core/memory/broker.js +9 -9
- package/src/core/memory/compactor.js +2 -2
- package/src/core/memory/index.js +2 -2
- package/src/core/memory/indexer.js +1 -1
- package/src/core/{code-sessions-store.js → stores/code-sessions.js} +7 -8
- package/src/core/{messages-store.js → stores/messages.js} +6 -4
- package/src/core/stores/routine-memory.js +71 -0
- package/src/core/{routines-store.js → stores/routines.js} +1 -3
- package/src/core/stores/runtime-sessions.js +99 -0
- package/src/core/{tasks-store.js → stores/tasks.js} +3 -8
- package/src/core/update-check.js +1 -1
- package/src/core/util/ids.js +14 -0
- package/src/core/util/index.js +2 -0
- package/src/core/util/time.js +9 -0
- package/src/core/voice/tts.js +1 -1
- package/src/host/daemon/api/admin-config.js +4 -3
- package/src/host/daemon/api/admin.js +1 -1
- package/src/host/daemon/api/agents.js +4 -25
- package/src/host/daemon/api/artifacts.js +26 -1
- package/src/host/daemon/api/code.js +62 -17
- package/src/host/daemon/api/confirm.js +1 -1
- package/src/host/daemon/api/connections.js +2 -2
- package/src/host/daemon/api/conversations.js +2 -2
- package/src/host/daemon/api/deck.js +1 -1
- package/src/host/daemon/api/desktop.js +1 -1
- package/src/host/daemon/api/embeddings.js +4 -4
- package/src/host/daemon/api/engines.js +2 -2
- package/src/host/daemon/api/exec.js +20 -5
- package/src/host/daemon/api/identity.js +1 -1
- package/src/host/daemon/api/mcps.js +1 -1
- package/src/host/daemon/api/messages.js +1 -1
- package/src/host/daemon/api/runtimes.js +9 -8
- package/src/host/daemon/api/sessions-search.js +1 -1
- package/src/host/daemon/api/sessions.js +2 -2
- package/src/host/daemon/api/shared.js +5 -4
- package/src/host/daemon/api/skills.js +30 -0
- package/src/host/daemon/api/super-agent.js +29 -9
- package/src/host/daemon/api/tasks.js +2 -2
- package/src/host/daemon/api/telegram.js +1 -1
- package/src/host/daemon/api/tools.js +6 -6
- package/src/host/daemon/api/tts.js +2 -2
- package/src/host/daemon/api/voice.js +14 -12
- package/src/host/daemon/api.js +2 -0
- package/src/host/daemon/compact.js +1 -1
- package/src/host/daemon/db.js +4 -4
- package/src/host/daemon/desktop-ws.js +1 -1
- package/src/host/daemon/index.js +4 -4
- package/src/host/daemon/plugins/{desktop.js → desktop/index.js} +11 -6
- package/src/host/daemon/plugins/index.js +2 -2
- package/src/host/daemon/plugins/{telegram.js → telegram/index.js} +52 -193
- package/src/host/daemon/plugins/telegram/media.js +162 -0
- package/src/host/daemon/projects-helpers.js +54 -0
- package/src/host/daemon/routines.js +28 -12
- package/src/host/daemon/smoke.js +2 -2
- package/src/host/daemon/token-store.js +1 -1
- package/src/host/daemon/transcription.js +2 -2
- package/src/host/daemon/wakeup.js +2 -2
- package/src/interfaces/cli/commands/agent.js +3 -3
- package/src/interfaces/cli/commands/command.js +1 -1
- package/src/interfaces/cli/commands/config.js +3 -2
- package/src/interfaces/cli/commands/desktop.js +1 -1
- package/src/interfaces/cli/commands/exec.js +2 -1
- package/src/interfaces/cli/commands/identity.js +2 -2
- package/src/interfaces/cli/commands/init.js +1 -1
- package/src/interfaces/cli/commands/mcp.js +1 -1
- package/src/interfaces/cli/commands/memory.js +2 -2
- package/src/interfaces/cli/commands/model.js +16 -6
- package/src/interfaces/cli/commands/project.js +1 -1
- package/src/interfaces/cli/commands/routine.js +58 -0
- package/src/interfaces/cli/commands/search.js +1 -1
- package/src/interfaces/cli/commands/session.js +4 -4
- package/src/interfaces/cli/commands/setup.js +4 -3
- package/src/interfaces/cli/commands/skills.js +25 -4
- package/src/interfaces/cli/commands/status.js +1 -1
- package/src/interfaces/cli/commands/sys.js +11 -4
- package/src/interfaces/cli/commands/update.js +1 -1
- package/src/interfaces/cli/index.js +4 -4
- package/src/interfaces/cli/postinstall.js +2 -2
- package/src/interfaces/mcp-server/index.js +1 -1
- package/src/interfaces/tui/component/prompt/index.tsx +3 -1
- package/src/interfaces/tui/context/sdk-apx.tsx +47 -7
- package/src/interfaces/tui/context/sync-apx.tsx +20 -2
- package/src/interfaces/tui/context/sync.tsx +2 -1
- package/src/interfaces/tui/routes/session/index.tsx +151 -136
- package/src/interfaces/tui/routes/session/sidebar-apx.tsx +37 -15
- package/src/interfaces/tui/run.ts +2 -0
- package/src/interfaces/web/dist/assets/index-7dVT2O1S.css +1 -0
- package/src/interfaces/web/dist/assets/index-DWsE_8Nz.js +602 -0
- package/src/interfaces/web/dist/assets/index-DWsE_8Nz.js.map +1 -0
- package/src/interfaces/web/dist/index.html +2 -2
- package/src/interfaces/web/package-lock.json +6 -6
- package/src/interfaces/web/src/App.tsx +53 -32
- package/src/interfaces/web/src/components/RobyBubble.tsx +12 -6
- package/src/interfaces/web/src/components/UiSelect.tsx +13 -3
- package/src/interfaces/web/src/components/chat/SkillPicker.tsx +77 -0
- package/src/interfaces/web/src/components/code/CodeArtifactsTab.tsx +253 -111
- package/src/interfaces/web/src/components/code/CodeChangesTab.tsx +10 -8
- package/src/interfaces/web/src/components/code/CodeComposer.tsx +20 -17
- package/src/interfaces/web/src/components/code/CodeContextTab.tsx +43 -18
- package/src/interfaces/web/src/components/code/CodeFileTree.tsx +212 -0
- package/src/interfaces/web/src/components/code/CodeFileViewer.tsx +121 -0
- package/src/interfaces/web/src/components/code/CodeProjectPicker.tsx +1 -1
- package/src/interfaces/web/src/components/code/CodeSessionList.tsx +30 -26
- package/src/interfaces/web/src/components/code/CodeSidePanel.tsx +40 -21
- package/src/interfaces/web/src/components/code/CodeTerminal.tsx +140 -0
- package/src/interfaces/web/src/components/common/TabLayout.tsx +11 -7
- package/src/interfaces/web/src/components/common/TabNav.tsx +3 -3
- package/src/interfaces/web/src/components/layout/ProjectSidebar.tsx +4 -2
- package/src/interfaces/web/src/components/ui/chat-input.tsx +17 -6
- package/src/interfaces/web/src/hooks/useChat.ts +48 -2
- package/src/interfaces/web/src/hooks/useNavCollapseCtx.tsx +83 -0
- package/src/interfaces/web/src/hooks/usePersonaName.ts +11 -0
- package/src/interfaces/web/src/i18n/en.ts +7 -7
- package/src/interfaces/web/src/i18n/es.ts +8 -8
- package/src/interfaces/web/src/lib/api/agents.ts +1 -1
- package/src/interfaces/web/src/lib/api/artifacts.ts +10 -0
- package/src/interfaces/web/src/lib/api/code.ts +4 -2
- package/src/interfaces/web/src/lib/api/skills.ts +25 -0
- package/src/interfaces/web/src/lib/api.ts +1 -0
- package/src/interfaces/web/src/screens/modules/CodeScreen.tsx +430 -86
- package/src/interfaces/web/src/screens/modules/DeckScreen.tsx +5 -18
- package/src/interfaces/web/src/screens/modules/DesktopScreen.tsx +1 -8
- package/src/interfaces/web/src/screens/modules/VoiceScreen.tsx +39 -40
- package/src/interfaces/web/src/screens/project/ChatTab.tsx +16 -16
- package/src/skills/apc-context/SKILL.md +159 -0
- package/src/core/agent/ghost-guard.js +0 -24
- package/src/core/agent/prompts/channels/terminal.md +0 -16
- package/src/host/daemon/apc-runtime-context.js +0 -124
- package/src/host/daemon/super-agent-tools/helpers.js +0 -124
- package/src/host/daemon/tool-call-parser.js +0 -2
- package/src/interfaces/web/dist/assets/index-63P_ji1a.js +0 -571
- package/src/interfaces/web/dist/assets/index-63P_ji1a.js.map +0 -1
- package/src/interfaces/web/dist/assets/index-DLWy6dYz.css +0 -1
- /package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/ask-questions.js +0 -0
- /package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/list-files.js +0 -0
- /package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/list-mcps.js +0 -0
- /package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/list-projects.js +0 -0
- /package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/read-file.js +0 -0
- /package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/search-files.js +0 -0
- /package/src/core/agent/{pseudo-tools.js → tools/pseudo-tools.js} +0 -0
- /package/src/core/agent/{tool-call-parser.js → tools/tool-call-parser.js} +0 -0
- /package/src/core/{parser.js → apc/parser.js} +0 -0
- /package/src/core/{apc-skill-sync.js → apc/skill-sync.js} +0 -0
- /package/src/core/{artifacts-store.js → stores/artifacts.js} +0 -0
- /package/src/{host/daemon → core/stores}/engine-sessions.js +0 -0
- /package/src/core/{session-store.js → stores/sessions.js} +0 -0
- /package/src/host/daemon/plugins/{telegram-ask.js → telegram/ask.js} +0 -0
|
@@ -119,48 +119,47 @@ export function VoiceScreen() {
|
|
|
119
119
|
};
|
|
120
120
|
|
|
121
121
|
return (
|
|
122
|
-
<div className="mx-auto max-w-
|
|
123
|
-
<
|
|
124
|
-
|
|
125
|
-
<
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
122
|
+
<div className="mx-auto max-w-6xl p-6" data-testid="screen-voice">
|
|
123
|
+
<div className="grid gap-6 xl:grid-cols-2">
|
|
124
|
+
{/* Left: TTS providers */}
|
|
125
|
+
<Section
|
|
126
|
+
title="Proveedores de voz (TTS)"
|
|
127
|
+
description="Motores de síntesis. El estado lo reporta el daemon en vivo. Elegí cuál usar por defecto."
|
|
128
|
+
>
|
|
129
|
+
{provLoading || cfgLoading ? (
|
|
130
|
+
<Loading />
|
|
131
|
+
) : provError ? (
|
|
132
|
+
<Empty>No se pudieron cargar los proveedores: {(provError as Error).message}</Empty>
|
|
133
|
+
) : (
|
|
134
|
+
<VoiceProviderList
|
|
135
|
+
engines={engines}
|
|
136
|
+
order={order}
|
|
137
|
+
mode={mode}
|
|
138
|
+
configuredProvider={configuredProvider}
|
|
139
|
+
onSetMode={setMode}
|
|
140
|
+
onSetDefault={setDefault}
|
|
141
|
+
onToggleEnabled={toggleEnabled}
|
|
142
|
+
onReorder={reorder}
|
|
143
|
+
onConfigure={(id) => setEditing(id)}
|
|
144
|
+
busy={busyDefault}
|
|
145
|
+
/>
|
|
146
|
+
)}
|
|
147
|
+
</Section>
|
|
129
148
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
<Loading />
|
|
136
|
-
) : provError ? (
|
|
137
|
-
<Empty>No se pudieron cargar los proveedores: {(provError as Error).message}</Empty>
|
|
138
|
-
) : (
|
|
139
|
-
<VoiceProviderList
|
|
140
|
-
engines={engines}
|
|
141
|
-
order={order}
|
|
142
|
-
mode={mode}
|
|
143
|
-
configuredProvider={configuredProvider}
|
|
144
|
-
onSetMode={setMode}
|
|
145
|
-
onSetDefault={setDefault}
|
|
146
|
-
onToggleEnabled={toggleEnabled}
|
|
147
|
-
onReorder={reorder}
|
|
148
|
-
onConfigure={(id) => setEditing(id)}
|
|
149
|
-
busy={busyDefault}
|
|
150
|
-
/>
|
|
151
|
-
)}
|
|
152
|
-
</Section>
|
|
149
|
+
{/* Right: test + STT */}
|
|
150
|
+
<div className="space-y-6">
|
|
151
|
+
<Section title="Probar voz" description='Elegí con qué motor sintetizar y, si aplica, cómo querés que hable.'>
|
|
152
|
+
<VoiceTestCard engines={engines} defaultProvider={configuredProvider} mode={mode} />
|
|
153
|
+
</Section>
|
|
153
154
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
>
|
|
162
|
-
{cfgLoading ? <Loading /> : <VoiceSttCard config={transcriptionCfg} onPatch={patchStt} />}
|
|
163
|
-
</Section>
|
|
155
|
+
<Section
|
|
156
|
+
title="Transcripción (STT)"
|
|
157
|
+
description="Motor de voz a texto que usan el deck, Telegram y la CLI al escuchar."
|
|
158
|
+
>
|
|
159
|
+
{cfgLoading ? <Loading /> : <VoiceSttCard config={transcriptionCfg} onPatch={patchStt} />}
|
|
160
|
+
</Section>
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
164
163
|
|
|
165
164
|
<VoiceProviderModal
|
|
166
165
|
open={!!editing}
|
|
@@ -12,6 +12,7 @@ import { InlineAskPanel, pendingAskQuestions } from "../../components/chat/Inlin
|
|
|
12
12
|
import { useChat } from "../../hooks/useChat";
|
|
13
13
|
import { useToast } from "../../components/Toast";
|
|
14
14
|
import { t } from "../../i18n";
|
|
15
|
+
import { usePersonaName } from "../../hooks/usePersonaName";
|
|
15
16
|
import type { AgentEntry } from "../../types/daemon";
|
|
16
17
|
|
|
17
18
|
// Virtual entry slug used in the agent dropdown to address the daemon-level
|
|
@@ -28,18 +29,19 @@ export function ChatTab({ pid }: { pid: string }) {
|
|
|
28
29
|
const [model, setModel] = useState("");
|
|
29
30
|
const [dismissedAskKey, setDismissedAskKey] = useState<string | null>(null);
|
|
30
31
|
const { msgs, send: sendChat, stop, clear, streaming } = useChat(pid, (m) => toast.error(m));
|
|
32
|
+
const persona = usePersonaName();
|
|
31
33
|
|
|
32
34
|
const agentList = agents.data || [];
|
|
33
|
-
// Virtual options shown in the dropdown —
|
|
34
|
-
// real project agents.
|
|
35
|
-
// /super-agent/chat) so we expose it everywhere, not just /base.
|
|
35
|
+
// Virtual options shown in the dropdown — the super-agent is always first,
|
|
36
|
+
// then the real project agents. It works on every project (calls
|
|
37
|
+
// /projects/:pid/super-agent/chat) so we expose it everywhere, not just /base.
|
|
36
38
|
const isRoby = (slug: string | null | undefined) => slug === ROBY_SLUG;
|
|
37
39
|
const dropdownOptions = useMemo(
|
|
38
40
|
() => [
|
|
39
|
-
{ value: ROBY_SLUG, label:
|
|
41
|
+
{ value: ROBY_SLUG, label: `${persona} (super-agent)` },
|
|
40
42
|
...agentList.map((a) => ({ value: a.slug, label: a.slug })),
|
|
41
43
|
],
|
|
42
|
-
[agentList],
|
|
44
|
+
[agentList, persona],
|
|
43
45
|
);
|
|
44
46
|
const activeAgent = useMemo(
|
|
45
47
|
() => agentList.find((a) => a.slug === activeSlug) || agentList[0],
|
|
@@ -59,11 +61,9 @@ export function ChatTab({ pid }: { pid: string }) {
|
|
|
59
61
|
const resetConversation = () => clear();
|
|
60
62
|
|
|
61
63
|
const send = async (text: string) => {
|
|
62
|
-
// Roby (super-agent) is always available; a real project agent requires
|
|
63
|
-
// that the project actually has one configured.
|
|
64
64
|
if (!activeIsRoby && !activeAgent) return;
|
|
65
65
|
await sendChat(text, {
|
|
66
|
-
model:
|
|
66
|
+
model: model || undefined,
|
|
67
67
|
agentSlug: activeIsRoby ? undefined : activeAgent!.slug,
|
|
68
68
|
});
|
|
69
69
|
};
|
|
@@ -75,18 +75,16 @@ export function ChatTab({ pid }: { pid: string }) {
|
|
|
75
75
|
|
|
76
76
|
if (agents.isLoading) return <Loading />;
|
|
77
77
|
|
|
78
|
-
// Header subtitle differs: with Roby selected the chat goes through the
|
|
79
|
-
// super-agent (it CAN call tools); a project agent is a direct LLM call.
|
|
80
78
|
const headerSubtitle = activeIsRoby
|
|
81
|
-
? t("project.chat.
|
|
79
|
+
? t("project.chat.superagent_subtitle", { persona })
|
|
82
80
|
: t("project.chat.subtitle");
|
|
83
81
|
|
|
84
82
|
return (
|
|
85
|
-
<div className="flex h-
|
|
83
|
+
<div className="flex h-full flex-col overflow-hidden rounded-xl border border-border bg-card/40">
|
|
86
84
|
<header className="flex shrink-0 items-center justify-between gap-3 border-b border-border px-4 py-3">
|
|
87
85
|
<div className="min-w-0">
|
|
88
86
|
<h2 className="text-sm font-semibold">
|
|
89
|
-
{activeIsRoby ? t("project.chat.
|
|
87
|
+
{activeIsRoby ? t("project.chat.superagent_title", { persona }) : t("project.chat.title")}
|
|
90
88
|
</h2>
|
|
91
89
|
<p className="truncate text-[11px] text-muted-fg">{headerSubtitle}</p>
|
|
92
90
|
</div>
|
|
@@ -115,7 +113,9 @@ export function ChatTab({ pid }: { pid: string }) {
|
|
|
115
113
|
{msgs.length ? (
|
|
116
114
|
<MessageList msgs={msgs} onCopy={copyToClipboard} />
|
|
117
115
|
) : (
|
|
118
|
-
<
|
|
116
|
+
<div className="flex h-full items-center justify-center p-8">
|
|
117
|
+
<p className="text-sm text-muted-fg">{t("project.chat.empty")}</p>
|
|
118
|
+
</div>
|
|
119
119
|
)}
|
|
120
120
|
</div>
|
|
121
121
|
<ContextBar msgs={msgs} />
|
|
@@ -136,8 +136,8 @@ export function ChatTab({ pid }: { pid: string }) {
|
|
|
136
136
|
onSend={send}
|
|
137
137
|
onStop={stop}
|
|
138
138
|
streaming={streaming}
|
|
139
|
-
model={
|
|
140
|
-
onModelChange={
|
|
139
|
+
model={model}
|
|
140
|
+
onModelChange={setModel}
|
|
141
141
|
/>
|
|
142
142
|
<CreateAgentDialog
|
|
143
143
|
open={creating}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: apc-context
|
|
3
|
+
description: "ALWAYS activate when the project has a .apc/ directory or AGENTS.md file. Do not wait to be asked. Read .apc/ before making any assumption about agents, memory, or project structure. Activate on: .apc/, AGENTS.md, 'which agents', 'list agents', 'agent context', 'who are the agents', any question about agents or memory in this project. IMPORTANT: if .apc/migrate.md exists, open the conversation with a migration offer before answering anything else. If the user declines, delete .apc/migrate.md immediately so it is not shown again."
|
|
4
|
+
homepage: https://github.com/agentprojectcontext/agentprojectcontext
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Agent Project Context
|
|
8
|
+
|
|
9
|
+
This project uses APC. APC stores portable project context in `.apc/` and `AGENTS.md`.
|
|
10
|
+
|
|
11
|
+
APC does not store raw runtime sessions. Sessions, conversations, messages, caches, provider
|
|
12
|
+
threads, and private runtime memory stay in the IDE, CLI, daemon, or user-level store that created
|
|
13
|
+
them.
|
|
14
|
+
|
|
15
|
+
## FIRST: check for pending migration
|
|
16
|
+
|
|
17
|
+
Before doing anything else, check if `.apc/migrate.md` exists:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
cat .apc/migrate.md 2>/dev/null
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
If it exists, open with this offer before answering anything else:
|
|
24
|
+
|
|
25
|
+
> I see this project was initialized with Agent Project Context (APC).
|
|
26
|
+
>
|
|
27
|
+
> I found context files that may need migration:
|
|
28
|
+
> [list files from .apc/migrate.md]
|
|
29
|
+
>
|
|
30
|
+
> I can read them, separate durable project context from runtime/private state, and migrate only
|
|
31
|
+
> what belongs in APC.
|
|
32
|
+
>
|
|
33
|
+
> Want me to start?
|
|
34
|
+
|
|
35
|
+
If the user says no or later, delete `.apc/migrate.md` so the offer is not repeated.
|
|
36
|
+
|
|
37
|
+
## Migration rule: think, do not copy
|
|
38
|
+
|
|
39
|
+
Read detected files first. Also read `AGENTS.md` if it exists.
|
|
40
|
+
|
|
41
|
+
Classify content:
|
|
42
|
+
|
|
43
|
+
| Content | Action |
|
|
44
|
+
|---|---|
|
|
45
|
+
| Agent definitions: name, model, description | Put in `.apc/agents/<name>.md` and/or `AGENTS.md` |
|
|
46
|
+
| Shared project rules, stack notes, commands, testing policy | Keep in `AGENTS.md` |
|
|
47
|
+
| Reusable instruction blocks | Move to `.apc/skills/<name>.md` |
|
|
48
|
+
| Durable safe facts useful to all contributors | Add to `.apc/agents/<name>/memory.md` only after curation |
|
|
49
|
+
| MCP expectations without secrets | Add to `.apc/mcps.json` |
|
|
50
|
+
| Raw sessions, transcripts, conversations, messages, tool logs | Do not move into `.apc/`; leave with source runtime |
|
|
51
|
+
| Secrets, tokens, credentials, private headers | Do not store in repository |
|
|
52
|
+
| IDE UI settings or personal aliases | Leave in IDE/user config |
|
|
53
|
+
| Instructions to store sessions under `.apc/` | Drop as obsolete |
|
|
54
|
+
|
|
55
|
+
After migration:
|
|
56
|
+
|
|
57
|
+
1. Update `AGENTS.md` as the root project contract.
|
|
58
|
+
2. Create or update `.apc/agents/`, `.apc/skills/`, `.apc/mcps.json` as needed.
|
|
59
|
+
3. Do not create `.apc/**/sessions`, `.apc/messages`, or `.apc/conversations`.
|
|
60
|
+
4. Delete obsolete source files only when their useful project context was migrated or intentionally dropped.
|
|
61
|
+
5. Delete `.apc/migrate.md`.
|
|
62
|
+
6. Summarize what moved, what stayed local, and what was dropped.
|
|
63
|
+
|
|
64
|
+
## APC structure
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
AGENTS.md ← root project contract
|
|
68
|
+
.apc/
|
|
69
|
+
project.json ← project metadata
|
|
70
|
+
.gitignore ← safety guard
|
|
71
|
+
agents/<name>.md ← agent definition
|
|
72
|
+
agents/<name>/memory.md ← optional curated project memory
|
|
73
|
+
skills/<name>.md ← reusable project instructions
|
|
74
|
+
mcps.json ← MCP hints without secrets
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Do not store:
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
.apc/agents/<name>/sessions/
|
|
81
|
+
.apc/sessions/
|
|
82
|
+
.apc/conversations/
|
|
83
|
+
.apc/messages/
|
|
84
|
+
.apc/cache/
|
|
85
|
+
.apc/tmp/
|
|
86
|
+
.apc/private/
|
|
87
|
+
.apc/secrets/
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Visibility rules
|
|
91
|
+
|
|
92
|
+
| Data | Visibility | Commit? |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| Agent definitions, skills, project rules | `stable` / `project` | Yes |
|
|
95
|
+
| Curated safe `memory.md` | `project` | Yes, if team-safe |
|
|
96
|
+
| MCP hints without secrets | `project` | Yes |
|
|
97
|
+
| Sessions, conversations, messages | `local` | No; runtime-owned |
|
|
98
|
+
| Secrets, tokens, `*.secret.json`, `*.env` | `private` | Never |
|
|
99
|
+
| Caches, temp files, databases | `ephemeral` | No |
|
|
100
|
+
|
|
101
|
+
## Operating rules
|
|
102
|
+
|
|
103
|
+
1. Read `AGENTS.md` and relevant `.apc/` files before assuming project context.
|
|
104
|
+
2. Read agent definitions from `.apc/agents/<name>.md` when present.
|
|
105
|
+
3. Read curated project memory from `.apc/agents/<name>/memory.md` when present.
|
|
106
|
+
4. Write only durable, safe, curated facts to APC memory.
|
|
107
|
+
5. Never write raw sessions, transcripts, messages, conversations, or tool logs into `.apc/`.
|
|
108
|
+
6. Keep secrets out of APC and out of git.
|
|
109
|
+
7. Treat `.apc/mcps.json` as MCP configuration hints, not as an MCP implementation.
|
|
110
|
+
|
|
111
|
+
## Normalization
|
|
112
|
+
|
|
113
|
+
If agent formats are broken or use legacy fields (role, skills in YAML), offer to normalize:
|
|
114
|
+
|
|
115
|
+
```yaml
|
|
116
|
+
---
|
|
117
|
+
name: agent-name
|
|
118
|
+
model: inherit
|
|
119
|
+
description: Semantic activation trigger
|
|
120
|
+
---
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Identify and fix inconsistencies in `model` (use technical IDs or `inherit`) and ensure `description` is present for semantic activation.
|
|
124
|
+
|
|
125
|
+
## Sessions
|
|
126
|
+
|
|
127
|
+
Sessions belong to the runtime that created them.
|
|
128
|
+
|
|
129
|
+
Examples:
|
|
130
|
+
|
|
131
|
+
```text
|
|
132
|
+
Codex runtime storage
|
|
133
|
+
Claude Code runtime storage
|
|
134
|
+
OpenCode runtime storage
|
|
135
|
+
~/.apx/projects/<project-id>/agents/<name>/sessions/
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
At task end, provide the user a concise result. If project memory should be updated, write a short
|
|
139
|
+
sanitized fact to `.apc/agents/<name>/memory.md` only when useful and safe.
|
|
140
|
+
|
|
141
|
+
## APX
|
|
142
|
+
|
|
143
|
+
Read `.apc/project.json` if present. It may contain an `apx` field:
|
|
144
|
+
|
|
145
|
+
- `"installed"`: APX is available; use `apx` commands when useful.
|
|
146
|
+
- `"declined"`: user chose not to install; do not suggest or run APX.
|
|
147
|
+
- missing or `null`: unknown; do not assume APX is available.
|
|
148
|
+
|
|
149
|
+
If APX is installed, it may manage runtime state outside the repository:
|
|
150
|
+
|
|
151
|
+
```text
|
|
152
|
+
~/.apx/projects/<project-id>/
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
APX can provide a local daemon, MCP management, Telegram bridge, routines, and runtime dispatch
|
|
156
|
+
across Codex, Claude Code, OpenCode, Aider, or direct LLM engines. Those are APX runtime features,
|
|
157
|
+
not APC portable-core requirements.
|
|
158
|
+
|
|
159
|
+
Never use APX to write secrets or raw sessions into `.apc/`.
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export function isShortConfirmation(text) {
|
|
2
|
-
return /^(yes|y|si|si dale|dale|ok|okay|confirm|confirmed|go|proceed|do it)\b/i
|
|
3
|
-
.test(String(text || "").trim());
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export function lastAssistantAskedForConfirmation(messages) {
|
|
7
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
8
|
-
if (messages[i]?.role !== "assistant") continue;
|
|
9
|
-
return /\b(confirm|confirmation|ok|okay|permission|allowed|proceed|do it|dale)\b/i.test(messages[i].content || "");
|
|
10
|
-
}
|
|
11
|
-
return false;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function isGhostResponse(text) {
|
|
15
|
-
const t = String(text || "").trim();
|
|
16
|
-
if (t.length > 200) return false;
|
|
17
|
-
return /^(ok|okay|got it|understood|sure|of course|on it|dale|entendido|claro|voy|ya lo hago|dame un (segundo|momento)|un momento|let me|i (will|can|shall)|i'm (going|about)|give me a|ahora lo|enseguida|checking|looking|fetching|working on|stand by|please wait|un seg|dame sec)[\s.,!]*/i
|
|
18
|
-
.test(t);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function looksLikeActionRequest(text) {
|
|
22
|
-
const t = String(text || "").trim().toLowerCase();
|
|
23
|
-
return /\b(list|show|find|get|fetch|search|run|execute|create|add|make|start|stop|delete|update|send|check|read|write|look|tell me|dame|mostra|busca|ejecuta|crea|agrega|mandá|revisá|corré|borrá|arrancá)\b/.test(t);
|
|
24
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# Channel context
|
|
2
|
-
Channel: **terminal** (interactive APX sys session) — the same OpenCode-style coding surface as the web Code module, just in the terminal. You can read, search, edit files and run shell commands.
|
|
3
|
-
|
|
4
|
-
- CWD: {{cwd}}
|
|
5
|
-
- References to "this directory", "this project", "here", "current folder" mean the CWD above — use it as the path argument; do not ask for a path
|
|
6
|
-
|
|
7
|
-
Working style — KEEP GOING UNTIL THE TASK IS DONE (build mode):
|
|
8
|
-
- You are an autonomous coding agent. Once the user gives a task, complete the WHOLE thing in this turn: chain as many tool calls as needed (read → edit → run → verify), do not stop after one or two steps.
|
|
9
|
-
- NEVER stop to ask "do you want me to…?" / "¿confirmás…?" / "should I continue?". You already have permission on this surface — just do it. Only ask if the task is truly ambiguous and you genuinely cannot proceed.
|
|
10
|
-
- NEVER announce an action and then end your turn ("now I'll edit the file." → stop). If you say you will do something, immediately call the tool and actually do it in the same turn.
|
|
11
|
-
- After each tool result, decide the next concrete step and take it. Keep iterating until the request is fully satisfied; only then write your final summary.
|
|
12
|
-
- If something fails, read the error, fix it, and retry — don't hand the problem back to the user.
|
|
13
|
-
|
|
14
|
-
Formatting:
|
|
15
|
-
- Markdown OK; keep readable; use code diffs when editing.
|
|
16
|
-
- Lead with the result; keep prose tight. Don't re-paste full tool output the user can already see.
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
// Helpers that wrap external runtimes (Claude Code, Codex, OpenCode, Aider,
|
|
2
|
-
// Cursor Agent, Gemini CLI, Qwen Code)
|
|
3
|
-
// with APC awareness:
|
|
4
|
-
//
|
|
5
|
-
// 1. Create an APX runtime session BEFORE the runtime starts.
|
|
6
|
-
// 2. Inject an "APC Runtime Context" block into the system prompt so the
|
|
7
|
-
// runtime knows the session id, the cwd of the project, and the apx
|
|
8
|
-
// commands it can use to update memory / append session notes.
|
|
9
|
-
// 3. After the runtime returns, capture the external transcript path
|
|
10
|
-
// (Claude Code gives one; most other runtimes don't yet) and write it
|
|
11
|
-
// into the APX session frontmatter.
|
|
12
|
-
// 4. Close the session with a synthesised result (truncated stdout).
|
|
13
|
-
//
|
|
14
|
-
// Used by both POST /projects/:pid/agents/:slug/runtime (CLI) and the
|
|
15
|
-
// super-agent's call_runtime tool.
|
|
16
|
-
|
|
17
|
-
import fs from "node:fs";
|
|
18
|
-
import path from "node:path";
|
|
19
|
-
import { generateSessionId } from "../../core/session-store.js";
|
|
20
|
-
|
|
21
|
-
const nowIso = () => new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
22
|
-
|
|
23
|
-
const APC_RUNTIME_HINT = `
|
|
24
|
-
# APC Runtime Context
|
|
25
|
-
|
|
26
|
-
You are running inside an APC (Agent Project Context) project. APC gives you portable project context. APX gives you local runtime session state.
|
|
27
|
-
|
|
28
|
-
- **Project**: {{name}} ({{path}})
|
|
29
|
-
- **Agent**: {{agent}}
|
|
30
|
-
- **APC session id**: {{session_id}}
|
|
31
|
-
(stored in APX local runtime storage, outside .apc/)
|
|
32
|
-
|
|
33
|
-
## Commands you can use during this run
|
|
34
|
-
|
|
35
|
-
- \`apx memory {{agent}} --append "<note>"\` save a long-term fact for this agent
|
|
36
|
-
- \`apx session update {{session_id}} --status "..."\` update the session status
|
|
37
|
-
- \`apx session update {{session_id}} --task-ref TASK-...\` link to an external task
|
|
38
|
-
|
|
39
|
-
## When you finish
|
|
40
|
-
|
|
41
|
-
Close the session with a one-line result so a future operator (or apx session resume) can summarize:
|
|
42
|
-
|
|
43
|
-
apx session close {{session_id}} --result "<one-line summary of what you did>"
|
|
44
|
-
|
|
45
|
-
If you cannot run apx (sandboxed shell), just print the result on the last line of your output prefixed with "APC_RESULT:" and APX will capture it automatically.
|
|
46
|
-
`.trim();
|
|
47
|
-
|
|
48
|
-
export function buildApfHint({ projectName, projectPath, agentSlug, sessionId }) {
|
|
49
|
-
return APC_RUNTIME_HINT
|
|
50
|
-
.replace(/\{\{name\}\}/g, projectName)
|
|
51
|
-
.replace(/\{\{path\}\}/g, projectPath)
|
|
52
|
-
.replace(/\{\{agent\}\}/g, agentSlug)
|
|
53
|
-
.replace(/\{\{session_id\}\}/g, sessionId);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Create the APX runtime session file on disk. Returns { id, filename, path }.
|
|
57
|
-
export function createRuntimeSession({ projectRoot, storageRoot = projectRoot, agentSlug, runtime, taskRef = "", title }) {
|
|
58
|
-
const dir = path.join(storageRoot, "agents", agentSlug, "sessions");
|
|
59
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
60
|
-
const id = generateSessionId(storageRoot, agentSlug);
|
|
61
|
-
const file = path.join(dir, `${id}.md`);
|
|
62
|
-
const started = nowIso();
|
|
63
|
-
const sessionTitle = title || `Runtime: ${runtime}`;
|
|
64
|
-
const body =
|
|
65
|
-
`---\n` +
|
|
66
|
-
`id: ${id}\n` +
|
|
67
|
-
`agent: ${agentSlug}\n` +
|
|
68
|
-
`title: ${sessionTitle}\n` +
|
|
69
|
-
`task_ref: ${taskRef}\n` +
|
|
70
|
-
`status: 🔄 In progress\n` +
|
|
71
|
-
`started: ${started}\n` +
|
|
72
|
-
`completed: \n` +
|
|
73
|
-
`result: \n` +
|
|
74
|
-
`runtime: ${runtime}\n` +
|
|
75
|
-
`external_session_path: \n` +
|
|
76
|
-
`---\n\n` +
|
|
77
|
-
`# ${sessionTitle}\n\n`;
|
|
78
|
-
fs.writeFileSync(file, body);
|
|
79
|
-
return { id, filename: `${id}.md`, path: file };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Update session frontmatter with the external transcript path captured from
|
|
83
|
-
// the runtime adapter. Closes the session with a result string.
|
|
84
|
-
export function closeRuntimeSession({ filePath, externalSessionPath, exitCode, result }) {
|
|
85
|
-
let text = fs.readFileSync(filePath, "utf8");
|
|
86
|
-
text = setField(text, "completed", nowIso());
|
|
87
|
-
if (externalSessionPath) {
|
|
88
|
-
text = setField(text, "external_session_path", externalSessionPath);
|
|
89
|
-
}
|
|
90
|
-
if (typeof exitCode === "number") {
|
|
91
|
-
text = setField(text, "result", `${exitCode === 0 ? "✅" : "⚠️"} exit ${exitCode}: ${(result || "").slice(0, 200)}`);
|
|
92
|
-
} else if (result) {
|
|
93
|
-
text = setField(text, "result", result.slice(0, 300));
|
|
94
|
-
}
|
|
95
|
-
text = setField(text, "status", exitCode === 0 ? "✅ Completed" : "⚠️ Closed with error");
|
|
96
|
-
fs.writeFileSync(filePath, text);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function setField(text, field, value) {
|
|
100
|
-
if (!text.startsWith("---\n")) return text;
|
|
101
|
-
const end = text.indexOf("\n---", 4);
|
|
102
|
-
if (end === -1) return text;
|
|
103
|
-
const fmText = text.slice(4, end);
|
|
104
|
-
const lines = fmText.split("\n");
|
|
105
|
-
let found = false;
|
|
106
|
-
const out = lines.map((line) => {
|
|
107
|
-
if (line.startsWith(`${field}:`)) {
|
|
108
|
-
found = true;
|
|
109
|
-
return `${field}: ${value}`;
|
|
110
|
-
}
|
|
111
|
-
return line;
|
|
112
|
-
});
|
|
113
|
-
if (!found) out.push(`${field}: ${value}`);
|
|
114
|
-
return `---\n${out.join("\n")}\n---${text.slice(end + 4)}`;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Look at the runtime's stdout for a self-reported "APC_RESULT: ..." line
|
|
118
|
-
// (the convention printed in the hint above). Returns the captured string or
|
|
119
|
-
// null. This is the fallback for runtimes that can't shell out.
|
|
120
|
-
export function extractApfResult(stdout) {
|
|
121
|
-
if (!stdout || typeof stdout !== "string") return null;
|
|
122
|
-
const m = stdout.match(/^APC_RESULT:\s*(.+?)\s*$/m);
|
|
123
|
-
return m ? m[1].trim() : null;
|
|
124
|
-
}
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { agentSkills, buildAgentSystem as buildCoreAgentSystem } from "../../../core/agent-system.js";
|
|
3
|
-
import { buildConfirmDescription } from "../../../core/confirmation/index.js";
|
|
4
|
-
|
|
5
|
-
export function projectMeta(projects, entry) {
|
|
6
|
-
const meta = projects.list().find((p) => p.id === entry.id);
|
|
7
|
-
return {
|
|
8
|
-
id: entry.id,
|
|
9
|
-
name: meta?.name || path.basename(entry.path),
|
|
10
|
-
path: entry.path,
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function resolveProject(projects, target, { allowMulti = false } = {}) {
|
|
15
|
-
if (target === undefined || target === null || target === "") {
|
|
16
|
-
if (allowMulti) return null;
|
|
17
|
-
const defaultProject = projects.get(0);
|
|
18
|
-
if (defaultProject) return defaultProject;
|
|
19
|
-
const all = projects.list();
|
|
20
|
-
if (all.length === 1) return projects.get(all[0].id);
|
|
21
|
-
throw new Error(`multiple projects registered (${all.length}); specify project=<id|name|path>`);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const tgt = String(target);
|
|
25
|
-
if (tgt.toLowerCase() === "default") {
|
|
26
|
-
const defaultProject = projects.get(0);
|
|
27
|
-
if (!defaultProject) throw new Error("default project not available");
|
|
28
|
-
return defaultProject;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (typeof target === "number" || /^\d+$/.test(tgt)) {
|
|
32
|
-
const entry = projects.get(parseInt(tgt, 10));
|
|
33
|
-
if (!entry) throw new Error(`project id ${target} not found`);
|
|
34
|
-
return entry;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const all = projects.list();
|
|
38
|
-
const byPath = all.find((p) => p.path === path.resolve(tgt));
|
|
39
|
-
if (byPath) return projects.get(byPath.id);
|
|
40
|
-
|
|
41
|
-
const byName = all.find((p) => p.name === tgt);
|
|
42
|
-
if (byName) return projects.get(byName.id);
|
|
43
|
-
|
|
44
|
-
const tgtLow = tgt.toLowerCase();
|
|
45
|
-
const fuzzy = all.filter(
|
|
46
|
-
(p) => p.name.toLowerCase().includes(tgtLow) || p.path.toLowerCase().includes(tgtLow)
|
|
47
|
-
);
|
|
48
|
-
if (fuzzy.length === 1) return projects.get(fuzzy[0].id);
|
|
49
|
-
if (fuzzy.length > 1) {
|
|
50
|
-
throw new Error(`project "${tgt}" is ambiguous; matches: ${fuzzy.map((p) => p.name).join(", ")}`);
|
|
51
|
-
}
|
|
52
|
-
throw new Error(`project "${tgt}" not found`);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export function safePathJoin(root, sub = ".") {
|
|
56
|
-
const target = path.resolve(root, sub || ".");
|
|
57
|
-
const rootResolved = path.resolve(root);
|
|
58
|
-
if (target !== rootResolved && !target.startsWith(rootResolved + path.sep)) {
|
|
59
|
-
throw new Error(`path "${sub}" escapes the project root`);
|
|
60
|
-
}
|
|
61
|
-
return target;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function skillsFromFields(fields = {}) {
|
|
65
|
-
return agentSkills({ fields });
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function agentRow(agent) {
|
|
69
|
-
return {
|
|
70
|
-
slug: agent.slug,
|
|
71
|
-
role: agent.fields.Role || null,
|
|
72
|
-
model: agent.fields.Model || null,
|
|
73
|
-
language: agent.fields.Language || null,
|
|
74
|
-
description: agent.fields.Description || null,
|
|
75
|
-
skills: skillsFromFields(agent.fields),
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export function buildAgentSystem(project, agent, opts = {}) {
|
|
80
|
-
return buildCoreAgentSystem(project, agent, opts);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export function createPermissionGuard(globalConfig = {}, {
|
|
84
|
-
implicitConfirmation = false,
|
|
85
|
-
requestConfirmation = null,
|
|
86
|
-
} = {}) {
|
|
87
|
-
const permissionMode = globalConfig.super_agent?.permission_mode || "automatico";
|
|
88
|
-
const allowedTools = new Set(globalConfig.super_agent?.allowed_tools || []);
|
|
89
|
-
|
|
90
|
-
// async so tools can `await requirePermission(...)` and the confirmation
|
|
91
|
-
// dialog resolves transparently before execution continues.
|
|
92
|
-
return async function requirePermission(tool, { dangerous = false, confirmed = false, args } = {}) {
|
|
93
|
-
const ok = confirmed || implicitConfirmation;
|
|
94
|
-
if (permissionMode === "total") return;
|
|
95
|
-
|
|
96
|
-
const blocked =
|
|
97
|
-
(permissionMode === "permiso" && !allowedTools.has(tool) && !ok) ||
|
|
98
|
-
(permissionMode === "automatico" && dangerous && !ok);
|
|
99
|
-
|
|
100
|
-
if (!blocked) return;
|
|
101
|
-
|
|
102
|
-
const description = buildConfirmDescription(tool, args || {});
|
|
103
|
-
|
|
104
|
-
if (!requestConfirmation) {
|
|
105
|
-
// No confirmation channel wired for this invocation context (e.g. routine,
|
|
106
|
-
// autonomous agent). Surface a clear message so the model can explain it.
|
|
107
|
-
throw new Error(`Action requires user confirmation: ${description}`);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const userConfirmed = await requestConfirmation(tool, args || {}, description);
|
|
111
|
-
|
|
112
|
-
if (!userConfirmed) {
|
|
113
|
-
throw new Error(`User did not confirm: ${description}`);
|
|
114
|
-
}
|
|
115
|
-
// Confirmed — fall through, tool executes normally.
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export function confirmedProperty(description) {
|
|
120
|
-
return {
|
|
121
|
-
type: "boolean",
|
|
122
|
-
description: description || "true only after explicit user confirmation for this exact action",
|
|
123
|
-
};
|
|
124
|
-
}
|