@agentprojectcontext/apx 1.55.2 → 1.56.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,8 +18,8 @@
18
18
  <link rel="apple-touch-icon" href="/favicon/dark/apple-touch-icon.png" media="(prefers-color-scheme: dark)" />
19
19
  <link rel="manifest" href="/favicon/white/site.webmanifest" media="(prefers-color-scheme: light)" />
20
20
  <link rel="manifest" href="/favicon/dark/site.webmanifest" media="(prefers-color-scheme: dark)" />
21
- <script type="module" crossorigin src="/assets/index-p33JHkov.js"></script>
22
- <link rel="stylesheet" crossorigin href="/assets/index-BwnMDZaD.css">
21
+ <script type="module" crossorigin src="/assets/index-B34JqOED.js"></script>
22
+ <link rel="stylesheet" crossorigin href="/assets/index-CAUezTBY.css">
23
23
  </head>
24
24
  <body class="bg-background text-foreground antialiased">
25
25
  <div id="root"></div>
@@ -1259,9 +1259,9 @@
1259
1259
  }
1260
1260
  },
1261
1261
  "node_modules/@reduxjs/toolkit/node_modules/immer": {
1262
- "version": "11.1.9",
1263
- "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.9.tgz",
1264
- "integrity": "sha512-sc/z0Cyti70bZa0ZU4sWfAElfovFb9Ni8tArJZLuklYWxegPiK3pDOql1Rq5H0FIRAW9LSQRG6OX4KqBldbhBA==",
1262
+ "version": "11.1.11",
1263
+ "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.11.tgz",
1264
+ "integrity": "sha512-qzXuyXAkPySAGYkfsAwodDPWT8Zm7/Uo5BNt4BjhMhG5WlWyZZ4wQqnWwdS8kjlQ1Cwu6gjw3A6+0gTQwlyYtw==",
1265
1265
  "license": "MIT",
1266
1266
  "funding": {
1267
1267
  "type": "opencollective",
@@ -3488,9 +3488,9 @@
3488
3488
  }
3489
3489
  },
