@agentprojectcontext/apx 1.59.0 → 1.60.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.
Files changed (30) hide show
  1. package/package.json +1 -1
  2. package/src/core/agent/tools/handlers/_asana.js +34 -0
  3. package/src/core/agent/tools/handlers/asana-create-task.js +38 -0
  4. package/src/core/agent/tools/handlers/asana-list-projects.js +19 -0
  5. package/src/core/agent/tools/handlers/asana-list-tasks.js +27 -0
  6. package/src/core/agent/tools/handlers/asana-update-task.js +32 -0
  7. package/src/core/agent/tools/names.js +10 -0
  8. package/src/core/agent/tools/registry.js +11 -0
  9. package/src/core/integrations/catalog.js +66 -0
  10. package/src/core/integrations/index.js +10 -0
  11. package/src/core/integrations/plugins/asana.js +231 -0
  12. package/src/core/integrations/sources.js +56 -0
  13. package/src/core/integrations/store.js +118 -0
  14. package/src/core/stores/project-files.js +21 -2
  15. package/src/host/daemon/api/integrations.js +191 -0
  16. package/src/host/daemon/api.js +2 -0
  17. package/src/interfaces/web/dist/assets/{index-CnQb4N6C.js → index-DFNV6BWh.js} +193 -163
  18. package/src/interfaces/web/dist/assets/index-DFNV6BWh.js.map +1 -0
  19. package/src/interfaces/web/dist/assets/index-HU-Wt2l9.css +1 -0
  20. package/src/interfaces/web/dist/index.html +2 -2
  21. package/src/interfaces/web/src/components/integrations/AsanaPlugin.tsx +275 -0
  22. package/src/interfaces/web/src/components/integrations/ComingSoonPlugin.tsx +44 -0
  23. package/src/interfaces/web/src/components/integrations/PluginCard.tsx +61 -0
  24. package/src/interfaces/web/src/components/integrations/PluginToolsSection.tsx +39 -0
  25. package/src/interfaces/web/src/lib/api/integrations.ts +106 -0
  26. package/src/interfaces/web/src/lib/api.ts +1 -0
  27. package/src/interfaces/web/src/screens/ProjectScreen.tsx +6 -2
  28. package/src/interfaces/web/src/screens/project/IntegrationsTab.tsx +146 -0
  29. package/src/interfaces/web/dist/assets/index-CnQb4N6C.js.map +0 -1
  30. package/src/interfaces/web/dist/assets/index-Dv3X-zpx.css +0 -1
