@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.
- package/package.json +1 -1
- package/src/core/agent/tools/handlers/_asana.js +34 -0
- package/src/core/agent/tools/handlers/asana-create-task.js +38 -0
- package/src/core/agent/tools/handlers/asana-list-projects.js +19 -0
- package/src/core/agent/tools/handlers/asana-list-tasks.js +27 -0
- package/src/core/agent/tools/handlers/asana-update-task.js +32 -0
- package/src/core/agent/tools/names.js +10 -0
- package/src/core/agent/tools/registry.js +11 -0
- package/src/core/integrations/catalog.js +66 -0
- package/src/core/integrations/index.js +10 -0
- package/src/core/integrations/plugins/asana.js +231 -0
- package/src/core/integrations/sources.js +56 -0
- package/src/core/integrations/store.js +118 -0
- package/src/core/stores/project-files.js +21 -2
- package/src/host/daemon/api/integrations.js +191 -0
- package/src/host/daemon/api.js +2 -0
- package/src/interfaces/web/dist/assets/{index-CnQb4N6C.js → index-DFNV6BWh.js} +193 -163
- package/src/interfaces/web/dist/assets/index-DFNV6BWh.js.map +1 -0
- package/src/interfaces/web/dist/assets/index-HU-Wt2l9.css +1 -0
- package/src/interfaces/web/dist/index.html +2 -2
- package/src/interfaces/web/src/components/integrations/AsanaPlugin.tsx +275 -0
- package/src/interfaces/web/src/components/integrations/ComingSoonPlugin.tsx +44 -0
- package/src/interfaces/web/src/components/integrations/PluginCard.tsx +61 -0
- package/src/interfaces/web/src/components/integrations/PluginToolsSection.tsx +39 -0
- package/src/interfaces/web/src/lib/api/integrations.ts +106 -0
- package/src/interfaces/web/src/lib/api.ts +1 -0
- package/src/interfaces/web/src/screens/ProjectScreen.tsx +6 -2
- package/src/interfaces/web/src/screens/project/IntegrationsTab.tsx +146 -0
- package/src/interfaces/web/dist/assets/index-CnQb4N6C.js.map +0 -1
- 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
|
+
}
|