conectese 0.1.14
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 +265 -0
- package/_conectese/.conectese-version +1 -0
- package/_conectese/config/playwright.config.json +11 -0
- package/_conectese/core/architect.agent.yaml +110 -0
- package/_conectese/core/best-practices/_catalog.yaml +116 -0
- package/_conectese/core/best-practices/blog-post.md +132 -0
- package/_conectese/core/best-practices/blog-seo.md +127 -0
- package/_conectese/core/best-practices/copywriting.md +426 -0
- package/_conectese/core/best-practices/data-analysis.md +401 -0
- package/_conectese/core/best-practices/email-newsletter.md +118 -0
- package/_conectese/core/best-practices/email-sales.md +110 -0
- package/_conectese/core/best-practices/image-design.md +348 -0
- package/_conectese/core/best-practices/instagram-feed.md +235 -0
- package/_conectese/core/best-practices/instagram-reels.md +112 -0
- package/_conectese/core/best-practices/instagram-stories.md +107 -0
- package/_conectese/core/best-practices/linkedin-article.md +116 -0
- package/_conectese/core/best-practices/linkedin-post.md +121 -0
- package/_conectese/core/best-practices/researching.md +349 -0
- package/_conectese/core/best-practices/review.md +269 -0
- package/_conectese/core/best-practices/social-networks-publishing.md +294 -0
- package/_conectese/core/best-practices/strategist.md +344 -0
- package/_conectese/core/best-practices/technical-writing.md +365 -0
- package/_conectese/core/best-practices/twitter-post.md +105 -0
- package/_conectese/core/best-practices/twitter-thread.md +122 -0
- package/_conectese/core/best-practices/whatsapp-broadcast.md +107 -0
- package/_conectese/core/best-practices/youtube-script.md +122 -0
- package/_conectese/core/best-practices/youtube-shorts.md +112 -0
- package/_conectese/core/prompts/build.prompt.md +547 -0
- package/_conectese/core/prompts/design.prompt.md +469 -0
- package/_conectese/core/prompts/discovery.prompt.md +269 -0
- package/_conectese/core/prompts/sherlock-instagram.md +123 -0
- package/_conectese/core/prompts/sherlock-linkedin.md +73 -0
- package/_conectese/core/prompts/sherlock-shared.md +684 -0
- package/_conectese/core/prompts/sherlock-twitter.md +78 -0
- package/_conectese/core/prompts/sherlock-youtube.md +85 -0
- package/_conectese/core/runner.pipeline.md +535 -0
- package/_conectese/core/skills.engine.md +381 -0
- package/agents/data-extractor/AGENT.md +13 -0
- package/agents/direito-adaneiro/AGENT.md +18 -0
- package/agents/direito-administrativo/AGENT.md +18 -0
- package/agents/direito-aeroporta-rio/AGENT.md +18 -0
- package/agents/direito-agra-rio/AGENT.md +18 -0
- package/agents/direito-ambiental/AGENT.md +18 -0
- package/agents/direito-banca-rio/AGENT.md +18 -0
- package/agents/direito-civil/AGENT.md +18 -0
- package/agents/direito-constitcional/AGENT.md +18 -0
- package/agents/direito-da-crianc-a-e-do-adolescente-eca/AGENT.md +18 -0
- package/agents/direito-da-propriedade-intelectal/AGENT.md +18 -0
- package/agents/direito-de-ami-lia/AGENT.md +18 -0
- package/agents/direito-de-tra-nsito/AGENT.md +18 -0
- package/agents/direito-desportivo/AGENT.md +18 -0
- package/agents/direito-digital/AGENT.md +18 -0
- package/agents/direito-do-consmidor/AGENT.md +18 -0
- package/agents/direito-do-trabalho/AGENT.md +18 -0
- package/agents/direito-econo-mico/AGENT.md +18 -0
- package/agents/direito-eleitoral/AGENT.md +18 -0
- package/agents/direito-empresarial/AGENT.md +18 -0
- package/agents/direito-imobilia-rio/AGENT.md +18 -0
- package/agents/direito-inanceiro/AGENT.md +18 -0
- package/agents/direito-internacional/AGENT.md +18 -0
- package/agents/direito-mari-timo/AGENT.md +18 -0
- package/agents/direito-me-dico-e-da-sa-de/AGENT.md +18 -0
- package/agents/direito-militar/AGENT.md +18 -0
- package/agents/direito-ndia-rio/AGENT.md +18 -0
- package/agents/direito-notarial-e-registral/AGENT.md +18 -0
- package/agents/direito-penal/AGENT.md +18 -0
- package/agents/direito-previdencia-rio/AGENT.md +18 -0
- package/agents/direito-processal-civil/AGENT.md +18 -0
- package/agents/direito-processal-do-trabalho/AGENT.md +18 -0
- package/agents/direito-processal-militar/AGENT.md +18 -0
- package/agents/direito-processal-penal/AGENT.md +18 -0
- package/agents/direito-rbani-stico/AGENT.md +18 -0
- package/agents/direito-secrita-rio/AGENT.md +18 -0
- package/agents/direito-sindical/AGENT.md +18 -0
- package/agents/direito-societa-rio/AGENT.md +18 -0
- package/agents/direito-tribta-rio/AGENT.md +18 -0
- package/agents/direitos-hmanos/AGENT.md +18 -0
- package/agents/legal-analyst/AGENT.md +16 -0
- package/agents/legal-synthesizer/AGENT.md +13 -0
- package/agents/lgpd-anonymizer/AGENT.md +14 -0
- package/agents/lgpd-restorer/AGENT.md +14 -0
- package/agents/task-router/AGENT.md +13 -0
- package/bin/conectese.js +73 -0
- package/dashboard/index.html +12 -0
- package/dashboard/package-lock.json +1971 -0
- package/dashboard/package.json +28 -0
- package/dashboard/public/assets/avatars/Female1_1wave.png +0 -0
- package/dashboard/public/assets/avatars/Female1_2wave.png +0 -0
- package/dashboard/public/assets/avatars/Female1_blink.png +0 -0
- package/dashboard/public/assets/avatars/Female1_talk.png +0 -0
- package/dashboard/public/assets/avatars/Female2_1wave.png +0 -0
- package/dashboard/public/assets/avatars/Female2_2wave.png +0 -0
- package/dashboard/public/assets/avatars/Female2_blink.png +0 -0
- package/dashboard/public/assets/avatars/Female2_talk.png +0 -0
- package/dashboard/public/assets/avatars/Female3_blink.png +0 -0
- package/dashboard/public/assets/avatars/Female3_talk.png +0 -0
- package/dashboard/public/assets/avatars/Female3_wave.png +0 -0
- package/dashboard/public/assets/avatars/Female4_blink.png +0 -0
- package/dashboard/public/assets/avatars/Female4_talk.png +0 -0
- package/dashboard/public/assets/avatars/Female4_wave.png +0 -0
- package/dashboard/public/assets/avatars/Female5_blink.png +0 -0
- package/dashboard/public/assets/avatars/Female5_talk.png +0 -0
- package/dashboard/public/assets/avatars/Female5_wave.png +0 -0
- package/dashboard/public/assets/avatars/Female6_blink.png +0 -0
- package/dashboard/public/assets/avatars/Female6_talk.png +0 -0
- package/dashboard/public/assets/avatars/Female6_wave.png +0 -0
- package/dashboard/public/assets/avatars/Male1_1wave.png +0 -0
- package/dashboard/public/assets/avatars/Male1_2wave.png +0 -0
- package/dashboard/public/assets/avatars/Male1_blink.png +0 -0
- package/dashboard/public/assets/avatars/Male1_talk.png +0 -0
- package/dashboard/public/assets/avatars/Male2_1wave.png +0 -0
- package/dashboard/public/assets/avatars/Male2_2wave.png +0 -0
- package/dashboard/public/assets/avatars/Male2_blink.png +0 -0
- package/dashboard/public/assets/avatars/Male2_talk.png +0 -0
- package/dashboard/public/assets/avatars/Male3_blink.png +0 -0
- package/dashboard/public/assets/avatars/Male3_talk.png +0 -0
- package/dashboard/public/assets/avatars/Male3_wave.png +0 -0
- package/dashboard/public/assets/avatars/Male4_blink.png +0 -0
- package/dashboard/public/assets/avatars/Male4_talk.png +0 -0
- package/dashboard/public/assets/avatars/Male4_wave.png +0 -0
- package/dashboard/public/assets/desks/desktop_set_black_down.png +0 -0
- package/dashboard/public/assets/desks/desktop_set_black_down_coding-1.png +0 -0
- package/dashboard/public/assets/desks/desktop_set_black_down_coding.png +0 -0
- package/dashboard/public/assets/desks/desktop_set_black_up.png +0 -0
- package/dashboard/public/assets/desks/desktop_set_white_down.png +0 -0
- package/dashboard/public/assets/desks/desktop_set_white_down_coding-1.png +0 -0
- package/dashboard/public/assets/desks/desktop_set_white_down_coding.png +0 -0
- package/dashboard/public/assets/desks/desktop_set_white_up.png +0 -0
- package/dashboard/public/assets/furniture/armchair_tan.png +0 -0
- package/dashboard/public/assets/furniture/armchair_tan_down.png +0 -0
- package/dashboard/public/assets/furniture/backpack_blue.png +0 -0
- package/dashboard/public/assets/furniture/backpack_red.png +0 -0
- package/dashboard/public/assets/furniture/blinds.png +0 -0
- package/dashboard/public/assets/furniture/blinds_large_closed_white.png +0 -0
- package/dashboard/public/assets/furniture/bookshelf.png +0 -0
- package/dashboard/public/assets/furniture/bookshelf_purple_tall.png +0 -0
- package/dashboard/public/assets/furniture/bulletin_board.png +0 -0
- package/dashboard/public/assets/furniture/clock.png +0 -0
- package/dashboard/public/assets/furniture/coffee_mug.png +0 -0
- package/dashboard/public/assets/furniture/coffee_mug_blue.png +0 -0
- package/dashboard/public/assets/furniture/coffee_table.png +0 -0
- package/dashboard/public/assets/furniture/coffeepot_right.png +0 -0
- package/dashboard/public/assets/furniture/coffeetable_black_horizontal.png +0 -0
- package/dashboard/public/assets/furniture/couch.png +0 -0
- package/dashboard/public/assets/furniture/couch_tan_down.png +0 -0
- package/dashboard/public/assets/furniture/cushion_blue.png +0 -0
- package/dashboard/public/assets/furniture/cushion_tan.png +0 -0
- package/dashboard/public/assets/furniture/desk_wood.png +0 -0
- package/dashboard/public/assets/furniture/fancy_rug.png +0 -0
- package/dashboard/public/assets/furniture/fancy_rug_wide.png +0 -0
- package/dashboard/public/assets/furniture/flowers1.png +0 -0
- package/dashboard/public/assets/furniture/flowers2.png +0 -0
- package/dashboard/public/assets/furniture/lamp_tan.png +0 -0
- package/dashboard/public/assets/furniture/lantern.png +0 -0
- package/dashboard/public/assets/furniture/monstera.png +0 -0
- package/dashboard/public/assets/furniture/monstera_small.png +0 -0
- package/dashboard/public/assets/furniture/picture_frame.png +0 -0
- package/dashboard/public/assets/furniture/plant1.png +0 -0
- package/dashboard/public/assets/furniture/plant2.png +0 -0
- package/dashboard/public/assets/furniture/plant3.png +0 -0
- package/dashboard/public/assets/furniture/plant_poof.png +0 -0
- package/dashboard/public/assets/furniture/plant_spindly.png +0 -0
- package/dashboard/public/assets/furniture/poster_blue.png +0 -0
- package/dashboard/public/assets/furniture/rug.png +0 -0
- package/dashboard/public/assets/furniture/succulent_blue.png +0 -0
- package/dashboard/public/assets/furniture/succulent_green.png +0 -0
- package/dashboard/public/assets/furniture/treasurechest_closed_gold.png +0 -0
- package/dashboard/public/assets/furniture/water_cooler_better.png +0 -0
- package/dashboard/public/assets/furniture/whiteboard.png +0 -0
- package/dashboard/public/assets/furniture/whiteboard_stand_graph.png +0 -0
- package/dashboard/public/assets/furniture/window_blinds_open.png +0 -0
- package/dashboard/src/App.tsx +46 -0
- package/dashboard/src/components/SquadCard.tsx +47 -0
- package/dashboard/src/components/SquadSelector.tsx +61 -0
- package/dashboard/src/components/StatusBadge.tsx +32 -0
- package/dashboard/src/components/StatusBar.tsx +97 -0
- package/dashboard/src/hooks/useSquadSocket.ts +135 -0
- package/dashboard/src/lib/formatTime.ts +16 -0
- package/dashboard/src/lib/normalizeState.ts +25 -0
- package/dashboard/src/main.tsx +10 -0
- package/dashboard/src/office/AgentSprite.ts +241 -0
- package/dashboard/src/office/OfficeScene.ts +153 -0
- package/dashboard/src/office/PhaserGame.tsx +80 -0
- package/dashboard/src/office/RoomBuilder.ts +190 -0
- package/dashboard/src/office/assetKeys.ts +150 -0
- package/dashboard/src/office/palette.ts +32 -0
- package/dashboard/src/plugin/squadWatcher.ts +233 -0
- package/dashboard/src/store/useSquadStore.ts +56 -0
- package/dashboard/src/styles/globals.css +36 -0
- package/dashboard/src/types/state.ts +63 -0
- package/dashboard/src/vite-env.d.ts +1 -0
- package/dashboard/test-results/.last-run.json +4 -0
- package/dashboard/tsconfig.json +24 -0
- package/dashboard/tsconfig.tsbuildinfo +1 -0
- package/dashboard/vite.config.ts +13 -0
- package/package.json +53 -0
- package/skills/README.md +63 -0
- package/skills/apify/SKILL.md +55 -0
- package/skills/blotato/SKILL.md +63 -0
- package/skills/canva/SKILL.md +60 -0
- package/skills/conectese-agent-creator/SKILL.md +192 -0
- package/skills/conectese-skill-creator/SKILL.md +407 -0
- package/skills/conectese-skill-creator/agents/analyzer.md +274 -0
- package/skills/conectese-skill-creator/agents/comparator.md +202 -0
- package/skills/conectese-skill-creator/agents/grader.md +223 -0
- package/skills/conectese-skill-creator/assets/eval_review.html +146 -0
- package/skills/conectese-skill-creator/eval-viewer/generate_review.py +471 -0
- package/skills/conectese-skill-creator/eval-viewer/viewer.html +1325 -0
- package/skills/conectese-skill-creator/references/schemas.md +430 -0
- package/skills/conectese-skill-creator/references/skill-format.md +235 -0
- package/skills/conectese-skill-creator/scripts/__init__.py +0 -0
- package/skills/conectese-skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/skills/conectese-skill-creator/scripts/quick_validate.py +103 -0
- package/skills/conectese-skill-creator/scripts/run_eval.py +310 -0
- package/skills/conectese-skill-creator/scripts/utils.py +47 -0
- package/skills/image-ai-generator/SKILL.md +124 -0
- package/skills/image-ai-generator/scripts/generate.py +175 -0
- package/skills/image-creator/SKILL.md +155 -0
- package/skills/image-fetcher/SKILL.md +91 -0
- package/skills/instagram-publisher/SKILL.md +119 -0
- package/skills/instagram-publisher/scripts/publish.js +165 -0
- package/skills/resend/SKILL.md +80 -0
- package/skills/template-designer/SKILL.md +201 -0
- package/skills/template-designer/base-templates/model-a.html +27 -0
- package/skills/template-designer/base-templates/model-b.html +31 -0
- package/skills/template-designer/base-templates/model-c.html +42 -0
- package/src/agents-cli.js +158 -0
- package/src/agents.js +134 -0
- package/src/i18n.js +48 -0
- package/src/init.js +341 -0
- package/src/locales/en.json +73 -0
- package/src/locales/es.json +72 -0
- package/src/locales/pt-BR.json +72 -0
- package/src/logger.js +38 -0
- package/src/prompt.js +46 -0
- package/src/readme/README.md +119 -0
- package/src/runs.js +90 -0
- package/src/skills-cli.js +157 -0
- package/src/skills.js +146 -0
- package/src/update.js +169 -0
- package/templates/_conectese/.conectese-version +1 -0
- package/templates/_conectese/_investigations/.gitkeep +0 -0
- package/templates/ide-templates/antigravity/.agent/rules/conectese.md +55 -0
- package/templates/ide-templates/antigravity/.agent/workflows/conectese.md +102 -0
- package/templates/ide-templates/claude-code/.claude/skills/conectese/SKILL.md +182 -0
- package/templates/ide-templates/claude-code/.mcp.json +8 -0
- package/templates/ide-templates/claude-code/CLAUDE.md +43 -0
- package/templates/ide-templates/codex/.agents/skills/conectese/SKILL.md +6 -0
- package/templates/ide-templates/codex/AGENTS.md +105 -0
- package/templates/ide-templates/cursor/.cursor/commands/conectese.md +9 -0
- package/templates/ide-templates/cursor/.cursor/mcp.json +8 -0
- package/templates/ide-templates/cursor/.cursor/rules/conectese.mdc +48 -0
- package/templates/ide-templates/cursor/.cursorignore +3 -0
- package/templates/ide-templates/opencode/.opencode/commands/conectese.md +9 -0
- package/templates/ide-templates/opencode/AGENTS.md +105 -0
- package/templates/ide-templates/vscode-copilot/.github/prompts/conectese.prompt.md +201 -0
- package/templates/ide-templates/vscode-copilot/.vscode/mcp.json +8 -0
- package/templates/ide-templates/vscode-copilot/.vscode/settings.json +3 -0
- package/templates/package.json +8 -0
- package/templates/squads/.gitkeep +0 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Conectese
|
|
2
|
+
|
|
3
|
+
Crie squads de agentes de IA que trabalham juntos — direto do seu IDE.
|
|
4
|
+
|
|
5
|
+
## Como Usar
|
|
6
|
+
|
|
7
|
+
Abra esta pasta no seu IDE e digite:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
/conectese
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Isso abre o menu principal. De lá você pode criar squads, executá-los e mais.
|
|
14
|
+
|
|
15
|
+
Você também pode ser direto — descreva o que quer em linguagem natural:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
/conectese crie um squad para escrever posts no LinkedIn sobre IA
|
|
19
|
+
/conectese execute o squad meu-squad
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Criar um Squad
|
|
23
|
+
|
|
24
|
+
Digite `/conectese` e escolha "Criar squad" no menu, ou seja direto:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
/conectese crie um squad para [o que você precisa]
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
O Arquiteto fará algumas perguntas, projetará o squad e configurará tudo automaticamente.
|
|
31
|
+
|
|
32
|
+
## Executar um Squad
|
|
33
|
+
|
|
34
|
+
Digite `/conectese` e escolha "Executar squad" no menu, ou seja direto:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
/conectese execute o squad <nome-do-squad>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
O squad executa automaticamente, pausando apenas nos checkpoints de decisão.
|
|
41
|
+
|
|
42
|
+
## Escritório Virtual
|
|
43
|
+
|
|
44
|
+
O Escritório Virtual é uma interface visual 2D que mostra seus agentes trabalhando em tempo real.
|
|
45
|
+
|
|
46
|
+
**Passo 1 — Gere o dashboard** (no seu IDE):
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
/conectese dashboard
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Passo 2 — Sirva localmente** (no terminal):
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npx serve squads/<nome-do-squad>/dashboard
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Passo 3 —** Abra `http://localhost:3000` no seu navegador.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
# Conectese (English)
|
|
63
|
+
|
|
64
|
+
Create AI squads that work together — right from your IDE.
|
|
65
|
+
|
|
66
|
+
## How to Use
|
|
67
|
+
|
|
68
|
+
Open this folder in your IDE and type:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
/conectese
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
This opens the main menu. From there you can create squads, run them, and more.
|
|
75
|
+
|
|
76
|
+
You can also be direct — describe what you want in plain language:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
/conectese create a squad for writing LinkedIn posts about AI
|
|
80
|
+
/conectese run my-squad
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Create a Squad
|
|
84
|
+
|
|
85
|
+
Type `/conectese` and choose "Create squad" from the menu, or be direct:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
/conectese create a squad for [what you need]
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The Architect will ask a few questions, design the squad, and set everything up automatically.
|
|
92
|
+
|
|
93
|
+
## Run a Squad
|
|
94
|
+
|
|
95
|
+
Type `/conectese` and choose "Run squad" from the menu, or be direct:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
/conectese run the <squad-name> squad
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The squad runs automatically, pausing only at decision checkpoints.
|
|
102
|
+
|
|
103
|
+
## Virtual Office
|
|
104
|
+
|
|
105
|
+
The Virtual Office is a 2D visual interface that shows your agents working in real time.
|
|
106
|
+
|
|
107
|
+
**Step 1 — Generate the dashboard** (in your IDE):
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
/conectese dashboard
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Step 2 — Serve it locally** (in terminal):
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
npx serve squads/<squad-name>/dashboard
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Step 3 —** Open `http://localhost:3000` in your browser.
|
package/src/runs.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { readdir, readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
const MAX_RUNS = 20;
|
|
5
|
+
|
|
6
|
+
export async function listRuns(squadName, targetDir = process.cwd()) {
|
|
7
|
+
const squadsDir = join(targetDir, 'squads');
|
|
8
|
+
let squadNames;
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
if (squadName) {
|
|
12
|
+
squadNames = [squadName];
|
|
13
|
+
} else {
|
|
14
|
+
const entries = await readdir(squadsDir, { withFileTypes: true });
|
|
15
|
+
squadNames = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
16
|
+
}
|
|
17
|
+
} catch {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const runs = [];
|
|
22
|
+
|
|
23
|
+
for (const name of squadNames) {
|
|
24
|
+
const outputDir = join(squadsDir, name, 'output');
|
|
25
|
+
let runDirs;
|
|
26
|
+
try {
|
|
27
|
+
const entries = await readdir(outputDir, { withFileTypes: true });
|
|
28
|
+
runDirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
29
|
+
} catch {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
for (const runId of runDirs) {
|
|
34
|
+
const run = { squad: name, runId, status: 'unknown', steps: null, duration: null };
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const raw = await readFile(join(outputDir, runId, 'state.json'), 'utf-8');
|
|
38
|
+
const state = JSON.parse(raw);
|
|
39
|
+
run.status = state.status || 'unknown';
|
|
40
|
+
if (state.step) run.steps = `${state.step.current}/${state.step.total}`;
|
|
41
|
+
if (state.startedAt && (state.completedAt || state.failedAt)) {
|
|
42
|
+
const start = new Date(state.startedAt).getTime();
|
|
43
|
+
const end = new Date(state.completedAt || state.failedAt).getTime();
|
|
44
|
+
run.duration = formatDuration(end - start);
|
|
45
|
+
}
|
|
46
|
+
} catch {
|
|
47
|
+
// No state.json or malformed — keep defaults
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
runs.push(run);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
runs.sort((a, b) => b.runId.localeCompare(a.runId));
|
|
55
|
+
return runs.slice(0, MAX_RUNS);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function formatDuration(ms) {
|
|
59
|
+
if (ms <= 0) return '0s';
|
|
60
|
+
const seconds = Math.floor(ms / 1000);
|
|
61
|
+
const hours = Math.floor(seconds / 3600);
|
|
62
|
+
const minutes = Math.floor((seconds % 3600) / 60);
|
|
63
|
+
const secs = seconds % 60;
|
|
64
|
+
|
|
65
|
+
if (hours > 0) return `${hours}h ${minutes}m`;
|
|
66
|
+
if (minutes > 0) return `${minutes}m ${secs}s`;
|
|
67
|
+
return `${secs}s`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function printRuns(runs) {
|
|
71
|
+
if (runs.length === 0) {
|
|
72
|
+
console.log('\n No runs found.\n');
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let currentSquad = null;
|
|
77
|
+
for (const run of runs) {
|
|
78
|
+
if (run.squad !== currentSquad) {
|
|
79
|
+
currentSquad = run.squad;
|
|
80
|
+
console.log(`\n ${currentSquad}`);
|
|
81
|
+
console.log(' ' + '─'.repeat(50));
|
|
82
|
+
}
|
|
83
|
+
const parts = [` ${run.runId}`];
|
|
84
|
+
parts.push(`[${run.status}]`);
|
|
85
|
+
if (run.steps) parts.push(`${run.steps} steps`);
|
|
86
|
+
if (run.duration) parts.push(run.duration);
|
|
87
|
+
console.log(parts.join(' '));
|
|
88
|
+
}
|
|
89
|
+
console.log();
|
|
90
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { createInterface } from 'node:readline';
|
|
2
|
+
import { stat } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { listInstalled, installSkill, removeSkill, getSkillMeta, getLocalizedDescription } from './skills.js';
|
|
5
|
+
import { loadLocale, t, getLocaleCode } from './i18n.js';
|
|
6
|
+
import { loadSavedLocale } from './init.js';
|
|
7
|
+
import { logEvent } from './logger.js';
|
|
8
|
+
|
|
9
|
+
async function confirm(question) {
|
|
10
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
11
|
+
return new Promise((resolve) => {
|
|
12
|
+
rl.question(question, (answer) => {
|
|
13
|
+
rl.close();
|
|
14
|
+
resolve(answer.trim().toLowerCase());
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function skillsCli(subcommand, args, targetDir) {
|
|
20
|
+
// Require initialized project
|
|
21
|
+
try {
|
|
22
|
+
await stat(join(targetDir, '_conectese'));
|
|
23
|
+
} catch {
|
|
24
|
+
await loadLocale('English');
|
|
25
|
+
console.log(`\n ${t('skillsNotInitialized')}\n`);
|
|
26
|
+
return { success: false };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
await loadSavedLocale(targetDir);
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
if (subcommand === 'list' || !subcommand) {
|
|
33
|
+
await runList(targetDir);
|
|
34
|
+
} else if (subcommand === 'install') {
|
|
35
|
+
const installed = await runInstall(args[0], targetDir);
|
|
36
|
+
if (installed === false) return { success: false };
|
|
37
|
+
} else if (subcommand === 'remove') {
|
|
38
|
+
const removed = await runRemove(args[0], targetDir);
|
|
39
|
+
if (removed === false) return { success: false };
|
|
40
|
+
} else if (subcommand === 'update') {
|
|
41
|
+
await runUpdate(targetDir);
|
|
42
|
+
} else if (subcommand === 'update-one') {
|
|
43
|
+
await runUpdateOne(args[0], targetDir);
|
|
44
|
+
} else {
|
|
45
|
+
console.log(`\n ${t('skillsUnknownCommand', { cmd: subcommand })}\n`);
|
|
46
|
+
return { success: false };
|
|
47
|
+
}
|
|
48
|
+
} catch (err) {
|
|
49
|
+
console.log(`\n ${t('skillsError', { message: err.message })}\n`);
|
|
50
|
+
return { success: false };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return { success: true };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function runList(targetDir) {
|
|
57
|
+
console.log(`\n Conectese Skills\n`);
|
|
58
|
+
|
|
59
|
+
const installed = await listInstalled(targetDir);
|
|
60
|
+
|
|
61
|
+
if (installed.length > 0) {
|
|
62
|
+
console.log(` ${t('skillsInstalledHeader')}`);
|
|
63
|
+
for (const id of installed) {
|
|
64
|
+
const meta = await getSkillMeta(id);
|
|
65
|
+
if (meta) {
|
|
66
|
+
const desc = getLocalizedDescription(meta, getLocaleCode());
|
|
67
|
+
const parts = [meta.name];
|
|
68
|
+
if (meta.type) parts.push(`(${meta.type})`);
|
|
69
|
+
parts.push(`- ${desc.split('.')[0]}`);
|
|
70
|
+
console.log(` ${parts.join(' ')}`);
|
|
71
|
+
} else {
|
|
72
|
+
console.log(` ${id}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
console.log(` ${t('skillsNoneInstalled')}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
console.log(`\n Browse available skills at: https://github.com/renatoasse/conectese/tree/main/skills\n`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function runInstall(id, targetDir) {
|
|
83
|
+
if (!id) {
|
|
84
|
+
console.log('\n Usage: conectese install <id>\n');
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const installed = await listInstalled(targetDir);
|
|
89
|
+
if (installed.includes(id)) {
|
|
90
|
+
const answer = await confirm(`\n ${t('skillsAlreadyInstalled', { id })}`);
|
|
91
|
+
// Accept 'y' (English) or 's' (Portuguese "sim") as affirmative answers
|
|
92
|
+
if (answer !== 'y' && answer !== 's') return false;
|
|
93
|
+
console.log(` ${t('skillsInstalling', { id })}`);
|
|
94
|
+
await installSkill(id, targetDir);
|
|
95
|
+
console.log(` ${t('skillsReinstalled', { id })}\n`);
|
|
96
|
+
await logEvent('skill:install', { name: id, reinstall: true }, targetDir);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
console.log(`\n ${t('skillsInstalling', { id })}`);
|
|
101
|
+
await installSkill(id, targetDir);
|
|
102
|
+
console.log(` ${t('skillsInstalled', { id })}\n`);
|
|
103
|
+
await logEvent('skill:install', { name: id }, targetDir);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function runRemove(id, targetDir) {
|
|
107
|
+
if (!id) {
|
|
108
|
+
console.log('\n Usage: conectese uninstall <id>\n');
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const installed = await listInstalled(targetDir);
|
|
113
|
+
if (!installed.includes(id)) {
|
|
114
|
+
console.log(`\n ${t('skillsNotInstalled', { id })}\n`);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
console.log(`\n ${t('skillsRemoving', { id })}`);
|
|
119
|
+
await removeSkill(id, targetDir);
|
|
120
|
+
await logEvent('skill:remove', { name: id }, targetDir);
|
|
121
|
+
console.log(` ${t('skillsRemoved', { id })}\n`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function runUpdate(targetDir) {
|
|
125
|
+
const installed = await listInstalled(targetDir);
|
|
126
|
+
if (installed.length === 0) {
|
|
127
|
+
console.log(`\n ${t('skillsUpdateNone')}\n`);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
console.log(`\n ${t('skillsUpdating')}`);
|
|
132
|
+
for (const id of installed) {
|
|
133
|
+
console.log(` ${t('skillsInstalling', { id })}`);
|
|
134
|
+
await installSkill(id, targetDir);
|
|
135
|
+
console.log(` ${t('skillsInstalled', { id })}`);
|
|
136
|
+
}
|
|
137
|
+
await logEvent('skill:update', { count: installed.length }, targetDir);
|
|
138
|
+
console.log(`\n ${t('skillsUpdateDone', { count: installed.length })}\n`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async function runUpdateOne(id, targetDir) {
|
|
142
|
+
if (!id) {
|
|
143
|
+
console.log('\n Usage: conectese update <name>\n');
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const installed = await listInstalled(targetDir);
|
|
148
|
+
if (!installed.includes(id)) {
|
|
149
|
+
console.log(`\n ${t('skillsNotInstalled', { id })}\n`);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
console.log(`\n ${t('skillsInstalling', { id })}`);
|
|
154
|
+
await installSkill(id, targetDir);
|
|
155
|
+
await logEvent('skill:update', { name: id }, targetDir);
|
|
156
|
+
console.log(` ${t('skillsInstalled', { id })}\n`);
|
|
157
|
+
}
|
package/src/skills.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { cp, readdir, readFile, rm, stat } from 'node:fs/promises';
|
|
2
|
+
import { dirname, join, resolve, sep } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const BUNDLED_SKILLS_DIR = join(__dirname, '..', 'skills');
|
|
7
|
+
|
|
8
|
+
const metaCache = new Map();
|
|
9
|
+
|
|
10
|
+
export async function listInstalled(targetDir) {
|
|
11
|
+
try {
|
|
12
|
+
const skillsDir = join(targetDir, 'skills');
|
|
13
|
+
const entries = await readdir(skillsDir, { withFileTypes: true });
|
|
14
|
+
return entries
|
|
15
|
+
.filter((e) => e.isDirectory() && e.name !== 'conectese-skill-creator')
|
|
16
|
+
.map((e) => e.name);
|
|
17
|
+
} catch (err) {
|
|
18
|
+
if (err.code === 'ENOENT') return [];
|
|
19
|
+
throw err;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function listAvailable() {
|
|
24
|
+
try {
|
|
25
|
+
const entries = await readdir(BUNDLED_SKILLS_DIR, { withFileTypes: true });
|
|
26
|
+
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
27
|
+
} catch {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function getSkillMeta(id) {
|
|
33
|
+
if (metaCache.has(id)) return metaCache.get(id);
|
|
34
|
+
try {
|
|
35
|
+
const raw = await readFile(join(BUNDLED_SKILLS_DIR, id, 'SKILL.md'), 'utf-8');
|
|
36
|
+
const content = raw.replace(/\r\n/g, '\n');
|
|
37
|
+
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
38
|
+
if (!fmMatch) return { name: id, description: '', descriptions: {}, type: '', env: [] };
|
|
39
|
+
|
|
40
|
+
const fm = fmMatch[1];
|
|
41
|
+
const name = fm.match(/^name:\s*(.+)$/m)?.[1]?.trim() || id;
|
|
42
|
+
const type = fm.match(/^type:\s*(.+)$/m)?.[1]?.trim() || '';
|
|
43
|
+
|
|
44
|
+
// description may use YAML folded scalar (>)
|
|
45
|
+
let description = '';
|
|
46
|
+
const descBlock = fm.match(/^description:\s*>\s*\n((?:\s{2,}.+\n?)+)/m);
|
|
47
|
+
if (descBlock) {
|
|
48
|
+
description = descBlock[1].replace(/\n\s*/g, ' ').trim();
|
|
49
|
+
} else {
|
|
50
|
+
const descInline = fm.match(/^description:\s*(.+)$/m);
|
|
51
|
+
if (descInline) description = descInline[1].trim();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// localized descriptions: description_pt-BR, description_es, etc.
|
|
55
|
+
const descriptions = {};
|
|
56
|
+
for (const code of ['pt-BR', 'es']) {
|
|
57
|
+
const key = `description_${code}`;
|
|
58
|
+
// folded scalar
|
|
59
|
+
const blockMatch = fm.match(new RegExp(`^${key}:\\s*>\\s*\\n((?:\\s{2,}.+\\n?)+)`, 'm'));
|
|
60
|
+
if (blockMatch) {
|
|
61
|
+
descriptions[code] = blockMatch[1].replace(/\n\s*/g, ' ').trim();
|
|
62
|
+
} else {
|
|
63
|
+
// inline
|
|
64
|
+
const inlineMatch = fm.match(new RegExp(`^${key}:\\s*(.+)$`, 'm'));
|
|
65
|
+
if (inlineMatch) descriptions[code] = inlineMatch[1].trim();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// env is a YAML list: lines starting with " - "
|
|
70
|
+
const env = [];
|
|
71
|
+
const envSection = fm.match(/^env:\s*\n((?:\s+-\s+.+\n?)+)/m);
|
|
72
|
+
if (envSection) {
|
|
73
|
+
for (const line of envSection[1].split('\n')) {
|
|
74
|
+
const item = line.match(/^\s+-\s+(.+)/);
|
|
75
|
+
if (item) env.push(item[1].trim());
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const result = { name, description, descriptions, type, env };
|
|
80
|
+
metaCache.set(id, result);
|
|
81
|
+
return result;
|
|
82
|
+
} catch (err) {
|
|
83
|
+
if (err.code === 'ENOENT') {
|
|
84
|
+
metaCache.set(id, null);
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
throw err;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function validateSkillId(id) {
|
|
92
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(id)) {
|
|
93
|
+
throw new Error(`Invalid skill id: '${id}'`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export async function installSkill(id, targetDir) {
|
|
98
|
+
validateSkillId(id);
|
|
99
|
+
const srcDir = join(BUNDLED_SKILLS_DIR, id);
|
|
100
|
+
try {
|
|
101
|
+
await stat(srcDir);
|
|
102
|
+
} catch (err) {
|
|
103
|
+
if (err.code === 'ENOENT') throw new Error(`Skill '${id}' not found in registry`, { cause: err });
|
|
104
|
+
throw err;
|
|
105
|
+
}
|
|
106
|
+
const destDir = join(targetDir, 'skills', id);
|
|
107
|
+
const resolvedSrc = resolve(srcDir);
|
|
108
|
+
const resolvedDest = resolve(destDir);
|
|
109
|
+
if (resolvedSrc === resolvedDest || resolvedDest.startsWith(resolvedSrc + sep)) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
await cp(srcDir, destDir, { recursive: true });
|
|
113
|
+
metaCache.delete(id);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export async function removeSkill(id, targetDir) {
|
|
117
|
+
validateSkillId(id);
|
|
118
|
+
const skillDir = join(targetDir, 'skills', id);
|
|
119
|
+
await rm(skillDir, { recursive: true, force: true });
|
|
120
|
+
metaCache.delete(id);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function clearMetaCache() {
|
|
124
|
+
metaCache.clear();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export async function getSkillVersion(id, targetDir) {
|
|
128
|
+
try {
|
|
129
|
+
const skillPath = join(targetDir, 'skills', id, 'SKILL.md');
|
|
130
|
+
const content = await readFile(skillPath, 'utf-8');
|
|
131
|
+
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
132
|
+
if (!fmMatch) return null;
|
|
133
|
+
const versionMatch = fmMatch[1].match(/^version:\s*(.+)$/m);
|
|
134
|
+
return versionMatch ? versionMatch[1].trim() : null;
|
|
135
|
+
} catch (err) {
|
|
136
|
+
if (err.code === 'ENOENT') return null;
|
|
137
|
+
throw err;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function getLocalizedDescription(meta, localeCode) {
|
|
142
|
+
if (localeCode && localeCode !== 'en' && meta.descriptions?.[localeCode]) {
|
|
143
|
+
return meta.descriptions[localeCode];
|
|
144
|
+
}
|
|
145
|
+
return meta.description;
|
|
146
|
+
}
|
package/src/update.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { cp, mkdir, readFile, stat } from 'node:fs/promises';
|
|
2
|
+
import { join, dirname, relative } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { loadLocale, t } from './i18n.js';
|
|
5
|
+
import { getTemplateEntries, loadSavedLocale, copyCanonicalSources } from './init.js';
|
|
6
|
+
import { listAvailable as listAvailableSkills, listInstalled as listInstalledSkills, installSkill, getSkillMeta } from './skills.js';
|
|
7
|
+
import { logEvent } from './logger.js';
|
|
8
|
+
|
|
9
|
+
async function loadSavedIdes(targetDir) {
|
|
10
|
+
try {
|
|
11
|
+
const prefsPath = join(targetDir, '_conectese', '_memory', 'preferences.md');
|
|
12
|
+
const content = await readFile(prefsPath, 'utf-8');
|
|
13
|
+
const match = content.match(/\*\*IDEs:\*\*\s*(.+)/);
|
|
14
|
+
if (match) {
|
|
15
|
+
return match[1].trim().split(/,\s*/);
|
|
16
|
+
}
|
|
17
|
+
} catch {
|
|
18
|
+
// No preferences file
|
|
19
|
+
}
|
|
20
|
+
return ['claude-code'];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
24
|
+
const TEMPLATES_DIR = join(__dirname, '..', 'templates');
|
|
25
|
+
|
|
26
|
+
const PROTECTED_PATHS = [
|
|
27
|
+
'_conectese/_memory',
|
|
28
|
+
'agents',
|
|
29
|
+
'squads',
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
function isProtected(relativePath) {
|
|
33
|
+
const normalized = relativePath.replaceAll('\\', '/');
|
|
34
|
+
return PROTECTED_PATHS.some(
|
|
35
|
+
(p) => normalized === p || normalized.startsWith(p + '/')
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function backupIfExists(destPath) {
|
|
40
|
+
try {
|
|
41
|
+
await stat(destPath);
|
|
42
|
+
const backupPath = destPath + '.bak';
|
|
43
|
+
await cp(destPath, backupPath);
|
|
44
|
+
return true;
|
|
45
|
+
} catch {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export async function update(targetDir) {
|
|
51
|
+
console.log('\n 🔄 Conectese — Update\n');
|
|
52
|
+
|
|
53
|
+
// 1. Check initialized
|
|
54
|
+
try {
|
|
55
|
+
await stat(join(targetDir, '_conectese'));
|
|
56
|
+
} catch {
|
|
57
|
+
await loadLocale('English');
|
|
58
|
+
console.log(` ${t('updateNotInitialized')}`);
|
|
59
|
+
return { success: false };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 2. Load user's locale
|
|
63
|
+
await loadSavedLocale(targetDir);
|
|
64
|
+
|
|
65
|
+
// 3. Read versions
|
|
66
|
+
let currentVersion = null;
|
|
67
|
+
try {
|
|
68
|
+
currentVersion = (
|
|
69
|
+
await readFile(join(targetDir, '_conectese', '.conectese-version'), 'utf-8')
|
|
70
|
+
).trim();
|
|
71
|
+
} catch {
|
|
72
|
+
// Legacy install — no version file
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const newVersion = (
|
|
76
|
+
await readFile(join(TEMPLATES_DIR, '_conectese', '.conectese-version'), 'utf-8')
|
|
77
|
+
).trim();
|
|
78
|
+
|
|
79
|
+
// 4. Announce
|
|
80
|
+
if (currentVersion) {
|
|
81
|
+
console.log(
|
|
82
|
+
` ${t('updateStarting', { old: `v${currentVersion}`, new: `v${newVersion}` })}`
|
|
83
|
+
);
|
|
84
|
+
} else {
|
|
85
|
+
console.log(` ${t('updateStartingUnknown', { new: `v${newVersion}` })}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// 5. Copy common templates, skipping protected paths and ide-templates/
|
|
89
|
+
const entries = await getTemplateEntries(TEMPLATES_DIR);
|
|
90
|
+
let count = 0;
|
|
91
|
+
|
|
92
|
+
for (const entry of entries) {
|
|
93
|
+
const relativePath = relative(TEMPLATES_DIR, entry);
|
|
94
|
+
if (isProtected(relativePath)) continue;
|
|
95
|
+
// Skip ide-templates — handled separately below
|
|
96
|
+
if (relativePath.replaceAll('\\', '/').startsWith('ide-templates/')) continue;
|
|
97
|
+
|
|
98
|
+
const destPath = join(targetDir, relativePath);
|
|
99
|
+
await mkdir(dirname(destPath), { recursive: true });
|
|
100
|
+
const backed = await backupIfExists(destPath);
|
|
101
|
+
await cp(entry, destPath);
|
|
102
|
+
const displayPath = relativePath.replaceAll('\\', '/');
|
|
103
|
+
if (backed) {
|
|
104
|
+
console.log(` ${t('updatedFile', { path: displayPath })} (backup: ${displayPath}.bak)`);
|
|
105
|
+
} else {
|
|
106
|
+
console.log(` ${t('updatedFile', { path: displayPath })}`);
|
|
107
|
+
}
|
|
108
|
+
count++;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 6. Copy IDE-specific templates based on saved preferences
|
|
112
|
+
const ides = await loadSavedIdes(targetDir);
|
|
113
|
+
for (const ide of ides) {
|
|
114
|
+
const ideSrcDir = join(TEMPLATES_DIR, 'ide-templates', ide);
|
|
115
|
+
let ideEntries;
|
|
116
|
+
try {
|
|
117
|
+
ideEntries = await getTemplateEntries(ideSrcDir);
|
|
118
|
+
} catch {
|
|
119
|
+
continue; // no template dir for this IDE
|
|
120
|
+
}
|
|
121
|
+
for (const entry of ideEntries) {
|
|
122
|
+
const relPath = relative(ideSrcDir, entry);
|
|
123
|
+
if (isProtected(relPath)) continue;
|
|
124
|
+
|
|
125
|
+
const destPath = join(targetDir, relPath);
|
|
126
|
+
await mkdir(dirname(destPath), { recursive: true });
|
|
127
|
+
const backed = await backupIfExists(destPath);
|
|
128
|
+
await cp(entry, destPath);
|
|
129
|
+
const displayPath = relPath.replaceAll('\\', '/');
|
|
130
|
+
if (backed) {
|
|
131
|
+
console.log(` ${t('updatedFile', { path: displayPath })} (backup: ${displayPath}.bak)`);
|
|
132
|
+
} else {
|
|
133
|
+
console.log(` ${t('updatedFile', { path: displayPath })}`);
|
|
134
|
+
}
|
|
135
|
+
count++;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// 6a. Copy canonical sources (core, config, dashboard)
|
|
140
|
+
count += await copyCanonicalSources(targetDir, {
|
|
141
|
+
overwrite: true,
|
|
142
|
+
backupFn: backupIfExists,
|
|
143
|
+
protectedFn: isProtected,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// 6b. Install new non-MCP, non-hybrid bundled skills not already present
|
|
147
|
+
const availableSkills = await listAvailableSkills();
|
|
148
|
+
const installedSkills = await listInstalledSkills(targetDir);
|
|
149
|
+
for (const id of availableSkills) {
|
|
150
|
+
if (id === 'conectese-skill-creator') continue;
|
|
151
|
+
if (installedSkills.includes(id)) continue;
|
|
152
|
+
const meta = await getSkillMeta(id);
|
|
153
|
+
if (!meta) continue;
|
|
154
|
+
if (meta.type === 'mcp' || meta.type === 'hybrid') continue;
|
|
155
|
+
await installSkill(id, targetDir);
|
|
156
|
+
console.log(` ${t('createdFile', { path: `skills/${id}/SKILL.md` })}`);
|
|
157
|
+
count++;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// 7. Summary
|
|
161
|
+
console.log(`\n ${t('updateFileCount', { count })}`);
|
|
162
|
+
console.log(` ${t('updatePreserved')}`);
|
|
163
|
+
console.log(` ${t('updateSuccess', { version: `v${newVersion}` })}`);
|
|
164
|
+
console.log(`\n ${t('updateLatestHint')}\n`);
|
|
165
|
+
|
|
166
|
+
await logEvent('update', { from: currentVersion || 'unknown', to: newVersion }, targetDir);
|
|
167
|
+
|
|
168
|
+
return { success: true };
|
|
169
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.1.14
|
|
File without changes
|