@@ -0,0 +1,146 @@
1
+ import { useState } from "react";
2
+ import useSWR from "swr";
3
+ import { Network, Puzzle, Wrench } from "lucide-react";
4
+ import { Integrations, type CatalogEntry, type IntegrationScope } from "../../lib/api";
5
+ import { cn } from "../../lib/cn";
6
+ import { Section } from "../../components/Section";
7
+ import { Empty, Loading } from "../../components/ui";
8
+ import { AsanaPlugin } from "../../components/integrations/AsanaPlugin";
9
+ import { ComingSoonPlugin } from "../../components/integrations/ComingSoonPlugin";
10
+ import { McpsTab } from "./McpsTab";
11
+
12
+ type SubTab = "plugins" | "mcp" | "tools";
13
+
14
+ const SUBTABS: { value: SubTab; label: string; icon: typeof Puzzle }[] = [
15
+ { value: "plugins", label: "Plugins", icon: Puzzle },
16
+ { value: "mcp", label: "MCP Servers", icon: Network },
17
+ { value: "tools", label: "Tools", icon: Wrench },
18
+ ];
19
+
20
+ // Renders the live plugin (Asana) or a coming-soon placeholder per catalog entry.
21
+ function PluginRow({ pid, scope, entry }: { pid: string; scope: IntegrationScope; entry: CatalogEntry }) {
22
+ if (entry.coming_soon) return <ComingSoonPlugin entry={entry} />;
23
+ if (entry.slug === "asana") return <AsanaPlugin pid={pid} scope={scope} />;
24
+ // Implemented plugin without a bespoke UI yet — fall back to the placeholder.
25
+ return <ComingSoonPlugin entry={entry} />;
26
+ }
27
+
28
+ function PluginsSection({ pid, scope }: { pid: string; scope: IntegrationScope }) {
29
+ const { data: catalog, isLoading } = useSWR(`integrations-catalog-${pid}`, () => Integrations.catalog(pid));
30
+
31
+ return (
32
+ <div className="space-y-3">
33
+ <p className="text-xs text-muted-foreground">
34
+ Plugins de canal y servicio instalables por proyecto. Se guardan en el ámbito
35
+ seleccionado arriba.
36
+ </p>
37
+ {isLoading && <Loading />}
38
+ {(catalog || []).map((entry) => (
39
+ <PluginRow key={entry.slug} pid={pid} scope={scope} entry={entry} />
40
+ ))}
41
+ <div className="rounded-xl border border-dashed border-border p-6 text-center">
42
+ <p className="text-sm text-muted-foreground">Más plugins próximamente…</p>
43
+ </div>
44
+ </div>
45
+ );
46
+ }
47
+
48
+ function ToolsSection({ pid }: { pid: string }) {
49
+ const { data: catalog } = useSWR(`integrations-catalog-${pid}`, () => Integrations.catalog(pid));
50
+ const rows = (catalog || [])
51
+ .filter((c) => !c.coming_soon && (c.tools?.length ?? 0) > 0)
52
+ .flatMap((c) => (c.tools || []).map((t) => ({ ...t, plugin: c.name, active: c.status.is_enabled })));
53
+
54
+ return (
55
+ <div className="space-y-3">
56
+ <p className="text-xs text-muted-foreground">
57
+ Tools que los plugins conectados exponen a los agentes de este proyecto.
58
+ </p>
59
+ {rows.length === 0 ? (
60
+ <Empty>No hay tools de integraciones. Conectá un plugin para habilitarlas.</Empty>
61
+ ) : (
62
+ <ul className="space-y-2">
63
+ {rows.map((t) => (
64
+ <li key={t.slug} className={cn("rounded-md border border-border bg-muted/30 px-3 py-2", !t.active && "opacity-55")}>
65
+ <div className="flex items-center gap-2">
66
+ <Wrench className="h-3.5 w-3.5 text-muted-foreground" />
67
+ <span className="font-mono text-xs text-foreground">{t.slug}</span>
68
+ <span className="ml-auto text-[10px] text-muted-foreground">{t.plugin}</span>
69
+ <span
70
+ className={cn(
71
+ "rounded border px-1.5 py-0.5 text-[10px]",
72
+ t.active
73
+ ? "border-emerald-700/40 bg-emerald-900/20 text-emerald-400"
74
+ : "border-border bg-muted text-muted-foreground",
75
+ )}
76
+ >
77
+ {t.active ? "activo" : "inactivo"}
78
+ </span>
79
+ </div>
80
+ <p className="mt-0.5 pl-5 text-[10px] text-muted-foreground">{t.desc}</p>
81
+ </li>
82
+ ))}
83
+ </ul>
84
+ )}
85
+ </div>
86
+ );
87
+ }
88
+
89
+ export function IntegrationsTab({ pid }: { pid: string }) {
90
+ const isBase = String(pid) === "0";
91
+ const [tab, setTab] = useState<SubTab>("plugins");
92
+ // On the base project, project scope IS the global (default) store.
93
+ const [scope, setScope] = useState<IntegrationScope>(isBase ? "global" : "project");
94
+
95
+ return (
96
+ <Section
97
+ title="Integrations"
98
+ description="Plugins, MCP servers y tools disponibles para este proyecto"
99
+ >
100
+ {/* Scope selector — a real project can use its own integrations or the
101
+ global (default-project) ones. */}
102
+ {!isBase && (
103
+ <div className="mb-4 flex items-center gap-2">
104
+ <span className="text-xs text-muted-foreground">Ámbito:</span>
105
+ {(["project", "global"] as const).map((s) => (
106
+ <button
107
+ key={s}
108
+ onClick={() => setScope(s)}
109
+ className={cn(
110
+ "rounded-md border px-2.5 py-1 text-xs transition-colors",
111
+ scope === s
112
+ ? "border-primary/50 bg-primary/10 text-foreground"
113
+ : "border-border bg-muted/30 text-muted-foreground hover:bg-muted/50",
114
+ )}
115
+ >
116
+ {s === "project" ? "Este proyecto" : "Global (default)"}
117
+ </button>
118
+ ))}
119
+ </div>
120
+ )}
121
+
122
+ {/* Sub-tabs */}
123
+ <div className="mb-4 inline-flex rounded-lg border border-border bg-muted/30 p-0.5">
124
+ {SUBTABS.map((s) => {
125
+ const Icon = s.icon;
126
+ return (
127
+ <button
128
+ key={s.value}
129
+ onClick={() => setTab(s.value)}
130
+ className={cn(
131
+ "flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs transition-colors",
132
+ tab === s.value ? "bg-card text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground",
133
+ )}
134
+ >
135
+ <Icon className="h-3.5 w-3.5" /> {s.label}
136
+ </button>
137
+ );
138
+ })}
139
+ </div>
140
+
141
+ {tab === "plugins" && <PluginsSection pid={pid} scope={scope} />}
142
+ {tab === "mcp" && <McpsTab pid={pid} />}
143
+ {tab === "tools" && <ToolsSection pid={pid} />}
144
+ </Section>
145
+ );
146
+ }