conectese 0.1.15 → 0.2.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 +2 -2
- package/agents/conectese_admin/AGENT.md +10 -5
- package/agents/data-extractor/AGENT.md +35 -3
- package/agents/direito-administrativo/AGENT.md +68 -22
- package/agents/direito-aduaneiro/AGENT.md +55 -0
- package/agents/direito-aeroportuario/AGENT.md +53 -0
- package/agents/direito-agrario/AGENT.md +73 -0
- package/agents/direito-ambiental/AGENT.md +61 -24
- package/agents/direito-bancario/AGENT.md +79 -0
- package/agents/direito-civil/AGENT.md +71 -20
- package/agents/direito-constitucional/AGENT.md +79 -0
- package/agents/direito-da-crianca-e-do-adolescente-eca/AGENT.md +69 -0
- package/agents/direito-da-propriedade-intelectual/AGENT.md +65 -0
- package/agents/direito-de-familia/AGENT.md +92 -0
- package/agents/direito-de-transito/AGENT.md +59 -0
- package/agents/direito-desportivo/AGENT.md +40 -27
- package/agents/direito-digital/AGENT.md +61 -24
- package/agents/direito-do-consumidor/AGENT.md +77 -0
- package/agents/direito-do-trabalho/AGENT.md +73 -20
- package/agents/direito-economico/AGENT.md +58 -0
- package/agents/direito-eleitoral/AGENT.md +56 -24
- package/agents/direito-empresarial/AGENT.md +62 -24
- package/agents/direito-financeiro/AGENT.md +63 -0
- package/agents/direito-imobiliario/AGENT.md +79 -0
- package/agents/direito-indigena/AGENT.md +72 -0
- package/agents/direito-internacional/AGENT.md +55 -24
- package/agents/direito-maritimo/AGENT.md +55 -0
- package/agents/direito-medico-e-da-saude/AGENT.md +69 -0
- package/agents/direito-militar/AGENT.md +54 -24
- package/agents/direito-notarial-e-registral/AGENT.md +47 -24
- package/agents/direito-penal/AGENT.md +74 -19
- package/agents/direito-previdenciario/AGENT.md +84 -0
- package/agents/direito-processal-civil/AGENT.md +72 -20
- package/agents/direito-processal-do-trabalho/AGENT.md +58 -24
- package/agents/direito-processal-militar/AGENT.md +38 -27
- package/agents/direito-processal-penal/AGENT.md +62 -24
- package/agents/direito-processual-civil/AGENT.md +94 -0
- package/agents/direito-processual-do-trabalho/AGENT.md +76 -0
- package/agents/direito-processual-militar/AGENT.md +53 -0
- package/agents/direito-processual-penal/AGENT.md +80 -0
- package/agents/direito-securitario/AGENT.md +75 -0
- package/agents/direito-sindical/AGENT.md +46 -24
- package/agents/direito-societario/AGENT.md +65 -0
- package/agents/direito-tributario/AGENT.md +98 -0
- package/agents/direito-urbanistico/AGENT.md +58 -0
- package/agents/direitos-humanos/AGENT.md +76 -0
- package/agents/legal-analyst/AGENT.md +1 -1
- package/agents/legal-designer/AGENT.md +8 -3
- package/agents/lgpd-anonymizer/AGENT.md +66 -4
- package/agents/lgpd-restorer/AGENT.md +38 -4
- package/agents/task-router/AGENT.md +47 -3
- package/bin/conectese.js +4 -4
- package/dashboard/src/App.tsx +6 -4
- package/dashboard/src/components/CheckpointModal.tsx +150 -0
- package/dashboard/src/components/StatusBadge.tsx +3 -3
- package/dashboard/src/components/StatusBar.tsx +7 -7
- package/dashboard/src/components/{SquadCard.tsx → TeamCard.tsx} +7 -7
- package/dashboard/src/components/{SquadSelector.tsx → TeamSelector.tsx} +18 -18
- package/dashboard/src/hooks/{useSquadSocket.ts → useTeamSocket.ts} +13 -13
- package/dashboard/src/lib/normalizeState.ts +3 -3
- package/dashboard/src/office/OfficeScene.ts +3 -3
- package/dashboard/src/office/PhaserGame.tsx +6 -6
- package/dashboard/src/plugin/{squadWatcher.ts → teamWatcher.ts} +83 -44
- package/dashboard/src/store/useTeamStore.ts +56 -0
- package/dashboard/src/types/state.ts +10 -9
- package/dashboard/tsconfig.tsbuildinfo +1 -1
- package/dashboard/vite.config.ts +2 -2
- package/package.json +12 -9
- package/skills/README.md +1 -1
- package/skills/conectese-agent-creator/SKILL.md +1 -1
- package/skills/conectese-design/SKILL.md +50 -0
- package/skills/conectese-skill-creator/SKILL.md +3 -3
- package/skills/conectese-skill-creator/references/skill-format.md +4 -4
- package/skills/document-analyzer/SKILL.md +40 -0
- package/skills/document-analyzer/scripts/parse-doc.js +113 -0
- package/skills/image-ai-generator/SKILL.md +5 -5
- package/skills/image-creator/SKILL.md +3 -3
- package/skills/image-fetcher/SKILL.md +5 -5
- package/skills/instagram-publisher/SKILL.md +2 -2
- package/skills/jurisprudencia-validator/SKILL.md +45 -0
- package/skills/jurisprudencia-validator/scripts/validate-urls.js +103 -0
- package/skills/legal-pricing/SKILL.md +33 -0
- package/skills/legal-pricing/scripts/pricing-engine.js +72 -0
- package/skills/resend/SKILL.md +2 -2
- package/skills/template-designer/SKILL.md +29 -29
- package/src/agents-cli.js +1 -1
- package/src/agents.js +1 -1
- package/src/init.js +2 -1
- package/src/locales/en.json +2 -2
- package/src/locales/es.json +2 -2
- package/src/locales/pt-BR.json +2 -2
- package/src/readme/README.md +26 -26
- package/src/runs.js +14 -14
- package/src/skills-cli.js +1 -1
- package/src/update.js +1 -1
- package/templates/_conectese/.conectese-version +1 -1
- package/templates/ide-templates/antigravity/.agent/rules/conectese.md +10 -10
- package/templates/ide-templates/antigravity/.agent/workflows/conectese.md +18 -18
- package/templates/ide-templates/claude-code/.claude/skills/conectese/SKILL.md +31 -31
- package/templates/ide-templates/claude-code/CLAUDE.md +10 -10
- package/templates/ide-templates/codex/.agents/skills/conectese/SKILL.md +1 -1
- package/templates/ide-templates/codex/AGENTS.md +18 -18
- package/templates/ide-templates/cursor/.cursor/commands/conectese.md +1 -1
- package/templates/ide-templates/opencode/.opencode/commands/conectese.md +1 -1
- package/templates/ide-templates/opencode/AGENTS.md +18 -18
- package/templates/ide-templates/vscode-copilot/.github/prompts/conectese.prompt.md +33 -33
- package/_conectese/.conectese-version +0 -1
- package/_conectese/_memory/company/modelo_contrato.md +0 -18
- package/_conectese/_memory/company/modelo_procuracao.md +0 -15
- package/_conectese/_memory/company/modelo_recibo.md +0 -13
- package/_conectese/config/playwright.config.json +0 -11
- package/_conectese/core/architect.agent.yaml +0 -110
- package/_conectese/core/best-practices/_catalog.yaml +0 -116
- package/_conectese/core/best-practices/blog-post.md +0 -132
- package/_conectese/core/best-practices/blog-seo.md +0 -127
- package/_conectese/core/best-practices/copywriting.md +0 -426
- package/_conectese/core/best-practices/data-analysis.md +0 -401
- package/_conectese/core/best-practices/email-newsletter.md +0 -118
- package/_conectese/core/best-practices/email-sales.md +0 -110
- package/_conectese/core/best-practices/image-design.md +0 -348
- package/_conectese/core/best-practices/instagram-feed.md +0 -235
- package/_conectese/core/best-practices/instagram-reels.md +0 -112
- package/_conectese/core/best-practices/instagram-stories.md +0 -107
- package/_conectese/core/best-practices/linkedin-article.md +0 -116
- package/_conectese/core/best-practices/linkedin-post.md +0 -121
- package/_conectese/core/best-practices/researching.md +0 -349
- package/_conectese/core/best-practices/review.md +0 -269
- package/_conectese/core/best-practices/social-networks-publishing.md +0 -294
- package/_conectese/core/best-practices/strategist.md +0 -344
- package/_conectese/core/best-practices/technical-writing.md +0 -365
- package/_conectese/core/best-practices/twitter-post.md +0 -105
- package/_conectese/core/best-practices/twitter-thread.md +0 -122
- package/_conectese/core/best-practices/whatsapp-broadcast.md +0 -107
- package/_conectese/core/best-practices/youtube-script.md +0 -122
- package/_conectese/core/best-practices/youtube-shorts.md +0 -112
- package/_conectese/core/prompts/build.prompt.md +0 -547
- package/_conectese/core/prompts/design.prompt.md +0 -469
- package/_conectese/core/prompts/discovery.prompt.md +0 -269
- package/_conectese/core/prompts/sherlock-instagram.md +0 -123
- package/_conectese/core/prompts/sherlock-linkedin.md +0 -73
- package/_conectese/core/prompts/sherlock-shared.md +0 -684
- package/_conectese/core/prompts/sherlock-twitter.md +0 -78
- package/_conectese/core/prompts/sherlock-youtube.md +0 -85
- package/_conectese/core/runner.pipeline.md +0 -535
- package/_conectese/core/skills.engine.md +0 -381
- package/agents/direito-adaneiro/AGENT.md +0 -42
- package/agents/direito-aeroporta-rio/AGENT.md +0 -42
- package/agents/direito-agra-rio/AGENT.md +0 -42
- package/agents/direito-banca-rio/AGENT.md +0 -42
- package/agents/direito-constitcional/AGENT.md +0 -42
- package/agents/direito-da-crianc-a-e-do-adolescente-eca/AGENT.md +0 -42
- package/agents/direito-da-propriedade-intelectal/AGENT.md +0 -42
- package/agents/direito-de-ami-lia/AGENT.md +0 -42
- package/agents/direito-de-tra-nsito/AGENT.md +0 -42
- package/agents/direito-do-consmidor/AGENT.md +0 -42
- package/agents/direito-econo-mico/AGENT.md +0 -42
- package/agents/direito-imobilia-rio/AGENT.md +0 -42
- package/agents/direito-inanceiro/AGENT.md +0 -42
- package/agents/direito-mari-timo/AGENT.md +0 -42
- package/agents/direito-me-dico-e-da-sa-de/AGENT.md +0 -42
- package/agents/direito-ndia-rio/AGENT.md +0 -42
- package/agents/direito-previdencia-rio/AGENT.md +0 -42
- package/agents/direito-rbani-stico/AGENT.md +0 -42
- package/agents/direito-secrita-rio/AGENT.md +0 -42
- package/agents/direito-societa-rio/AGENT.md +0 -42
- package/agents/direito-tribta-rio/AGENT.md +0 -42
- package/agents/direitos-hmanos/AGENT.md +0 -42
- package/dashboard/src/store/useSquadStore.ts +0 -56
|
@@ -7,40 +7,40 @@ import fsp from "node:fs/promises";
|
|
|
7
7
|
import { watch as chokidarWatch } from "chokidar";
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import { parse as parseYaml } from "yaml";
|
|
10
|
-
import type {
|
|
10
|
+
import type { TeamInfo, TeamState, WsMessage } from "../types/state";
|
|
11
11
|
|
|
12
|
-
function
|
|
12
|
+
function resolveTeamsDir(): string {
|
|
13
13
|
const candidates = [
|
|
14
|
-
path.resolve(process.cwd(), "../
|
|
15
|
-
path.resolve(process.cwd(), "
|
|
14
|
+
path.resolve(process.cwd(), "../teams"), // started from dashboard/
|
|
15
|
+
path.resolve(process.cwd(), "teams"), // started from project root
|
|
16
16
|
];
|
|
17
17
|
for (const c of candidates) {
|
|
18
18
|
if (fs.existsSync(c)) return c;
|
|
19
19
|
}
|
|
20
|
-
return path.resolve(process.cwd(), "../
|
|
20
|
+
return path.resolve(process.cwd(), "../teams"); // default (will be created on demand)
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
async function
|
|
23
|
+
async function discoverTeams(teamsDir: string): Promise<TeamInfo[]> {
|
|
24
24
|
let entries;
|
|
25
25
|
try {
|
|
26
|
-
entries = await fsp.readdir(
|
|
26
|
+
entries = await fsp.readdir(teamsDir, { withFileTypes: true });
|
|
27
27
|
} catch {
|
|
28
28
|
return [];
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
const
|
|
31
|
+
const teams: TeamInfo[] = [];
|
|
32
32
|
|
|
33
33
|
for (const entry of entries) {
|
|
34
34
|
if (!entry.isDirectory()) continue;
|
|
35
35
|
if (entry.name.startsWith(".") || entry.name.startsWith("_")) continue;
|
|
36
36
|
|
|
37
|
-
const yamlPath = path.join(
|
|
37
|
+
const yamlPath = path.join(teamsDir, entry.name, "team.yaml");
|
|
38
38
|
try {
|
|
39
39
|
const raw = await fsp.readFile(yamlPath, "utf-8");
|
|
40
40
|
const parsed = parseYaml(raw);
|
|
41
|
-
const s = parsed?.
|
|
41
|
+
const s = parsed?.team;
|
|
42
42
|
if (s) {
|
|
43
|
-
|
|
43
|
+
teams.push({
|
|
44
44
|
code: typeof s.code === "string" ? s.code : entry.name,
|
|
45
45
|
name: typeof s.name === "string" ? s.name : entry.name,
|
|
46
46
|
description: typeof s.description === "string" ? s.description : "",
|
|
@@ -50,10 +50,10 @@ async function discoverSquads(squadsDir: string): Promise<SquadInfo[]> {
|
|
|
50
50
|
continue;
|
|
51
51
|
}
|
|
52
52
|
} catch {
|
|
53
|
-
// No
|
|
53
|
+
// No team.yaml or invalid YAML — fall through to default
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
teams.push({
|
|
57
57
|
code: entry.name,
|
|
58
58
|
name: entry.name,
|
|
59
59
|
description: "",
|
|
@@ -62,10 +62,10 @@ async function discoverSquads(squadsDir: string): Promise<SquadInfo[]> {
|
|
|
62
62
|
});
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
return
|
|
65
|
+
return teams;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
function isValidState(data: unknown): data is
|
|
68
|
+
function isValidState(data: unknown): data is TeamState {
|
|
69
69
|
if (!data || typeof data !== "object") return false;
|
|
70
70
|
const d = data as Record<string, unknown>;
|
|
71
71
|
return (
|
|
@@ -75,19 +75,19 @@ function isValidState(data: unknown): data is SquadState {
|
|
|
75
75
|
);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
async function readActiveStates(
|
|
79
|
-
const states: Record<string,
|
|
78
|
+
async function readActiveStates(teamsDir: string): Promise<Record<string, TeamState>> {
|
|
79
|
+
const states: Record<string, TeamState> = {};
|
|
80
80
|
|
|
81
81
|
let entries;
|
|
82
82
|
try {
|
|
83
|
-
entries = await fsp.readdir(
|
|
83
|
+
entries = await fsp.readdir(teamsDir, { withFileTypes: true });
|
|
84
84
|
} catch {
|
|
85
85
|
return states;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
for (const entry of entries) {
|
|
89
89
|
if (!entry.isDirectory()) continue;
|
|
90
|
-
const statePath = path.join(
|
|
90
|
+
const statePath = path.join(teamsDir, entry.name, "state.json");
|
|
91
91
|
|
|
92
92
|
try {
|
|
93
93
|
const raw = await fsp.readFile(statePath, "utf-8");
|
|
@@ -103,11 +103,11 @@ async function readActiveStates(squadsDir: string): Promise<Record<string, Squad
|
|
|
103
103
|
return states;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
async function buildSnapshot(
|
|
106
|
+
async function buildSnapshot(teamsDir: string): Promise<WsMessage> {
|
|
107
107
|
return {
|
|
108
108
|
type: "SNAPSHOT",
|
|
109
|
-
|
|
110
|
-
activeStates: await readActiveStates(
|
|
109
|
+
teams: await discoverTeams(teamsDir),
|
|
110
|
+
activeStates: await readActiveStates(teamsDir),
|
|
111
111
|
};
|
|
112
112
|
}
|
|
113
113
|
|
|
@@ -124,22 +124,22 @@ function broadcast(wss: WebSocketServer, msg: WsMessage) {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
export function
|
|
127
|
+
export function teamWatcherPlugin(): Plugin {
|
|
128
128
|
return {
|
|
129
|
-
name: "
|
|
129
|
+
name: "team-watcher",
|
|
130
130
|
configureServer(server: ViteDevServer) {
|
|
131
131
|
if (!server.httpServer) {
|
|
132
|
-
server.config.logger.warn("[
|
|
132
|
+
server.config.logger.warn("[team-watcher] no httpServer — skipping");
|
|
133
133
|
return;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
const
|
|
137
|
-
server.config.logger.info(`[
|
|
136
|
+
const teamsDir = resolveTeamsDir();
|
|
137
|
+
server.config.logger.info(`[team-watcher] teams dir: ${teamsDir}`);
|
|
138
138
|
|
|
139
139
|
// Create WebSocket server with noServer to avoid intercepting Vite's HMR
|
|
140
140
|
const wss = new WebSocketServer({ noServer: true });
|
|
141
141
|
(server.httpServer as Server).on("upgrade", (req: IncomingMessage, socket: Duplex, head: Buffer) => {
|
|
142
|
-
if (req.url === "/
|
|
142
|
+
if (req.url === "/__teams_ws") {
|
|
143
143
|
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
144
144
|
wss.emit("connection", ws, req);
|
|
145
145
|
});
|
|
@@ -150,23 +150,23 @@ export function squadWatcherPlugin(): Plugin {
|
|
|
150
150
|
// Send snapshot on new connection
|
|
151
151
|
wss.on("connection", async (ws) => {
|
|
152
152
|
try {
|
|
153
|
-
const snap = await buildSnapshot(
|
|
153
|
+
const snap = await buildSnapshot(teamsDir);
|
|
154
154
|
ws.send(JSON.stringify(snap));
|
|
155
155
|
} catch {
|
|
156
156
|
// Connection may have closed before snapshot was ready
|
|
157
157
|
}
|
|
158
158
|
});
|
|
159
159
|
|
|
160
|
-
// Ensure
|
|
161
|
-
fsp.mkdir(
|
|
162
|
-
server.config.logger.error(`[
|
|
160
|
+
// Ensure teams directory exists
|
|
161
|
+
fsp.mkdir(teamsDir, { recursive: true }).catch((err) => {
|
|
162
|
+
server.config.logger.error(`[team-watcher] failed to create teams dir: ${err.message}`);
|
|
163
163
|
});
|
|
164
164
|
|
|
165
165
|
// REST API fallback & File Upload
|
|
166
166
|
server.middlewares.use(async (req, res, next) => {
|
|
167
167
|
if (req.url === "/api/snapshot" && req.method === "GET") {
|
|
168
168
|
try {
|
|
169
|
-
const snapshot = await buildSnapshot(
|
|
169
|
+
const snapshot = await buildSnapshot(teamsDir);
|
|
170
170
|
res.setHeader("Content-Type", "application/json");
|
|
171
171
|
res.setHeader("Cache-Control", "no-cache");
|
|
172
172
|
res.end(JSON.stringify(snapshot));
|
|
@@ -256,11 +256,50 @@ export function squadWatcherPlugin(): Plugin {
|
|
|
256
256
|
return;
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
+
if (req.url?.startsWith("/api/team/") && req.url?.endsWith("/checkpoint") && req.method === "POST") {
|
|
260
|
+
const parts = req.url.split("/");
|
|
261
|
+
const teamName = parts[3];
|
|
262
|
+
let body = "";
|
|
263
|
+
req.on("data", chunk => body += chunk.toString());
|
|
264
|
+
req.on("end", async () => {
|
|
265
|
+
try {
|
|
266
|
+
const payload = JSON.parse(body);
|
|
267
|
+
const checkpointFile = path.join(teamsDir, teamName, "checkpoint_response.json");
|
|
268
|
+
await fsp.writeFile(checkpointFile, JSON.stringify(payload, null, 2), "utf-8");
|
|
269
|
+
|
|
270
|
+
const stateFile = path.join(teamsDir, teamName, "state.json");
|
|
271
|
+
try {
|
|
272
|
+
const stateRaw = await fsp.readFile(stateFile, "utf-8");
|
|
273
|
+
const state = JSON.parse(stateRaw);
|
|
274
|
+
state.status = "running"; // Clear checkpoint status on UI
|
|
275
|
+
if (state.agents) {
|
|
276
|
+
state.agents.forEach((a: any) => {
|
|
277
|
+
if (a.status === "checkpoint") a.status = "working";
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
state.updatedAt = new Date().toISOString();
|
|
281
|
+
await fsp.writeFile(stateFile, JSON.stringify(state, null, 2), "utf-8");
|
|
282
|
+
} catch (e) {
|
|
283
|
+
// Ignore state.json update errors
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
res.setHeader("Content-Type", "application/json");
|
|
287
|
+
res.writeHead(200);
|
|
288
|
+
res.end(JSON.stringify({ success: true }));
|
|
289
|
+
} catch (err: any) {
|
|
290
|
+
res.setHeader("Content-Type", "application/json");
|
|
291
|
+
res.writeHead(400);
|
|
292
|
+
res.end(JSON.stringify({ success: false, error: err.message }));
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
259
298
|
return next();
|
|
260
299
|
});
|
|
261
300
|
|
|
262
301
|
// File watcher using chokidar — reliable cross-platform, handles partial writes
|
|
263
|
-
const watcher = chokidarWatch(
|
|
302
|
+
const watcher = chokidarWatch(teamsDir, {
|
|
264
303
|
ignoreInitial: true,
|
|
265
304
|
awaitWriteFinish: { stabilityThreshold: 300, pollInterval: 50 },
|
|
266
305
|
ignored: [/(^|[/\\])\./, /node_modules/, /output[/\\]/],
|
|
@@ -268,38 +307,38 @@ export function squadWatcherPlugin(): Plugin {
|
|
|
268
307
|
});
|
|
269
308
|
|
|
270
309
|
function handleFileChange(filePath: string) {
|
|
271
|
-
const relative = path.relative(
|
|
310
|
+
const relative = path.relative(teamsDir, filePath).replace(/\\/g, "/");
|
|
272
311
|
const parts = relative.split("/");
|
|
273
312
|
if (parts.length < 2) return;
|
|
274
313
|
|
|
275
|
-
const
|
|
314
|
+
const teamName = parts[0];
|
|
276
315
|
const fileName = parts[1];
|
|
277
316
|
|
|
278
317
|
if (fileName === "state.json") {
|
|
279
318
|
fsp.readFile(filePath, "utf-8").then((raw) => {
|
|
280
319
|
const parsed = JSON.parse(raw);
|
|
281
320
|
if (!isValidState(parsed)) return;
|
|
282
|
-
broadcast(wss, { type: "
|
|
321
|
+
broadcast(wss, { type: "TEAM_UPDATE", team: teamName, state: parsed });
|
|
283
322
|
}).catch(() => {
|
|
284
323
|
// Invalid JSON — next change event will retry
|
|
285
324
|
});
|
|
286
|
-
} else if (fileName === "
|
|
287
|
-
buildSnapshot(
|
|
325
|
+
} else if (fileName === "team.yaml") {
|
|
326
|
+
buildSnapshot(teamsDir).then((snap) => broadcast(wss, snap));
|
|
288
327
|
}
|
|
289
328
|
}
|
|
290
329
|
|
|
291
330
|
function handleFileRemoval(filePath: string) {
|
|
292
|
-
const relative = path.relative(
|
|
331
|
+
const relative = path.relative(teamsDir, filePath).replace(/\\/g, "/");
|
|
293
332
|
const parts = relative.split("/");
|
|
294
333
|
if (parts.length < 2) return;
|
|
295
334
|
|
|
296
|
-
const
|
|
335
|
+
const teamName = parts[0];
|
|
297
336
|
const fileName = parts[1];
|
|
298
337
|
|
|
299
338
|
if (fileName === "state.json") {
|
|
300
|
-
broadcast(wss, { type: "
|
|
301
|
-
} else if (fileName === "
|
|
302
|
-
buildSnapshot(
|
|
339
|
+
broadcast(wss, { type: "TEAM_INACTIVE", team: teamName });
|
|
340
|
+
} else if (fileName === "team.yaml") {
|
|
341
|
+
buildSnapshot(teamsDir).then((snap) => broadcast(wss, snap));
|
|
303
342
|
}
|
|
304
343
|
}
|
|
305
344
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { create } from "zustand";
|
|
2
|
+
import type { TeamInfo, TeamState } from "@/types/state";
|
|
3
|
+
|
|
4
|
+
interface TeamStore {
|
|
5
|
+
// State
|
|
6
|
+
teams: Map<string, TeamInfo>;
|
|
7
|
+
activeStates: Map<string, TeamState>;
|
|
8
|
+
selectedTeam: string | null;
|
|
9
|
+
isConnected: boolean;
|
|
10
|
+
|
|
11
|
+
// Actions
|
|
12
|
+
selectTeam: (name: string | null) => void;
|
|
13
|
+
setConnected: (connected: boolean) => void;
|
|
14
|
+
setSnapshot: (teams: TeamInfo[], activeStates: Record<string, TeamState>) => void;
|
|
15
|
+
setTeamActive: (team: string, state: TeamState) => void;
|
|
16
|
+
updateTeamState: (team: string, state: TeamState) => void;
|
|
17
|
+
setTeamInactive: (team: string) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const useTeamStore = create<TeamStore>((set) => ({
|
|
21
|
+
teams: new Map(),
|
|
22
|
+
activeStates: new Map(),
|
|
23
|
+
selectedTeam: null,
|
|
24
|
+
isConnected: false,
|
|
25
|
+
|
|
26
|
+
selectTeam: (name) => set({ selectedTeam: name }),
|
|
27
|
+
|
|
28
|
+
setConnected: (connected) => set({ isConnected: connected }),
|
|
29
|
+
|
|
30
|
+
setSnapshot: (teams, activeStates) =>
|
|
31
|
+
set({
|
|
32
|
+
teams: new Map(teams.map((s) => [s.code, s])),
|
|
33
|
+
activeStates: new Map(Object.entries(activeStates)),
|
|
34
|
+
}),
|
|
35
|
+
|
|
36
|
+
setTeamActive: (team, state) =>
|
|
37
|
+
set((prev) => ({
|
|
38
|
+
activeStates: new Map(prev.activeStates).set(team, state),
|
|
39
|
+
})),
|
|
40
|
+
|
|
41
|
+
updateTeamState: (team, state) =>
|
|
42
|
+
set((prev) => ({
|
|
43
|
+
activeStates: new Map(prev.activeStates).set(team, state),
|
|
44
|
+
})),
|
|
45
|
+
|
|
46
|
+
setTeamInactive: (team) =>
|
|
47
|
+
set((prev) => {
|
|
48
|
+
const next = new Map(prev.activeStates);
|
|
49
|
+
next.delete(team);
|
|
50
|
+
return {
|
|
51
|
+
activeStates: next,
|
|
52
|
+
// Reset selection if the inactive team was selected
|
|
53
|
+
selectedTeam: prev.selectedTeam === team ? null : prev.selectedTeam,
|
|
54
|
+
};
|
|
55
|
+
}),
|
|
56
|
+
}));
|
|
@@ -25,17 +25,18 @@ export interface Handoff {
|
|
|
25
25
|
to: string;
|
|
26
26
|
message: string;
|
|
27
27
|
completedAt: string;
|
|
28
|
+
missingData?: string[];
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
export type
|
|
31
|
+
export type TeamStatus =
|
|
31
32
|
| "idle"
|
|
32
33
|
| "running"
|
|
33
34
|
| "completed"
|
|
34
35
|
| "checkpoint";
|
|
35
36
|
|
|
36
|
-
export interface
|
|
37
|
-
|
|
38
|
-
status:
|
|
37
|
+
export interface TeamState {
|
|
38
|
+
team: string;
|
|
39
|
+
status: TeamStatus;
|
|
39
40
|
step: {
|
|
40
41
|
current: number;
|
|
41
42
|
total: number;
|
|
@@ -47,8 +48,8 @@ export interface SquadState {
|
|
|
47
48
|
updatedAt: string;
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
//
|
|
51
|
-
export interface
|
|
51
|
+
// Team metadata from team.yaml
|
|
52
|
+
export interface TeamInfo {
|
|
52
53
|
code: string;
|
|
53
54
|
name: string;
|
|
54
55
|
description: string;
|
|
@@ -58,6 +59,6 @@ export interface SquadInfo {
|
|
|
58
59
|
|
|
59
60
|
// WebSocket messages
|
|
60
61
|
export type WsMessage =
|
|
61
|
-
| { type: "SNAPSHOT";
|
|
62
|
-
| { type: "
|
|
63
|
-
| { type: "
|
|
62
|
+
| { type: "SNAPSHOT"; teams: TeamInfo[]; activeStates: Record<string, TeamState> }
|
|
63
|
+
| { type: "TEAM_UPDATE"; team: string; state: TeamState }
|
|
64
|
+
| { type: "TEAM_INACTIVE"; team: string };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/components/ingestionmodal.tsx","./src/components/
|
|
1
|
+
{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/components/ingestionmodal.tsx","./src/components/statusbadge.tsx","./src/components/statusbar.tsx","./src/components/teamcard.tsx","./src/components/teamselector.tsx","./src/hooks/useteamsocket.ts","./src/lib/formattime.ts","./src/lib/normalizestate.ts","./src/office/agentsprite.ts","./src/office/officescene.ts","./src/office/phasergame.tsx","./src/office/roombuilder.ts","./src/office/assetkeys.ts","./src/office/palette.ts","./src/plugin/teamwatcher.ts","./src/store/useteamstore.ts","./src/types/state.ts"],"version":"5.9.3"}
|
package/dashboard/vite.config.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { defineConfig } from "vite";
|
|
2
2
|
import react from "@vitejs/plugin-react";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { teamWatcherPlugin } from "./src/plugin/teamWatcher";
|
|
5
5
|
|
|
6
6
|
export default defineConfig({
|
|
7
|
-
plugins: [react(),
|
|
7
|
+
plugins: [react(), teamWatcherPlugin()],
|
|
8
8
|
resolve: {
|
|
9
9
|
alias: {
|
|
10
10
|
"@": path.resolve(__dirname, "./src"),
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "conectese",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Multi-agent orchestration framework — create AI
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Multi-agent orchestration framework — create AI teams that work together",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"conectese": "bin/conectese.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"test": "node --test tests/*.test.js",
|
|
10
|
+
"test": "node --test 'tests/**/*.test.js' 'tests/*.test.js'",
|
|
11
11
|
"lint": "eslint src/ bin/ tests/",
|
|
12
12
|
"setup-admin": "node bin/setup_admin.js",
|
|
13
13
|
"version": "node -e \"require('fs').writeFileSync('templates/_conectese/.conectese-version', require('./package.json').version + '\\n')\" && git add templates/_conectese/.conectese-version"
|
|
@@ -17,16 +17,16 @@
|
|
|
17
17
|
"ai-agents",
|
|
18
18
|
"multi-agent",
|
|
19
19
|
"orchestration",
|
|
20
|
-
"
|
|
20
|
+
"teams"
|
|
21
21
|
],
|
|
22
|
-
"author": "
|
|
23
|
-
"homepage": "https://github.com/
|
|
22
|
+
"author": "Carlos Henrique (https://github.com/henriqueadm-ai)",
|
|
23
|
+
"homepage": "https://github.com/henriqueadm-ai/conectese#readme",
|
|
24
24
|
"repository": {
|
|
25
25
|
"type": "git",
|
|
26
|
-
"url": "git+https://github.com/
|
|
26
|
+
"url": "git+https://github.com/henriqueadm-ai/conectese.git"
|
|
27
27
|
},
|
|
28
28
|
"bugs": {
|
|
29
|
-
"url": "https://github.com/
|
|
29
|
+
"url": "https://github.com/henriqueadm-ai/conectese/issues"
|
|
30
30
|
},
|
|
31
31
|
"license": "MIT",
|
|
32
32
|
"engines": {
|
|
@@ -38,10 +38,10 @@
|
|
|
38
38
|
"agents/",
|
|
39
39
|
"skills/",
|
|
40
40
|
"templates/",
|
|
41
|
-
"_conectese/",
|
|
42
41
|
"dashboard/"
|
|
43
42
|
],
|
|
44
43
|
"dependencies": {
|
|
44
|
+
"@google/genai": "^1.48.0",
|
|
45
45
|
"@inquirer/checkbox": "^5.1.0",
|
|
46
46
|
"@inquirer/input": "^5.0.0",
|
|
47
47
|
"@inquirer/select": "^5.1.0",
|
|
@@ -51,6 +51,9 @@
|
|
|
51
51
|
"dotenv": "^17.4.0",
|
|
52
52
|
"html-to-docx": "^1.8.0",
|
|
53
53
|
"marked": "^17.0.5",
|
|
54
|
+
"pdf-parse": "^2.4.5"
|
|
55
|
+
},
|
|
56
|
+
"optionalDependencies": {
|
|
54
57
|
"puppeteer": "^24.40.0",
|
|
55
58
|
"puppeteer-extra": "^3.3.6",
|
|
56
59
|
"puppeteer-extra-plugin-stealth": "^2.11.2"
|
package/skills/README.md
CHANGED
|
@@ -142,7 +142,7 @@ The Best-Practice Creator workflow (above) handles the initial `whenToUse` cross
|
|
|
142
142
|
|
|
143
143
|
### When updating a best-practice file's `whenToUse` scope
|
|
144
144
|
|
|
145
|
-
This is the most impactful change — it affects how the Architect selects best practices during
|
|
145
|
+
This is the most impactful change — it affects how the Architect selects best practices during team creation.
|
|
146
146
|
|
|
147
147
|
1. Document the old scope and new scope
|
|
148
148
|
2. Update the best-practice file's `whenToUse` field
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: conectese-design
|
|
3
|
+
description: >
|
|
4
|
+
Motor de design jurídico (Visual Law). Converte Markdown judicial em PDFs
|
|
5
|
+
e DOCXs estilizados com timbre do escritório, empregando CSS premium e
|
|
6
|
+
Puppeteer para renderização fiel. Inclui geração de contratos, procurações,
|
|
7
|
+
recibos e peças processuais formatadas.
|
|
8
|
+
type: mcp
|
|
9
|
+
version: "1.0.0"
|
|
10
|
+
mcp:
|
|
11
|
+
server_name: conectese-design
|
|
12
|
+
command: node
|
|
13
|
+
args: ["skills/conectese-design/index.cjs"]
|
|
14
|
+
transport: stdio
|
|
15
|
+
categories: [design, legal, pdf, visual-law]
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Conectese Design (Visual Law Engine)
|
|
19
|
+
|
|
20
|
+
## When to use
|
|
21
|
+
|
|
22
|
+
Use esta skill quando o pipeline precisar gerar documentos jurídicos em PDF ou DOCX com formatação profissional e timbre do escritório. Ela é o motor de saída visual da plataforma Conecte.se.
|
|
23
|
+
|
|
24
|
+
## Instructions
|
|
25
|
+
|
|
26
|
+
### Ferramentas disponíveis (MCP Tools)
|
|
27
|
+
|
|
28
|
+
- **`generate_visual_law_pdf`**: Recebe Markdown + ID do processo, gera PDF estilizado com timbre institucional.
|
|
29
|
+
- **`generate_visual_law_docx`**: Mesmo fluxo mas gera DOCX editável.
|
|
30
|
+
- **`generate_contract_pdf`**: Gera PDF de contrato preenchido a partir de modelo + dados do cliente.
|
|
31
|
+
|
|
32
|
+
### Parâmetros obrigatórios
|
|
33
|
+
|
|
34
|
+
| Parâmetro | Descrição |
|
|
35
|
+
|-----------|-----------|
|
|
36
|
+
| `markdownContent` | O conteúdo Markdown da peça/documento |
|
|
37
|
+
| `processId` | ID do processo (ex: `P05_04_0001`) ou `ADMINISTRATIVO` para documentos fora de processos |
|
|
38
|
+
| `outputFormat` | `pdf` ou `docx` |
|
|
39
|
+
|
|
40
|
+
### Comportamento de saída
|
|
41
|
+
|
|
42
|
+
- PDFs e DOCXs são salvos automaticamente em `PROCESSOS/{processId}/` ou `ADMINISTRATIVO/`.
|
|
43
|
+
- O timbre do escritório é carregado de `_conectese/_memory/company/dados.json`.
|
|
44
|
+
- CSS premium aplicado com fontes profissionais e espaçamento tipográfico adequado.
|
|
45
|
+
|
|
46
|
+
### Best practices
|
|
47
|
+
|
|
48
|
+
- Sempre passe o `processId` correto para organização automática de arquivos.
|
|
49
|
+
- O Markdown de entrada deve usar as tags de anonimização `[PESSOA_1]` até o `lgpd-restorer` fazer a restauração final.
|
|
50
|
+
- Para documentos administrativos (contratos, procurações), use `ADMINISTRATIVO` como processId.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: conectese-skill-creator
|
|
3
|
-
description: Create new Conectese skills, modify and improve existing skills, and measure skill performance. Use when users want to create a skill for their
|
|
3
|
+
description: Create new Conectese skills, modify and improve existing skills, and measure skill performance. Use when users want to create a skill for their teams, update or optimize an existing skill, run evals to test a skill, or benchmark skill performance. Supports all Conectese skill types: MCP integrations, custom scripts, hybrid, and behavioral prompts.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Conectese Skill Creator
|
|
@@ -47,7 +47,7 @@ It's OK to briefly explain terms if you're in doubt, and feel free to clarify te
|
|
|
47
47
|
Start by understanding the user's intent. The current conversation might already contain a workflow the user wants to capture (e.g., they say "turn this into a skill"). If so, extract answers from the conversation history first — the tools used, the sequence of steps, corrections the user made, input/output formats observed. The user may need to fill the gaps, and should confirm before proceeding to the next step.
|
|
48
48
|
|
|
49
49
|
1. What should this skill enable agents to do?
|
|
50
|
-
2. When should this skill be used? (what user phrases/contexts/
|
|
50
|
+
2. When should this skill be used? (what user phrases/contexts/team scenarios)
|
|
51
51
|
3. What's the expected output format?
|
|
52
52
|
4. Should we set up test cases to verify the skill works? Skills with objectively verifiable outputs (file transforms, data extraction, code generation, fixed workflow steps) benefit from test cases. Skills with subjective outputs (writing style, art) often don't need them. Suggest the appropriate default based on the skill type, but let the user decide.
|
|
53
53
|
|
|
@@ -190,7 +190,7 @@ For each test case, spawn two subagents in the same turn — one with the skill,
|
|
|
190
190
|
|
|
191
191
|
**With-skill run:**
|
|
192
192
|
|
|
193
|
-
The with-skill run simulates how a Conectese agent operates with this skill injected into its context. The skill's SKILL.md body gets appended to the agent's instructions, just like the pipeline runner does during actual
|
|
193
|
+
The with-skill run simulates how a Conectese agent operates with this skill injected into its context. The skill's SKILL.md body gets appended to the agent's instructions, just like the pipeline runner does during actual team execution.
|
|
194
194
|
|
|
195
195
|
```
|
|
196
196
|
Execute this task:
|
|
@@ -91,7 +91,7 @@ mcp:
|
|
|
91
91
|
|
|
92
92
|
## When to use
|
|
93
93
|
|
|
94
|
-
Use this skill when the user or
|
|
94
|
+
Use this skill when the user or team pipeline needs to create visual content — social media posts, presentations, flyers, or any graphic design task that benefits from Canva's template library.
|
|
95
95
|
|
|
96
96
|
## Instructions
|
|
97
97
|
|
|
@@ -155,7 +155,7 @@ Use this skill when the pipeline needs to analyze tabular data from CSV files
|
|
|
155
155
|
```yaml
|
|
156
156
|
---
|
|
157
157
|
name: professional-tone
|
|
158
|
-
description: Write content in a professional corporate tone. Use when
|
|
158
|
+
description: Write content in a professional corporate tone. Use when team agents need to produce business communications, reports, or client-facing materials that require formal, polished language.
|
|
159
159
|
type: prompt
|
|
160
160
|
version: 1.0.0
|
|
161
161
|
categories:
|
|
@@ -198,7 +198,7 @@ When writing in professional tone:
|
|
|
198
198
|
```yaml
|
|
199
199
|
---
|
|
200
200
|
name: social-publisher
|
|
201
|
-
description: Draft social media content and publish via API. Use when
|
|
201
|
+
description: Draft social media content and publish via API. Use when teams need to create and post content to Instagram, Twitter/X, or LinkedIn with approval workflows.
|
|
202
202
|
type: hybrid
|
|
203
203
|
version: 1.0.0
|
|
204
204
|
categories:
|
|
@@ -227,7 +227,7 @@ Use this skill when the pipeline needs to both create and publish social media c
|
|
|
227
227
|
|
|
228
228
|
## Instructions
|
|
229
229
|
|
|
230
|
-
1. Draft the content using
|
|
230
|
+
1. Draft the content using team agent context (topic, tone, audience)
|
|
231
231
|
2. Run the formatting script to prepare platform-specific versions
|
|
232
232
|
3. Present drafts for user approval at the checkpoint
|
|
233
233
|
4. After approval, use the MCP server to publish to the target platforms
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: document-analyzer
|
|
3
|
+
description: >
|
|
4
|
+
Motor analítico de documentos para extração e estruturação profunda de PDFs.
|
|
5
|
+
Lê arquivos não estruturados e aplica frameworks de extração semântica
|
|
6
|
+
(classificação de entidades, SLAs, Prazos, CNPJs, etc.).
|
|
7
|
+
version: "1.0.0"
|
|
8
|
+
type: "custom"
|
|
9
|
+
categories: [data, parsing, legal]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Document Analyzer
|
|
13
|
+
|
|
14
|
+
## When to use
|
|
15
|
+
|
|
16
|
+
Use a ferramenta `document-analyzer` quando você ou outro Agente precisar inferir e extrair inteligência processável a partir de contratos, relatórios, peças processuais ou arquivos PDF enviados por usuários. Esta skill consolida extração óptica/vetorial (OCR/Parsing) com a sua própria capacidade nativa cognitiva para devolver formatos padronizados (JSON, Markdown) livres de ruído estrutural.
|
|
17
|
+
|
|
18
|
+
## Instructions
|
|
19
|
+
|
|
20
|
+
Esta Skill invoca scripts locais do Node.js (via bash) juntamente com suas próprias heurísticas de extração semântica.
|
|
21
|
+
|
|
22
|
+
### Key capabilities
|
|
23
|
+
|
|
24
|
+
- **Text Extraction (PDFs):** Extração bruta de texto de vetores locais usando algoritmos otimizados para evitar alucinações de formatação.
|
|
25
|
+
- **Data Extractor Pipeline:** Extração estruturada de dados densos (ex: Cláusulas de Quebra, Multas, Prazos Recusais, Qualificação de Partes) de forma determinística.
|
|
26
|
+
- **Noise Reduction:** Limpeza de cabeçalhos/rodapés mortos que gastam cota de tokens no prompt.
|
|
27
|
+
|
|
28
|
+
### Best practices
|
|
29
|
+
|
|
30
|
+
- **Sempre Verifique o Retorno:** Ao ler um arquivo grande usando a ferramenta de extração, procure limitar a resposta fatiando-a, se for necessário analisar em múltiplos passos.
|
|
31
|
+
- **Saída Estruturada:** Se o usuário pedir os "termos chave", elabore um mapeamento estrito retornando num formato de blocos demarcados (`JSON` ou `lista md`).
|
|
32
|
+
- **Anonimização (LGPD):** Se você for rotear o resultado documentado para fora do ambiente de auditoria, Oculte CPFs e nomes sensíveis.
|
|
33
|
+
|
|
34
|
+
## Available operations
|
|
35
|
+
|
|
36
|
+
Abaixo explicamos o wrapper integrado para consumo. Execute o script com sua sandbox local:
|
|
37
|
+
|
|
38
|
+
- `node skills/document-analyzer/scripts/parse-doc.js <caminho.pdf>`: Recebe um arquivo PDF e tenta extrair o texto via parsing nativo. Caso retorne texto vazio (indicando ser um arquivo digitalizado/imagem), **fará um fallback automático** para leitura via LLM (Gemini Vision) em background requerendo a chave de ambiente `GEMINI_API_KEY`.
|
|
39
|
+
- `node skills/document-analyzer/scripts/parse-doc.js <caminho.pdf> --vision`: Força imediatamente a leitura visual multimodal desabilitando a decodificação pura do arquivo local.
|
|
40
|
+
- `node skills/document-analyzer/scripts/parse-doc.js <caminho.pdf> --extract="Extraia apenas os valores e datas em formato JSON"`: Além de fazer OCR/Vision do documento, embute um system prompt customizado onde a extração será orientada de modo formidável a retornar dados pré-estruturados conforme seu pedido.
|