@agentprojectcontext/apx 1.31.1 → 1.32.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 +0 -1
- package/package.json +1 -1
- package/skills/apc-context/SKILL.md +0 -1
- package/src/core/agent/constants.js +5 -0
- package/src/core/agent/run-agent.js +29 -1
- package/src/core/confirmation/adapters/code.js +41 -0
- package/src/core/confirmation/adapters/telegram.js +134 -0
- package/src/core/confirmation/adapters/terminal.js +35 -0
- package/src/core/confirmation/adapters/web.js +53 -0
- package/src/core/confirmation/index.js +44 -0
- package/src/core/confirmation/pending-store.js +68 -0
- package/src/host/daemon/api/artifacts.js +117 -0
- package/src/host/daemon/api/code.js +14 -0
- package/src/host/daemon/api/confirm.js +30 -0
- package/src/host/daemon/api/super-agent.js +12 -4
- package/src/host/daemon/api.js +2 -0
- package/src/host/daemon/plugins/desktop.js +34 -0
- package/src/host/daemon/plugins/telegram-ask.js +309 -0
- package/src/host/daemon/plugins/telegram.js +358 -2
- package/src/host/daemon/super-agent-tools/helpers.js +27 -6
- package/src/host/daemon/super-agent-tools/index.js +1 -0
- package/src/host/daemon/super-agent-tools/tools/add-project.js +2 -2
- package/src/host/daemon/super-agent-tools/tools/ask-questions.js +96 -13
- package/src/host/daemon/super-agent-tools/tools/call-mcp.js +1 -1
- package/src/host/daemon/super-agent-tools/tools/call-runtime.js +1 -1
- package/src/host/daemon/super-agent-tools/tools/edit-file.js +2 -2
- package/src/host/daemon/super-agent-tools/tools/import-agent.js +2 -2
- package/src/host/daemon/super-agent-tools/tools/run-shell.js +1 -1
- package/src/host/daemon/super-agent-tools/tools/search-files.js +1 -4
- package/src/host/daemon/super-agent-tools/tools/send-telegram.js +1 -1
- package/src/host/daemon/super-agent-tools/tools/set-identity.js +2 -2
- package/src/host/daemon/super-agent-tools/tools/set-permission-mode.js +2 -2
- package/src/host/daemon/super-agent-tools/tools/write-file.js +2 -2
- package/src/host/daemon/super-agent.js +5 -1
- package/src/interfaces/cli/commands/artifact.js +99 -0
- package/src/interfaces/cli/index.js +4 -0
- package/src/interfaces/cli/terminal-chat/renderer.js +22 -2
- package/src/interfaces/web/dist/assets/index-63P_ji1a.js +571 -0
- package/src/interfaces/web/dist/assets/index-63P_ji1a.js.map +1 -0
- package/src/interfaces/web/dist/assets/index-DLWy6dYz.css +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/components/chat/AskQuestionsCard.tsx +72 -0
- package/src/interfaces/web/src/components/chat/InlineAskPanel.tsx +399 -0
- package/src/interfaces/web/src/components/chat/MessageBubble.tsx +16 -3
- package/src/interfaces/web/src/components/chat/MessageList.tsx +2 -1
- package/src/interfaces/web/src/components/code/CodeArtifactsTab.tsx +230 -0
- package/src/interfaces/web/src/components/code/CodeSidePanel.tsx +12 -4
- package/src/interfaces/web/src/i18n/en.ts +20 -0
- package/src/interfaces/web/src/i18n/es.ts +20 -0
- package/src/interfaces/web/src/lib/api/artifacts.ts +47 -0
- package/src/interfaces/web/src/lib/api.ts +1 -0
- package/src/interfaces/web/src/screens/modules/CodeScreen.tsx +23 -2
- package/src/interfaces/web/src/screens/project/ChatTab.tsx +15 -0
- package/src/interfaces/web/dist/assets/index-BDUsA6L6.css +0 -1
- package/src/interfaces/web/dist/assets/index-BV615I9p.js +0 -548
- package/src/interfaces/web/dist/assets/index-BV615I9p.js.map +0 -1
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
import { Gauge, GitCompare } from "lucide-react";
|
|
1
|
+
import { Gauge, GitCompare, Package } from "lucide-react";
|
|
2
2
|
import { Tabs, TabsList, TabsTrigger, TabsContent } from "../ui/tabs";
|
|
3
3
|
import { t } from "../../i18n";
|
|
4
4
|
import { CodeContextTab } from "./CodeContextTab";
|
|
5
5
|
import { CodeChangesTab } from "./CodeChangesTab";
|
|
6
|
+
import { CodeArtifactsTab } from "./CodeArtifactsTab";
|
|
6
7
|
import type { CodeChanges, CodeTurn } from "../../lib/api/code";
|
|
7
8
|
|
|
8
9
|
interface Props {
|
|
10
|
+
pid: string;
|
|
9
11
|
turns: CodeTurn[];
|
|
10
12
|
changes: CodeChanges | undefined;
|
|
11
13
|
changesLoading: boolean;
|
|
12
14
|
onRefreshChanges: () => void;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
// Right-hand panel: Context (token metrics
|
|
16
|
-
//
|
|
17
|
-
export function CodeSidePanel({ turns, changes, changesLoading, onRefreshChanges }: Props) {
|
|
17
|
+
// Right-hand panel: Context (token metrics), Changes (diffs vs the session's
|
|
18
|
+
// git baseline), and Artifacts (managed files under <project>/artifacts/).
|
|
19
|
+
export function CodeSidePanel({ pid, turns, changes, changesLoading, onRefreshChanges }: Props) {
|
|
18
20
|
const changeCount = changes?.files.length || 0;
|
|
19
21
|
return (
|
|
20
22
|
<Tabs defaultValue="context" className="flex h-full flex-col gap-0" data-testid="code-side-panel">
|
|
@@ -31,6 +33,9 @@ export function CodeSidePanel({ turns, changes, changesLoading, onRefreshChanges
|
|
|
31
33
|
</span>
|
|
32
34
|
)}
|
|
33
35
|
</TabsTrigger>
|
|
36
|
+
<TabsTrigger value="artifacts" className="flex-1">
|
|
37
|
+
<Package className="size-3.5" /> {t("code_module.tab_artifacts")}
|
|
38
|
+
</TabsTrigger>
|
|
34
39
|
</TabsList>
|
|
35
40
|
</div>
|
|
36
41
|
<TabsContent value="context" className="min-h-0 flex-1 overflow-y-auto">
|
|
@@ -39,6 +44,9 @@ export function CodeSidePanel({ turns, changes, changesLoading, onRefreshChanges
|
|
|
39
44
|
<TabsContent value="changes" className="min-h-0 flex-1 overflow-hidden">
|
|
40
45
|
<CodeChangesTab changes={changes} loading={changesLoading} onRefresh={onRefreshChanges} />
|
|
41
46
|
</TabsContent>
|
|
47
|
+
<TabsContent value="artifacts" className="min-h-0 flex-1 overflow-hidden">
|
|
48
|
+
<CodeArtifactsTab pid={pid} />
|
|
49
|
+
</TabsContent>
|
|
42
50
|
</Tabs>
|
|
43
51
|
);
|
|
44
52
|
}
|
|
@@ -726,6 +726,18 @@ export const en = {
|
|
|
726
726
|
message: "That route does not exist.",
|
|
727
727
|
},
|
|
728
728
|
|
|
729
|
+
ask_panel: {
|
|
730
|
+
answers_header: "Answers",
|
|
731
|
+
other: "Other",
|
|
732
|
+
other_placeholder: "Write your own answer here",
|
|
733
|
+
text_placeholder: "Type your answer…",
|
|
734
|
+
back: "Back",
|
|
735
|
+
skip: "Skip",
|
|
736
|
+
next: "Next",
|
|
737
|
+
submit: "Send",
|
|
738
|
+
status_waiting: "Waiting for your answer…",
|
|
739
|
+
status_received: "Answers received",
|
|
740
|
+
},
|
|
729
741
|
code_module: {
|
|
730
742
|
title: "Code",
|
|
731
743
|
badge: "super-agent",
|
|
@@ -747,6 +759,14 @@ export const en = {
|
|
|
747
759
|
mode_plan_hint: "Plan — read-only, proposes changes without touching files",
|
|
748
760
|
tab_context: "Context",
|
|
749
761
|
tab_changes: "Changes",
|
|
762
|
+
tab_artifacts: "Artifacts",
|
|
763
|
+
artifacts_none: "No artifacts yet. Ask the agent to create a script under `artifacts/<name>`.",
|
|
764
|
+
artifacts_count: "{n} artifact(s)",
|
|
765
|
+
artifacts_copy_path: "Copy path",
|
|
766
|
+
artifacts_run: "Run",
|
|
767
|
+
artifacts_run_hint: "Run it from your terminal:",
|
|
768
|
+
artifacts_delete: "Delete",
|
|
769
|
+
artifacts_delete_confirm: "Delete this artifact? The file will be removed from disk.",
|
|
750
770
|
ctx_model: "Model",
|
|
751
771
|
ctx_tokens: "Tokens",
|
|
752
772
|
ctx_input: "Input",
|
|
@@ -727,6 +727,18 @@ export const es = {
|
|
|
727
727
|
message: "Esa ruta no existe.",
|
|
728
728
|
},
|
|
729
729
|
|
|
730
|
+
ask_panel: {
|
|
731
|
+
answers_header: "Respuestas",
|
|
732
|
+
other: "Otro",
|
|
733
|
+
other_placeholder: "Escribí tu propia respuesta acá",
|
|
734
|
+
text_placeholder: "Escribí tu respuesta…",
|
|
735
|
+
back: "Atrás",
|
|
736
|
+
skip: "Omitir",
|
|
737
|
+
next: "Siguiente",
|
|
738
|
+
submit: "Enviar",
|
|
739
|
+
status_waiting: "Esperando respuesta…",
|
|
740
|
+
status_received: "Respuestas recibidas",
|
|
741
|
+
},
|
|
730
742
|
code_module: {
|
|
731
743
|
title: "Code",
|
|
732
744
|
badge: "super-agent",
|
|
@@ -748,6 +760,14 @@ export const es = {
|
|
|
748
760
|
mode_plan_hint: "Plan — solo lectura, propone cambios sin tocar archivos",
|
|
749
761
|
tab_context: "Contexto",
|
|
750
762
|
tab_changes: "Cambios",
|
|
763
|
+
tab_artifacts: "Artifacts",
|
|
764
|
+
artifacts_none: "Todavía no hay artifacts. Pedile al agente que cree un script en `artifacts/<nombre>`.",
|
|
765
|
+
artifacts_count: "{n} artifact(s)",
|
|
766
|
+
artifacts_copy_path: "Copiar path",
|
|
767
|
+
artifacts_run: "Run",
|
|
768
|
+
artifacts_run_hint: "Para ejecutarlo desde la terminal:",
|
|
769
|
+
artifacts_delete: "Eliminar",
|
|
770
|
+
artifacts_delete_confirm: "¿Eliminar este artifact? El archivo se borra del disco.",
|
|
751
771
|
ctx_model: "Modelo",
|
|
752
772
|
ctx_tokens: "Tokens",
|
|
753
773
|
ctx_input: "Entrada",
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { http } from "../http";
|
|
2
|
+
|
|
3
|
+
export interface ArtifactEntry {
|
|
4
|
+
name: string;
|
|
5
|
+
path: string;
|
|
6
|
+
size: number;
|
|
7
|
+
modified: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ArtifactContent {
|
|
11
|
+
name: string;
|
|
12
|
+
path: string;
|
|
13
|
+
content: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Shape of POST /projects/:pid/artifacts/:name/run. On success the daemon
|
|
17
|
+
// returns the captured stdout/stderr and exit metadata; on 4xx an error
|
|
18
|
+
// payload is thrown by the http client instead.
|
|
19
|
+
export interface ArtifactRunResult {
|
|
20
|
+
ok: boolean;
|
|
21
|
+
exitCode?: number | null;
|
|
22
|
+
signal?: string | null;
|
|
23
|
+
timedOut?: boolean;
|
|
24
|
+
truncated?: boolean;
|
|
25
|
+
stdout?: string;
|
|
26
|
+
stderr?: string;
|
|
27
|
+
durationMs?: number;
|
|
28
|
+
error?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const Artifacts = {
|
|
32
|
+
list: (pid: string) =>
|
|
33
|
+
http.get<ArtifactEntry[]>(`/projects/${encodeURIComponent(pid)}/artifacts`),
|
|
34
|
+
read: (pid: string, name: string) =>
|
|
35
|
+
http.get<ArtifactContent>(
|
|
36
|
+
`/projects/${encodeURIComponent(pid)}/artifacts/${encodeURIComponent(name)}`,
|
|
37
|
+
),
|
|
38
|
+
run: (pid: string, name: string, args: string[] = []) =>
|
|
39
|
+
http.post<ArtifactRunResult>(
|
|
40
|
+
`/projects/${encodeURIComponent(pid)}/artifacts/${encodeURIComponent(name)}/run`,
|
|
41
|
+
{ args },
|
|
42
|
+
),
|
|
43
|
+
remove: (pid: string, name: string) =>
|
|
44
|
+
http.del<void>(
|
|
45
|
+
`/projects/${encodeURIComponent(pid)}/artifacts/${encodeURIComponent(name)}`,
|
|
46
|
+
),
|
|
47
|
+
};
|
|
@@ -8,6 +8,7 @@ import { CodeProjectPicker } from "../../components/code/CodeProjectPicker";
|
|
|
8
8
|
import { CodeSessionList } from "../../components/code/CodeSessionList";
|
|
9
9
|
import { CodeComposer } from "../../components/code/CodeComposer";
|
|
10
10
|
import { CodeSidePanel } from "../../components/code/CodeSidePanel";
|
|
11
|
+
import { InlineAskPanel, pendingAskQuestions } from "../../components/chat/InlineAskPanel";
|
|
11
12
|
import { useToast } from "../../components/Toast";
|
|
12
13
|
import { t } from "../../i18n";
|
|
13
14
|
import { applyStreamEvent, textOf, type ChatMsg } from "../../hooks/useChat";
|
|
@@ -151,8 +152,8 @@ export function CodeScreen() {
|
|
|
151
152
|
return copy;
|
|
152
153
|
});
|
|
153
154
|
|
|
154
|
-
const send = async () => {
|
|
155
|
-
const prompt = draft.trim();
|
|
155
|
+
const send = async (overridePrompt?: string) => {
|
|
156
|
+
const prompt = (overridePrompt ?? draft).trim();
|
|
156
157
|
if (!prompt || busy || !pid || !sid) return;
|
|
157
158
|
const now = new Date().toISOString();
|
|
158
159
|
setMsgs((curr) => [
|
|
@@ -209,6 +210,16 @@ export function CodeScreen() {
|
|
|
209
210
|
const hasProjects = !projects.isLoading && projectList.length > 0;
|
|
210
211
|
const turns: CodeTurn[] = useMemo(() => msgs as unknown as CodeTurn[], [msgs]);
|
|
211
212
|
|
|
213
|
+
// Detect unanswered ask_questions in the last assistant turn. Local "dismissed"
|
|
214
|
+
// ref keys off the turn id so the panel re-appears for a fresh batch.
|
|
215
|
+
const [dismissedKey, setDismissedKey] = useState<string | null>(null);
|
|
216
|
+
const pending = !busy ? pendingAskQuestions(msgs) : null;
|
|
217
|
+
const askVisible = pending && pending.turnKey !== dismissedKey;
|
|
218
|
+
|
|
219
|
+
const submitAnswers = (compiled: string) => {
|
|
220
|
+
void send(compiled);
|
|
221
|
+
};
|
|
222
|
+
|
|
212
223
|
return (
|
|
213
224
|
<div className="flex h-full min-h-0 flex-col overflow-hidden p-4" data-testid="screen-code">
|
|
214
225
|
<header className="mb-3 flex items-center justify-between gap-3">
|
|
@@ -263,6 +274,15 @@ export function CodeScreen() {
|
|
|
263
274
|
</div>
|
|
264
275
|
)}
|
|
265
276
|
</div>
|
|
277
|
+
{askVisible && pending && (
|
|
278
|
+
<InlineAskPanel
|
|
279
|
+
turnKey={pending.turnKey}
|
|
280
|
+
questions={pending.questions}
|
|
281
|
+
onSubmit={submitAnswers}
|
|
282
|
+
onDismiss={() => setDismissedKey(pending.turnKey)}
|
|
283
|
+
disabled={busy}
|
|
284
|
+
/>
|
|
285
|
+
)}
|
|
266
286
|
<div className="border-t border-border bg-card/60 p-3" data-testid="code-input">
|
|
267
287
|
<CodeComposer
|
|
268
288
|
value={draft}
|
|
@@ -282,6 +302,7 @@ export function CodeScreen() {
|
|
|
282
302
|
{/* Right: context + changes */}
|
|
283
303
|
<aside className="hidden w-80 shrink-0 flex-col border-l border-border lg:flex">
|
|
284
304
|
<CodeSidePanel
|
|
305
|
+
pid={pid}
|
|
285
306
|
turns={turns}
|
|
286
307
|
changes={changes.data}
|
|
287
308
|
changesLoading={changes.isLoading}
|
|
@@ -8,6 +8,7 @@ import { UiSelect } from "../../components/UiSelect";
|
|
|
8
8
|
import { Composer } from "../../components/chat/Composer";
|
|
9
9
|
import { MessageList } from "../../components/chat/MessageList";
|
|
10
10
|
import { ContextBar } from "../../components/chat/ContextBar";
|
|
11
|
+
import { InlineAskPanel, pendingAskQuestions } from "../../components/chat/InlineAskPanel";
|
|
11
12
|
import { useChat } from "../../hooks/useChat";
|
|
12
13
|
import { useToast } from "../../components/Toast";
|
|
13
14
|
import { t } from "../../i18n";
|
|
@@ -25,6 +26,7 @@ export function ChatTab({ pid }: { pid: string }) {
|
|
|
25
26
|
const [activeSlug, setActiveSlug] = useState(params.get("agent") || "");
|
|
26
27
|
const [creating, setCreating] = useState(false);
|
|
27
28
|
const [model, setModel] = useState("");
|
|
29
|
+
const [dismissedAskKey, setDismissedAskKey] = useState<string | null>(null);
|
|
28
30
|
const { msgs, send: sendChat, stop, clear, streaming } = useChat(pid, (m) => toast.error(m));
|
|
29
31
|
|
|
30
32
|
const agentList = agents.data || [];
|
|
@@ -117,6 +119,19 @@ export function ChatTab({ pid }: { pid: string }) {
|
|
|
117
119
|
)}
|
|
118
120
|
</div>
|
|
119
121
|
<ContextBar msgs={msgs} />
|
|
122
|
+
{(() => {
|
|
123
|
+
const pending = !streaming ? pendingAskQuestions(msgs) : null;
|
|
124
|
+
if (!pending || pending.turnKey === dismissedAskKey) return null;
|
|
125
|
+
return (
|
|
126
|
+
<InlineAskPanel
|
|
127
|
+
turnKey={pending.turnKey}
|
|
128
|
+
questions={pending.questions}
|
|
129
|
+
onSubmit={(compiled) => void send(compiled)}
|
|
130
|
+
onDismiss={() => setDismissedAskKey(pending.turnKey)}
|
|
131
|
+
disabled={streaming}
|
|
132
|
+
/>
|
|
133
|
+
);
|
|
134
|
+
})()}
|
|
120
135
|
<Composer
|
|
121
136
|
onSend={send}
|
|
122
137
|
onStop={stop}
|