3490
3490
  "node_modules/react-resizable-panels": {
3491
- "version": "4.12.0",
3492
- "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-4.12.0.tgz",
3493
- "integrity": "sha512-t/Gp57qSCxGQ52ckhz+8lM7dnuymeU95TEzl2U203qEbGkSLHrtm7US2/ANzq/zOlja3CwPTAfCDuh1unv9mfw==",
3491
+ "version": "4.12.1",
3492
+ "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-4.12.1.tgz",
3493
+ "integrity": "sha512-ElE/UpOvMLRWtAqbCgyizHXcbws8RPMyN3cBqmdY17Nxr5f01+DEwzOLqhgcy68GSnjtIUFgKWKl8aIgx5aypQ==",
3494
3494
  "license": "MIT",
3495
3495
  "peerDependencies": {
3496
3496
  "react": "^18.0.0 || ^19.0.0",
@@ -235,6 +235,7 @@ function projectLabel(key?: string) {
235
235
  case "routines": return t("project.nav.routines");
236
236
  case "tasks": return t("project.nav.tasks");
237
237
  case "mcps": return t("project.nav.mcps");
238
+ case "artifacts": return t("project.nav.artifacts");
238
239
  case "config": return t("project.nav.config");
239
240
  case "workspaces": return t("base.workspaces_title");
240
241
  case "models": return t("settings.tabs.engines");
@@ -197,27 +197,36 @@ function ArtifactRow({
197
197
  </DialogContent>
198
198
  </Dialog>
199
199
 
200
- {/* Editar — opens as a file tab in the main panel */}
201
- <Tip content={t("code_module.artifacts_edit")}>
202
- <button
203
- type="button"
204
- onClick={() => onEditArtifact?.(entry.name)}
205
- className="inline-flex items-center gap-1 rounded px-1.5 py-1 text-[10px] font-medium bg-violet-500/15 text-violet-700 hover:bg-violet-500/25 dark:text-violet-300"
206
- >
207
- <SquarePen className="size-3" />
208
- {t("modules_ui.code_artifact_edit_short")}
209
- </button>
210
- </Tip>
200
+ {/* Editar — opens as a file tab in the main panel. Only available when
201
+ a host editor (the Code screen) is wired in. */}
202
+ {onEditArtifact && (
203
+ <Tip content={t("code_module.artifacts_edit")}>
204
+ <button
205
+ type="button"
206
+ onClick={() => onEditArtifact(entry.name)}
207
+ className="inline-flex items-center gap-1 rounded px-1.5 py-1 text-[10px] font-medium bg-violet-500/15 text-violet-700 hover:bg-violet-500/25 dark:text-violet-300"
208
+ >
209
+ <SquarePen className="size-3" />
210
+ {t("modules_ui.code_artifact_edit_short")}
211
+ </button>
212
+ </Tip>
213
+ )}
211
214
 
212
- {/* Run button */}
215
+ {/* Run button — hand off to the terminal when there is one (Code
216
+ screen), otherwise execute in place and show the captured output. */}
213
217
  {looksRunnable && (
214
218
  <Tip content={t("code_module.artifacts_run")}>
215
219
  <button
216
220
  type="button"
217
- onClick={() => onRunInTerminal?.(`apx artifact run ${entry.name}`)}
218
- className="inline-flex items-center gap-1 rounded px-1.5 py-1 text-[10px] font-medium bg-emerald-500/15 text-emerald-700 hover:bg-emerald-500/25 dark:text-emerald-300"
221
+ disabled={running}
222
+ onClick={() =>
223
+ onRunInTerminal
224
+ ? onRunInTerminal(`apx artifact run ${entry.name}`)
225
+ : void run()
226
+ }
227
+ className="inline-flex items-center gap-1 rounded px-1.5 py-1 text-[10px] font-medium bg-emerald-500/15 text-emerald-700 hover:bg-emerald-500/25 disabled:opacity-60 dark:text-emerald-300"
219
228
  >
220
- <Play className="size-3" />
229
+ {running ? <Spinner size={10} /> : <Play className="size-3" />}
221
230
  {t("code_module.artifacts_run")}
222
231
  </button>
223
232
  </Tip>
@@ -288,6 +288,7 @@ export const en = {
288
288
  routines: "Routines",
289
289
  tasks: "Tasks",
290
290
  mcps: "MCPs",
291
+ artifacts: "Artifacts",
291
292
  vars: "Variables",
292
293
  logs: "Logs",
293
294
  memories: "Memories",
@@ -305,10 +306,16 @@ export const en = {
305
306
  routines: "Routines",
306
307
  agents: "Agents",
307
308
  mcps: "MCPs",
309
+ artifacts: "Artifacts",
308
310
  chat: "Chat (super-agent)",
309
311
  chat_value: "open",
310
312
  },
311
313
 
314
+ artifacts: {
315
+ title: "Artifacts",
316
+ subtitle: "Reusable scripts and files stored under the project. Agents create them; you can view, run, rename or delete them.",
317
+ },
318
+
312
319
  chat: {
313
320
  title: "Chat with agent",
314
321
  subtitle: "Direct conversations with project agents. The super-agent does not intervene.",
@@ -289,6 +289,7 @@ export const es = {
289
289
  routines: "Rutinas",
290
290
  tasks: "Tasks",
291
291
  mcps: "MCPs",
292
+ artifacts: "Artifacts",
292
293
  vars: "Variables",
293
294
  logs: "Logs",
294
295
  memories: "Memorias",
@@ -306,10 +307,16 @@ export const es = {
306
307
  routines: "Rutinas",
307
308
  agents: "Agents",
308
309
  mcps: "MCPs",
310
+ artifacts: "Artifacts",
309
311
  chat: "Chat (super-agent)",
310
312
  chat_value: "abrir",
311
313
  },
312
314
 
315
+ artifacts: {
316
+ title: "Artifacts",
317
+ subtitle: "Scripts y archivos reutilizables guardados en el proyecto. Los crean los agentes; podés verlos, ejecutarlos, renombrarlos o eliminarlos.",
318
+ },
319
+
313
320
  chat: {
314
321
  title: "Chat con agente",
315
322
  subtitle: "Chat directo con el agente del proyecto.",
@@ -3,7 +3,7 @@ import { useParams, Routes, Route, Navigate, useLocation, useNavigate } from "re
3
3
  import {
4
4
  Bot, Heart, Zap, Puzzle, FolderKanban, Settings,
5
5
  MessagesSquare, Send, KeyRound,
6
- LayoutDashboard, Boxes, Cpu, ScrollText, History, Brain,
6
+ LayoutDashboard, Boxes, Cpu, ScrollText, History, Brain, FileCode2,
7
7
  } from "lucide-react";
8
8
  import { useNavCollapse, type TabSection } from "../components/common/TabNav";
9
9
  import { TabLayout } from "../components/common/TabLayout";
@@ -28,11 +28,12 @@ import { VarsTab } from "./project/VarsTab";
28
28
  import { ChatTab } from "./project/ChatTab";
29
29
  import { TelegramTab } from "./project/TelegramTab";
30
30
  import { MemoriesTab } from "./project/MemoriesTab";
31
+ import { ArtifactsTab } from "./project/ArtifactsTab";
31
32
  import { AgentDetailScreen } from "./project/AgentDetailScreen";
32
33
 
33
34
  type NavKey =
34
35
  | "" | "chat" | "config" | "telegram"
35
- | "agents" | "routines" | "tasks" | "mcps" | "vars" | "logs" | "memories";
36
+ | "agents" | "routines" | "tasks" | "mcps" | "vars" | "logs" | "memories" | "artifacts";
36
37
 
37
38
  export function ProjectScreen() {
38
39
  const navigate = useNavigate();
@@ -69,10 +70,11 @@ export function ProjectScreen() {
69
70
  items: [
70
71
  { key: "agents", label: t("project.nav.agents"), icon: Bot },
71
72
  { key: "memories", label: t("project.nav.memories"), icon: Brain },
72
- { key: "routines", label: t("project.nav.routines"), icon: Heart },
73
- { key: "mcps", label: t("project.nav.mcps"), icon: Puzzle },
74
- { key: "vars", label: t("project.nav.vars"), icon: KeyRound },
75
- { key: "config", label: t("project.nav.config"), icon: Settings },
73
+ { key: "routines", label: t("project.nav.routines"), icon: Heart },
74
+ { key: "mcps", label: t("project.nav.mcps"), icon: Puzzle },
75
+ { key: "artifacts", label: t("project.nav.artifacts"), icon: FileCode2 },
76
+ { key: "vars", label: t("project.nav.vars"), icon: KeyRound },
77
+ { key: "config", label: t("project.nav.config"), icon: Settings },
76
78
  ],
77
79
  },
78
80
  ];
@@ -91,11 +93,12 @@ export function ProjectScreen() {
91
93
  {
92
94
  title: t("project.sections.automation"),
93
95
  items: [
94
- { key: "routines", label: t("project.nav.routines"), icon: Heart },
95
- { key: "tasks", label: t("project.nav.tasks"), icon: Zap },
96
- { key: "mcps", label: t("project.nav.mcps"), icon: Puzzle },
97
- { key: "vars", label: t("project.nav.vars"), icon: KeyRound },
98
- { key: "logs", label: t("project.nav.logs"), icon: ScrollText },
96
+ { key: "routines", label: t("project.nav.routines"), icon: Heart },
97
+ { key: "tasks", label: t("project.nav.tasks"), icon: Zap },
98
+ { key: "mcps", label: t("project.nav.mcps"), icon: Puzzle },
99
+ { key: "artifacts", label: t("project.nav.artifacts"), icon: FileCode2 },
100
+ { key: "vars", label: t("project.nav.vars"), icon: KeyRound },
101
+ { key: "logs", label: t("project.nav.logs"), icon: ScrollText },
99
102
  ],
100
103
  },
101
104
  {
@@ -156,6 +159,7 @@ export function ProjectScreen() {
156
159
  <Route path="routines" element={<RoutinesTab pid={pid} />} />
157
160
  <Route path="tasks" element={isBase ? <GlobalTasksTab /> : <TasksTab pid={pid} />} />
158
161
  <Route path="mcps" element={<McpsTab pid={pid} />} />
162
+ <Route path="artifacts" element={<ArtifactsTab pid={pid} />} />
159
163
  <Route path="vars" element={<VarsTab pid={pid} />} />
160
164
  <Route path="threads" element={<Navigate to={`/p/${pid}/chat`} replace />} />
161
165
  <Route path="chat" element={<ChatTab pid={pid} />} />
@@ -1,4 +1,5 @@
1
1
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2
+ import { useSearchParams } from "react-router-dom";
2
3
  import useSWR from "swr";
3
4
  import { Bot, FolderTree, MessageSquare, PanelLeft, PanelRight, Terminal, X } from "lucide-react";
4
5
  import { Group as PanelGroup, Panel, Separator as PanelResizeHandle } from "react-resizable-panels";
@@ -64,6 +65,8 @@ export function CodeScreen() {
64
65
  const [termInitCmd, setTermInitCmd] = useState("");
65
66
  const [worktreeOpen, setWorktreeOpen] = useState(false);
66
67
  const abortRef = useRef<AbortController | null>(null);
68
+ const [searchParams, setSearchParams] = useSearchParams();
69
+ const deepLinkDone = useRef(false);
67
70
 
68
71
  // Open file tabs. `artifactName` marks an artifact opened for editing;
69
72
  // saves route through Artifacts.write instead of being read-only.
@@ -346,6 +349,27 @@ export function CodeScreen() {
346
349
  [pid],
347
350
  );
348
351
 
352
+ // Deep-link from the project Artifacts tab (/m/code?pid=..&cmd=.. or &edit=..).
353
+ // Select the requested project, then prefill the terminal with the artifact
354
+ // command (so args like a URL can be typed) or open the file for editing.
355
+ useEffect(() => {
356
+ if (deepLinkDone.current) return;
357
+ const wantPid = searchParams.get("pid");
358
+ const cmd = searchParams.get("cmd");
359
+ const edit = searchParams.get("edit");
360
+ if (!wantPid || (!cmd && !edit)) return;
361
+ // Wait until the requested project is active so the command/edit targets it.
362
+ if (String(pid) !== String(wantPid)) {
363
+ setPid(String(wantPid));
364
+ return;
365
+ }
366
+ deepLinkDone.current = true;
367
+ if (edit) openArtifact(edit);
368
+ if (cmd) runInTerminal(cmd.endsWith(" ") ? cmd : cmd + " ");
369
+ // Clear params so a refresh/back doesn't retrigger the handoff.
370
+ setSearchParams({}, { replace: true });
371
+ }, [searchParams, pid, openArtifact, runInTerminal, setSearchParams]);
372
+
349
373
  const saveOpenFile = useCallback(
350
374
  async (path: string, content: string) => {
351
375
  const file = openFiles.find((f) => f.path === path);
@@ -0,0 +1,32 @@
1
+ import { useNavigate } from "react-router-dom";
2
+ import { Section } from "../../components/Section";
3
+ import { CodeArtifactsTab } from "../../components/code/CodeArtifactsTab";
4
+ import { t } from "../../i18n";
5
+
6
+ // Project-level view of the artifacts stored under <project>/artifacts/. Reuses
7
+ // the same list/row UI as the Code screen. Run and Edit hand off to the Code
8
+ // module — the terminal there lets you pass args (e.g. a URL) and the file
9
+ // editor lets you edit — instead of running headless in place.
10
+ export function ArtifactsTab({ pid }: { pid: string }) {
11
+ const navigate = useNavigate();
12
+
13
+ const toCode = (params: Record<string, string>) => {
14
+ const qs = new URLSearchParams({ pid, ...params }).toString();
15
+ navigate(`/m/code?${qs}`);
16
+ };
17
+
18
+ return (
19
+ <Section
20
+ title={t("project.artifacts.title")}
21
+ description={t("project.artifacts.subtitle")}
22
+ fullHeight
23
+ className="min-h-[24rem]"
24
+ >
25
+ <CodeArtifactsTab
26
+ pid={pid}
27
+ onRunInTerminal={(cmd) => toCode({ cmd })}
28
+ onEditArtifact={(name) => toCode({ edit: name })}
29
+ />
30
+ </Section>
31
+ );
32
+ }
@@ -1,7 +1,7 @@
1
1
  import useSWR from "swr";
2
2
  import { NavLink } from "react-router-dom";
3
- import { Bot, Heart, MessagesSquare, Puzzle, Zap } from "lucide-react";
4
- import { Agents, Mcps, Routines, Tasks } from "../../lib/api";
3
+ import { Bot, FileCode2, Heart, MessagesSquare, Puzzle, Zap } from "lucide-react";
4
+ import { Agents, Artifacts, Mcps, Routines, Tasks } from "../../lib/api";
5
5
  import { t } from "../../i18n";
6
6
 
7
7
  export function Overview({ pid }: { pid: string }) {
@@ -9,12 +9,14 @@ export function Overview({ pid }: { pid: string }) {
9
9
  const routines = useSWR(`/projects/${pid}/routines`, () => Routines.list(pid));
10
10
  const agents = useSWR(`/projects/${pid}/agents`, () => Agents.list(pid));
11
11
  const mcps = useSWR(`/projects/${pid}/mcps`, () => Mcps.list(pid));
12
+ const artifacts = useSWR(`/projects/${pid}/artifacts`, () => Artifacts.list(pid));
12
13
  return (
13
14
  <div className="grid grid-cols-2 gap-4 md:grid-cols-3">
14
15
  <Card title={t("project.overview.tasks_open")} value={tasks.data?.length ?? "…"} href={`/p/${pid}/tasks`} icon={Zap} />
15
16
  <Card title={t("project.overview.routines")} value={routines.data?.length ?? "…"} href={`/p/${pid}/routines`} icon={Heart} />
16
17
  <Card title={t("project.overview.agents")} value={agents.data?.length ?? "…"} href={`/p/${pid}/agents`} icon={Bot} />
17
18
  <Card title={t("project.overview.mcps")} value={mcps.data?.length ?? "…"} href={`/p/${pid}/mcps`} icon={Puzzle} />
19
+ <Card title={t("project.overview.artifacts")} value={artifacts.data?.length ?? "…"} href={`/p/${pid}/artifacts`} icon={FileCode2} />
18
20
  <Card title={t("project.overview.chat")} value={t("project.overview.chat_value")} href={`/p/${pid}/chat`} icon={MessagesSquare} />
19
21
  </div>
20
22
  );