@devstroupe/devkit-cli 1.2.0-beta.5 → 1.2.0-beta.6

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.
@@ -0,0 +1,14 @@
1
+ # DT-DevKit backend rules
2
+
3
+ - NestJS CRUD controllers extend `BaseCrudController`.
4
+ - TypeORM repositories extend `BaseRepository`.
5
+ - Use application use cases for simple CRUD; do not add `@nestjs/cqrs` by default.
6
+ - Persistent entities use soft delete. Application hard delete and restore are forbidden.
7
+ - Tenant-scoped repositories use `executionContext.requireTenantId()`.
8
+ - Public filters use a trusted registry and pagination has a maximum limit.
9
+ - Never use unbounded `.find()` or `.getMany()`.
10
+ - Domain and entity layers must not import infrastructure, controllers or modules.
11
+ - TypeORM `synchronize` remains `false`; schema changes require migrations.
12
+ - Cross-module references persist IDs and do not import external infrastructure.
13
+ - Writes plus integration events use Unit of Work and transactional outbox.
14
+
@@ -0,0 +1,8 @@
1
+ # Engineering rules
2
+
3
+ - Prefer the smallest complete change that satisfies the approved specification.
4
+ - Diagnose root causes; do not hide failures with workarounds.
5
+ - Preserve unrelated user changes.
6
+ - Keep durable decisions in the feature techspec or an ADR.
7
+ - A task is complete only with relevant verification evidence.
8
+
@@ -0,0 +1,11 @@
1
+ # DT-DevKit frontend and UI rules
2
+
3
+ - Angular list components extend `BaseListPage`.
4
+ - List templates use `<devkit-table>` and `<devkit-filter>`.
5
+ - Use separate `templateUrl` and `styleUrl`/`styleUrls`; no inline templates or styles.
6
+ - Do not implement polling with `setInterval`, `interval` or repeating `timer`.
7
+ - Reuse local `devkit-*` wrappers before creating a new UI abstraction.
8
+ - Spartan Helm primitives in `libs/ui` belong to the app; do not place business logic in them.
9
+ - Apply Spartan styles through `components.json` and `ds_set_spartan_style`, never by CSS imitation.
10
+ - Protect routes and actions with `devkitPermissionGuard` and `*devkitHasPermission`.
11
+
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: dt-build-ui
3
+ description: Build or modify Angular UI using the DT-DevKit wrappers and project-owned Spartan Helm primitives. Use for pages, forms, lists, dialogs, navigation or Spartan style work.
4
+ ---
5
+
6
+ # Build UI
7
+
8
+ 1. Read `.devstroupe/rules/frontend.md`, `devstroupe.config.ts` and `components.json` when present.
9
+ 2. Call `ds_health` and `ds_get_config`. Bootstrap MCP if unavailable.
10
+ 3. If UI is not initialized, call `ds_init_ui`. Change official style only with `ds_set_spartan_style`.
11
+ 4. Reuse local `devkit-*` wrappers. Add a wrapper only when the application lacks the required abstraction.
12
+ 5. Never emulate a Spartan style with runtime CSS or add business logic to `libs/ui` primitives.
13
+ 6. Keep Angular templates/styles separate, avoid polling and apply RBAC directives/guards.
14
+ 7. Verify build and call `ds_check_architecture`.
15
+
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: dt-create-feature
3
+ description: Create a DevsTroupe feature PRD, techspec and executable task plan. Use when the user asks to plan, specify or break down a feature in a DT-DevKit project.
4
+ ---
5
+
6
+ # Create feature
7
+
8
+ 1. Read `AGENTS.md`, `devstroupe.config.ts` and relevant `.devstroupe/rules/`.
9
+ 2. Call `ds_health`, then `ds_get_config`. If unavailable, activate `dt-mcp-bootstrap` and pause technical execution until MCP is ready.
10
+ 3. Classify the change as trivial, standard or high-risk. A trivial change may use a short change brief; other changes require PRD, techspec and tasks.
11
+ 4. Resolve unclear product decisions with the user before locking the specification.
12
+ 5. Create `.devstroupe/tasks/<slug>/_prd.md`, `_techspec.md` and `_tasks.md` from `.devstroupe/templates/`.
13
+ 6. Tasks must identify MCP operations, code changes, acceptance criteria and verification evidence.
14
+ 7. Do not implement code unless the user also asks for execution.
15
+
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: dt-create-task
3
+ description: Add a concrete executable task to an existing DevsTroupe feature specification. Use when the user asks to create, refine or split a task.
4
+ ---
5
+
6
+ # Create task
7
+
8
+ 1. Locate the feature under `.devstroupe/tasks/` and read its PRD, techspec and current tasks.
9
+ 2. Read the relevant backend/frontend rules and call `ds_get_config`.
10
+ 3. Define one bounded outcome with dependencies, exact scope, acceptance criteria and verification.
11
+ 4. Identify the expected `ds_*` calls. Never prescribe direct CLI fallback for an operation exposed by MCP.
12
+ 5. Append the task without rewriting approved tasks or changing scope silently.
13
+
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: dt-execute-task
3
+ description: Execute a specified DevsTroupe task using the DT-DevKit MCP, generated architecture and Spartan UI. Use when the user asks to implement or complete a task.
4
+ ---
5
+
6
+ # Execute task
7
+
8
+ 1. Read the feature PRD, techspec, task, `devstroupe.config.ts` and relevant rules.
9
+ 2. Call `ds_health` and `ds_get_config` before edits. If MCP is missing, use `dt-mcp-bootstrap`; do not silently use CLI.
10
+ 3. Use MCP operations whenever available: `ds_init_ui`, `ds_generate_crud`, `ds_generate_migration`, `ds_set_spartan_style` and `ds_check_architecture`.
11
+ 4. Edit code directly only for task-specific behavior not covered by a generator. Preserve the DevKit architecture and local UI ownership.
12
+ 5. For UI, reuse `devkit-*` wrappers and the existing Spartan primitives in `libs/ui`.
13
+ 6. Run applicable tests/build and `ds_check_architecture`.
14
+ 7. Update only the task status and evidence after verification succeeds. Report blockers truthfully.
15
+
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: dt-final-verify
3
+ description: Perform the final evidence-based verification of a DevsTroupe task or feature. Use before claiming implementation is complete.
4
+ ---
5
+
6
+ # Final verification
7
+
8
+ 1. Read the approved acceptance criteria and changed files.
9
+ 2. Call `ds_health` and `ds_get_config`.
10
+ 3. Run focused tests, relevant builds, migration checks and `ds_check_architecture` through MCP where exposed.
11
+ 4. Check generated UI against the project-owned Spartan style and DevKit wrappers.
12
+ 5. Record commands/tool calls, results and remaining risks in the task evidence.
13
+ 6. Do not mark complete when a required check failed or did not run.
14
+
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: dt-mcp-bootstrap
3
+ description: Diagnose, install or repair the DT-DevKit MCP integration for Codex, Claude Code, Cursor or Antigravity. Use whenever ds_health or other ds_* tools are unavailable.
4
+ ---
5
+
6
+ # MCP bootstrap
7
+
8
+ 1. Detect the current agent and inspect its project-local MCP configuration.
9
+ 2. Explain that DevKit task execution requires the MCP and request authorization before installing packages or modifying configuration outside the project.
10
+ 3. Prefer the project bootstrap: `devstroupe ai:init --targets <agent>`.
11
+ 4. The expected server is `npx -y @devstroupe/devkit-mcp`, named `devstroupe`.
12
+ 5. Run `devstroupe ai:doctor`, then ask for an agent-session restart if tool discovery is not live.
13
+ 6. Confirm readiness by calling `ds_health` and `ds_get_config`.
14
+ 7. Do not continue the technical task through direct CLI commands merely because MCP discovery failed.
15
+
@@ -0,0 +1,13 @@
1
+ # DevsTroupe AI Workflow
2
+
3
+ Este projeto usa o DT-DevKit e o workflow orientado por especificações da DevsTroupe.
4
+
5
+ - Para mudanças standard ou high-risk, crie PRD, techspec e tasks em `.devstroupe/tasks/<slug>/`.
6
+ - Use as skills `dt-*` instaladas no projeto.
7
+ - Antes de agir, valide o MCP DevKit com `ds_health` e leia o projeto com `ds_get_config`.
8
+ - Ferramentas MCP `ds_*` são obrigatórias quando existe uma operação equivalente.
9
+ - Se o MCP não estiver disponível, use `dt-mcp-bootstrap`; não faça fallback silencioso para a CLI.
10
+ - A CLI pode ser usada diretamente somente para instalar ou reparar o MCP, quando não houver ferramenta MCP equivalente ou por solicitação explícita.
11
+ - Leia `.devstroupe/rules/` antes de editar backend ou frontend.
12
+ - Sempre finalize com `ds_check_architecture` e as verificações aplicáveis.
13
+
@@ -0,0 +1,16 @@
1
+ # PRD — <feature>
2
+
3
+ ## Problem
4
+
5
+ ## Outcome
6
+
7
+ ## Users and use cases
8
+
9
+ ## Scope
10
+
11
+ ## Out of scope
12
+
13
+ ## Acceptance criteria
14
+
15
+ ## Risks and open questions
16
+
@@ -0,0 +1,21 @@
1
+ # Tasks — <feature>
2
+
3
+ ## Execution policy
4
+
5
+ - MCP DevKit required.
6
+ - Every task must contain acceptance criteria and verification evidence.
7
+
8
+ ## DT-001 — <task>
9
+
10
+ ### Context
11
+
12
+ ### Changes
13
+
14
+ ### Acceptance criteria
15
+
16
+ ### Verification
17
+
18
+ ### Status
19
+
20
+ pending
21
+
@@ -0,0 +1,16 @@
1
+ # Techspec — <feature>
2
+
3
+ ## Context and constraints
4
+
5
+ ## DevKit configuration impact
6
+
7
+ ## Backend design
8
+
9
+ ## Frontend and Spartan UI design
10
+
11
+ ## Data model and migrations
12
+
13
+ ## Permissions and tenant scope
14
+
15
+ ## Verification strategy
16
+
@@ -0,0 +1,19 @@
1
+ export declare const AI_TARGETS: readonly ["codex", "claude", "cursor", "antigravity"];
2
+ export type AiTarget = typeof AI_TARGETS[number];
3
+ export interface AiInstallResult {
4
+ projectRoot: string;
5
+ targets: AiTarget[];
6
+ skills: string[];
7
+ written: string[];
8
+ }
9
+ export interface AiDoctorResult {
10
+ ready: boolean;
11
+ checks: Array<{
12
+ name: string;
13
+ ok: boolean;
14
+ detail: string;
15
+ }>;
16
+ }
17
+ export declare function parseAiTargets(value?: string): AiTarget[];
18
+ export declare function installAiWorkflow(projectRoot: string, targets: AiTarget[]): AiInstallResult;
19
+ export declare function diagnoseAiWorkflow(projectRoot: string): AiDoctorResult;
@@ -0,0 +1,172 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.AI_TARGETS = void 0;
37
+ exports.parseAiTargets = parseAiTargets;
38
+ exports.installAiWorkflow = installAiWorkflow;
39
+ exports.diagnoseAiWorkflow = diagnoseAiWorkflow;
40
+ const path = __importStar(require("path"));
41
+ const fs = __importStar(require("fs-extra"));
42
+ exports.AI_TARGETS = ['codex', 'claude', 'cursor', 'antigravity'];
43
+ const MCP_COMMAND = 'npx';
44
+ const MCP_ARGS = ['-y', '@devstroupe/devkit-mcp'];
45
+ const MANAGED_START = '<!-- devstroupe-ai:start -->';
46
+ const MANAGED_END = '<!-- devstroupe-ai:end -->';
47
+ function parseAiTargets(value = 'all') {
48
+ if (value === 'all')
49
+ return [...exports.AI_TARGETS];
50
+ const targets = value.split(',').map((item) => item.trim()).filter(Boolean);
51
+ const invalid = targets.filter((target) => !exports.AI_TARGETS.includes(target));
52
+ if (invalid.length) {
53
+ throw new Error(`Targets inválidos: ${invalid.join(', ')}. Use: all, ${exports.AI_TARGETS.join(', ')}.`);
54
+ }
55
+ return [...new Set(targets)];
56
+ }
57
+ function resolveWorkflowRoot() {
58
+ const candidates = [
59
+ path.resolve(__dirname, 'ai-workflow'),
60
+ path.resolve(__dirname, '../ai-workflow'),
61
+ ];
62
+ const root = candidates.find((candidate) => fs.existsSync(path.join(candidate, 'skills')));
63
+ if (!root)
64
+ throw new Error('Assets do DevsTroupe AI Workflow não foram encontrados no pacote da CLI.');
65
+ return root;
66
+ }
67
+ function listSkills(workflowRoot) {
68
+ return fs.readdirSync(path.join(workflowRoot, 'skills'))
69
+ .filter((name) => fs.existsSync(path.join(workflowRoot, 'skills', name, 'SKILL.md')))
70
+ .sort();
71
+ }
72
+ function copySkills(workflowRoot, projectRoot, destination, skills, written) {
73
+ for (const skill of skills) {
74
+ const target = path.join(projectRoot, destination, skill);
75
+ fs.ensureDirSync(path.dirname(target));
76
+ fs.copySync(path.join(workflowRoot, 'skills', skill), target, { overwrite: true });
77
+ written.push(path.relative(projectRoot, target));
78
+ }
79
+ }
80
+ function writeJsonMerged(file, patch) {
81
+ const current = fs.existsSync(file) ? fs.readJsonSync(file) : {};
82
+ fs.ensureDirSync(path.dirname(file));
83
+ fs.writeJsonSync(file, { ...current, ...patch }, { spaces: 2 });
84
+ }
85
+ function configureMcp(projectRoot, target, written) {
86
+ const server = { command: MCP_COMMAND, args: MCP_ARGS };
87
+ if (target === 'claude') {
88
+ const file = path.join(projectRoot, '.mcp.json');
89
+ const current = fs.existsSync(file) ? fs.readJsonSync(file) : {};
90
+ writeJsonMerged(file, { ...current, mcpServers: { ...(current.mcpServers ?? {}), devstroupe: server } });
91
+ written.push('.mcp.json');
92
+ }
93
+ else if (target === 'cursor') {
94
+ const file = path.join(projectRoot, '.cursor', 'mcp.json');
95
+ const current = fs.existsSync(file) ? fs.readJsonSync(file) : {};
96
+ writeJsonMerged(file, { ...current, mcpServers: { ...(current.mcpServers ?? {}), devstroupe: server } });
97
+ written.push('.cursor/mcp.json');
98
+ }
99
+ else if (target === 'antigravity') {
100
+ const file = path.join(projectRoot, '.gemini', 'settings.json');
101
+ const current = fs.existsSync(file) ? fs.readJsonSync(file) : {};
102
+ writeJsonMerged(file, { ...current, mcpServers: { ...(current.mcpServers ?? {}), devstroupe: server } });
103
+ written.push('.gemini/settings.json');
104
+ }
105
+ else {
106
+ const file = path.join(projectRoot, '.codex', 'config.toml');
107
+ const block = `${MANAGED_START}\n[mcp_servers.devstroupe]\ncommand = \"${MCP_COMMAND}\"\nargs = [${MCP_ARGS.map((arg) => `\"${arg}\"`).join(', ')}]\n${MANAGED_END}`;
108
+ const current = fs.existsSync(file) ? fs.readFileSync(file, 'utf-8') : '';
109
+ const pattern = new RegExp(`${MANAGED_START}[\\s\\S]*?${MANAGED_END}`, 'm');
110
+ const next = pattern.test(current) ? current.replace(pattern, block) : `${current.trim()}${current.trim() ? '\n\n' : ''}${block}\n`;
111
+ fs.ensureDirSync(path.dirname(file));
112
+ fs.writeFileSync(file, next, 'utf-8');
113
+ written.push('.codex/config.toml');
114
+ }
115
+ }
116
+ function installAgentInstructions(workflowRoot, projectRoot, targets, written) {
117
+ const source = fs.readFileSync(path.join(workflowRoot, 'templates', 'AGENTS.md'), 'utf-8').trim();
118
+ const block = `${MANAGED_START}\n${source}\n${MANAGED_END}`;
119
+ for (const fileName of ['AGENTS.md', ...(targets.includes('claude') ? ['CLAUDE.md'] : [])]) {
120
+ const file = path.join(projectRoot, fileName);
121
+ const current = fs.existsSync(file) ? fs.readFileSync(file, 'utf-8') : '';
122
+ const pattern = new RegExp(`${MANAGED_START}[\\s\\S]*?${MANAGED_END}`, 'm');
123
+ const next = pattern.test(current) ? current.replace(pattern, block) : `${current.trim()}${current.trim() ? '\n\n' : ''}${block}\n`;
124
+ fs.writeFileSync(file, next, 'utf-8');
125
+ written.push(fileName);
126
+ }
127
+ }
128
+ function installAiWorkflow(projectRoot, targets) {
129
+ const workflowRoot = resolveWorkflowRoot();
130
+ const skills = listSkills(workflowRoot);
131
+ const written = [];
132
+ fs.ensureDirSync(path.join(projectRoot, '.devstroupe', 'tasks'));
133
+ fs.copySync(path.join(workflowRoot, 'templates'), path.join(projectRoot, '.devstroupe', 'templates'), { overwrite: true });
134
+ fs.copySync(path.join(workflowRoot, 'rules'), path.join(projectRoot, '.devstroupe', 'rules'), { overwrite: true });
135
+ written.push('.devstroupe/tasks', '.devstroupe/templates', '.devstroupe/rules');
136
+ if (targets.includes('codex') || targets.includes('antigravity')) {
137
+ copySkills(workflowRoot, projectRoot, '.agents/skills', skills, written);
138
+ }
139
+ if (targets.includes('claude'))
140
+ copySkills(workflowRoot, projectRoot, '.claude/skills', skills, written);
141
+ if (targets.includes('cursor')) {
142
+ copySkills(workflowRoot, projectRoot, '.cursor/skills', skills, written);
143
+ fs.ensureDirSync(path.join(projectRoot, '.cursor', 'commands'));
144
+ for (const skill of skills) {
145
+ fs.writeFileSync(path.join(projectRoot, '.cursor', 'commands', `${skill}.md`), `Use a skill \`${skill}\` em \`.cursor/skills/${skill}/SKILL.md\` e siga todas as instruções dela.\n`, 'utf-8');
146
+ }
147
+ written.push('.cursor/commands');
148
+ }
149
+ for (const target of targets)
150
+ configureMcp(projectRoot, target, written);
151
+ installAgentInstructions(workflowRoot, projectRoot, targets, written);
152
+ fs.writeJsonSync(path.join(projectRoot, '.devstroupe', 'ai-workflow.json'), {
153
+ schemaVersion: 1,
154
+ workflow: 'devstroupe',
155
+ mcp: { required: true, allowCliFallback: false, server: '@devstroupe/devkit-mcp' },
156
+ targets,
157
+ skills,
158
+ }, { spaces: 2 });
159
+ written.push('.devstroupe/ai-workflow.json');
160
+ return { projectRoot, targets, skills, written: [...new Set(written)] };
161
+ }
162
+ function diagnoseAiWorkflow(projectRoot) {
163
+ const checks = [
164
+ { name: 'config', ok: fs.existsSync(path.join(projectRoot, 'devstroupe.config.ts')), detail: 'devstroupe.config.ts' },
165
+ { name: 'manifest', ok: fs.existsSync(path.join(projectRoot, '.devstroupe', 'ai-workflow.json')), detail: '.devstroupe/ai-workflow.json' },
166
+ { name: 'tasks', ok: fs.existsSync(path.join(projectRoot, '.devstroupe', 'tasks')), detail: '.devstroupe/tasks' },
167
+ { name: 'skills', ok: fs.existsSync(path.join(projectRoot, '.agents', 'skills')) || fs.existsSync(path.join(projectRoot, '.claude', 'skills')) || fs.existsSync(path.join(projectRoot, '.cursor', 'skills')), detail: 'skills locais' },
168
+ { name: 'mcp', ok: ['.mcp.json', '.cursor/mcp.json', '.codex/config.toml', '.gemini/settings.json'].some((file) => fs.existsSync(path.join(projectRoot, file))), detail: 'configuração MCP' },
169
+ { name: 'instructions', ok: fs.existsSync(path.join(projectRoot, 'AGENTS.md')), detail: 'AGENTS.md' },
170
+ ];
171
+ return { ready: checks.every((check) => check.ok), checks };
172
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const assert = __importStar(require("node:assert/strict"));
37
+ const node_test_1 = require("node:test");
38
+ const os = __importStar(require("node:os"));
39
+ const path = __importStar(require("node:path"));
40
+ const fs = __importStar(require("fs-extra"));
41
+ const ai_workflow_1 = require("./ai-workflow");
42
+ const roots = [];
43
+ (0, node_test_1.afterEach)(() => {
44
+ while (roots.length)
45
+ fs.removeSync(roots.pop());
46
+ });
47
+ function project() {
48
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'devstroupe-ai-'));
49
+ roots.push(root);
50
+ fs.writeFileSync(path.join(root, 'devstroupe.config.ts'), 'export default { entities: [] };\n');
51
+ return root;
52
+ }
53
+ (0, node_test_1.describe)('DevsTroupe AI Workflow', () => {
54
+ (0, node_test_1.it)('valida targets', () => {
55
+ assert.deepEqual((0, ai_workflow_1.parseAiTargets)('codex,claude,codex'), ['codex', 'claude']);
56
+ assert.throws(() => (0, ai_workflow_1.parseAiTargets)('unknown'), /Targets inválidos/);
57
+ });
58
+ (0, node_test_1.it)('instala skills, templates e MCP para todos os agentes', () => {
59
+ const root = project();
60
+ const result = (0, ai_workflow_1.installAiWorkflow)(root, (0, ai_workflow_1.parseAiTargets)('all'));
61
+ assert.ok(result.skills.includes('dt-execute-task'));
62
+ assert.ok(fs.existsSync(path.join(root, '.agents/skills/dt-execute-task/SKILL.md')));
63
+ assert.ok(fs.existsSync(path.join(root, '.claude/skills/dt-execute-task/SKILL.md')));
64
+ assert.ok(fs.existsSync(path.join(root, '.cursor/commands/dt-execute-task.md')));
65
+ assert.equal(fs.readJsonSync(path.join(root, '.mcp.json')).mcpServers.devstroupe.command, 'npx');
66
+ assert.equal(fs.readJsonSync(path.join(root, '.cursor/mcp.json')).mcpServers.devstroupe.command, 'npx');
67
+ assert.match(fs.readFileSync(path.join(root, '.codex/config.toml'), 'utf-8'), /mcp_servers\.devstroupe/);
68
+ assert.equal((0, ai_workflow_1.diagnoseAiWorkflow)(root).ready, true);
69
+ });
70
+ (0, node_test_1.it)('é idempotente e preserva instruções existentes', () => {
71
+ const root = project();
72
+ fs.writeFileSync(path.join(root, 'AGENTS.md'), '# Existing\n');
73
+ (0, ai_workflow_1.installAiWorkflow)(root, ['codex']);
74
+ (0, ai_workflow_1.installAiWorkflow)(root, ['codex']);
75
+ const agents = fs.readFileSync(path.join(root, 'AGENTS.md'), 'utf-8');
76
+ assert.match(agents, /# Existing/);
77
+ assert.equal((agents.match(/devstroupe-ai:start/g) ?? []).length, 1);
78
+ });
79
+ });
package/dist/index.js CHANGED
@@ -49,6 +49,7 @@ const child_process_1 = require("child_process");
49
49
  const devkit_core_1 = require("@devstroupe/devkit-core");
50
50
  const backend_layout_1 = require("./generation/backend-layout");
51
51
  const entity_module_move_1 = require("./migrations/entity-module-move");
52
+ const ai_workflow_1 = require("./ai-workflow");
52
53
  // Registra ts-node para poder carregar arquivos .ts (como o config)
53
54
  try {
54
55
  require('ts-node').register({
@@ -1023,6 +1024,37 @@ program
1023
1024
  fs.writeFileSync(configPath, configContent, 'utf-8');
1024
1025
  console.log('Arquivo devstroupe.config.ts criado com sucesso!');
1025
1026
  });
1027
+ program
1028
+ .command('ai:init')
1029
+ .description('Instala o DevsTroupe AI Workflow, skills locais e configuração MCP no projeto')
1030
+ .option('-t, --targets <targets>', 'Agentes: all ou lista codex,claude,cursor,antigravity', 'all')
1031
+ .action((options) => {
1032
+ try {
1033
+ const targets = (0, ai_workflow_1.parseAiTargets)(options.targets);
1034
+ const result = (0, ai_workflow_1.installAiWorkflow)(process.cwd(), targets);
1035
+ console.log(`[AI] Workflow instalado para: ${result.targets.join(', ')}.`);
1036
+ console.log(`[AI] ${result.skills.length} skills disponíveis; MCP DevKit configurado como obrigatório.`);
1037
+ console.log('[AI] Reinicie a sessão do agente e execute "devstroupe ai:doctor" para validar.');
1038
+ }
1039
+ catch (error) {
1040
+ console.error('[AI] Falha na instalação:', error instanceof Error ? error.message : error);
1041
+ process.exit(1);
1042
+ }
1043
+ });
1044
+ program
1045
+ .command('ai:doctor')
1046
+ .description('Diagnostica skills, instruções e configuração MCP do DevsTroupe AI Workflow')
1047
+ .action(() => {
1048
+ const result = (0, ai_workflow_1.diagnoseAiWorkflow)(process.cwd());
1049
+ for (const check of result.checks) {
1050
+ console.log(`${check.ok ? '[ok]' : '[falha]'} ${check.name}: ${check.detail}`);
1051
+ }
1052
+ if (!result.ready) {
1053
+ console.error('[AI] Workflow incompleto. Execute "devstroupe ai:init" para instalar ou reparar.');
1054
+ process.exit(1);
1055
+ }
1056
+ console.log('[AI] Workflow pronto. O agente deve validar o MCP com ds_health antes de executar tasks.');
1057
+ });
1026
1058
  // Novo Comando init-ui para forçar geração manual do Design System
1027
1059
  program
1028
1060
  .command('init-ui')
@@ -2329,6 +2361,8 @@ program
2329
2361
  };
2330
2362
  `;
2331
2363
  fs.writeFileSync(configPath, configContent, 'utf-8');
2364
+ const aiResult = (0, ai_workflow_1.installAiWorkflow)(projectRoot, (0, ai_workflow_1.parseAiTargets)('all'));
2365
+ console.log(`[AI] Workflow DevsTroupe instalado com ${aiResult.skills.length} skills e MCP configurado.`);
2332
2366
  console.log(`\n\x1b[32m[SUCESSO] Projeto "${projectName}" inicializado com sucesso!\x1b[0m`);
2333
2367
  console.log(`Para começar:`);
2334
2368
  console.log(` 1. Acesse a pasta do projeto: cd ${projectName}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devstroupe/devkit-cli",
3
- "version": "1.2.0-beta.5",
3
+ "version": "1.2.0-beta.6",
4
4
  "description": "DevsTroupe Development Kit CLI — scaffold NestJS+Angular projects, inject Spartan UI, generate CRUDs and audit architectural governance",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -36,7 +36,7 @@
36
36
  "dependencies": {
37
37
  "commander": "^12.0.0",
38
38
  "fs-extra": "^11.2.0",
39
- "@devstroupe/devkit-core": "1.2.0-beta.5"
39
+ "@devstroupe/devkit-core": "1.2.0-beta.6"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/fs-extra": "^11.0.4",
@@ -45,6 +45,6 @@
45
45
  },
46
46
  "scripts": {
47
47
  "build": "node clean.js && tsc && node postbuild.js && chmod +x dist/index.js",
48
- "test": "node clean.js && tsc && node postbuild.js && node --test dist/rules/linter-rules.test.js dist/templates/relationship-templates.test.js dist/templates/generator-characterization.test.js dist/generation/backend-layout.test.js dist/generation/backend-generator.integration.test.js dist/migrations/entity-module-move.test.js"
48
+ "test": "node clean.js && tsc && node postbuild.js && node --test dist/ai-workflow.test.js dist/rules/linter-rules.test.js dist/templates/relationship-templates.test.js dist/templates/generator-characterization.test.js dist/generation/backend-layout.test.js dist/generation/backend-generator.integration.test.js dist/migrations/entity-module-move.test.js"
49
49
  }
50
50
  }