1050 lines
31 KiB
Markdown
1050 lines
31 KiB
Markdown
Vou criar um plano técnico focado apenas nas funções e implementações, sem aspectos de negócio, custos ou gestão de equipe. Ideal para gerar comandos no Claude Code.
|
|
|
|
\---
|
|
|
|
\`\`\`markdown
|
|
\# PLANO TÉCNICO DE IMPLEMENTAÇÃO: SKILL FABRIC
|
|
\#\# Gerador e Gestor de Desenvolvimento de Skills \- Arcádia Suite
|
|
|
|
\*\*Versão:\*\* 1.0
|
|
\*\*Data:\*\* Março 2026
|
|
\*\*Tipo:\*\* Especificação Técnica para Implementação
|
|
|
|
\---
|
|
|
|
\#\# 1\. ARQUITETURA TÉCNICA
|
|
|
|
\#\#\# 1.1 Stack Tecnológico
|
|
|
|
| Camada | Tecnologia | Propósito |
|
|
|--------|-----------|-----------|
|
|
| Frontend | React \+ TypeScript \+ Monaco Editor | IDE no browser |
|
|
| Backend | Node.js \+ TypeScript | API e runtime |
|
|
| Compilador | ANTLR \+ AST | Parser de skills |
|
|
| Validação | ESLint \+ Custom Rules | Quality gates |
|
|
| Runtime | VM2 \+ Sandboxing | Execução segura |
|
|
| Storage | PostgreSQL \+ Neo4j | Dados e grafo |
|
|
| Cache | Redis | Performance |
|
|
|
|
\#\#\# 1.2 Estrutura de Diretórios
|
|
|
|
\`\`\`
|
|
server/modules/skill-fabric/
|
|
├── src/
|
|
│ ├── api/
|
|
│ │ ├── routes/
|
|
│ │ │ ├── skills.routes.ts
|
|
│ │ │ ├── compiler.routes.ts
|
|
│ │ │ ├── validator.routes.ts
|
|
│ │ │ └── marketplace.routes.ts
|
|
│ │ └── controllers/
|
|
│ ├── core/
|
|
│ │ ├── skill/
|
|
│ │ │ ├── Skill.entity.ts
|
|
│ │ │ ├── Skill.repository.ts
|
|
│ │ │ └── Skill.service.ts
|
|
│ │ ├── compiler/
|
|
│ │ │ ├── VisualCompiler.ts
|
|
│ │ │ ├── CodeCompiler.ts
|
|
│ │ │ ├── MarkdownCompiler.ts
|
|
│ │ │ └── AST/
|
|
│ │ ├── validator/
|
|
│ │ │ ├── ValidationPipeline.ts
|
|
│ │ │ ├── rules/
|
|
│ │ │ │ ├── SyntaxRule.ts
|
|
│ │ │ │ ├── TypeRule.ts
|
|
│ │ │ │ ├── SecurityRule.ts
|
|
│ │ │ │ └── PerformanceRule.ts
|
|
│ │ ├── executor/
|
|
│ │ │ ├── SkillExecutor.ts
|
|
│ │ │ ├── Sandbox.ts
|
|
│ │ │ └── ReferenceResolver.ts
|
|
│ │ └── lifecycle/
|
|
│ │ ├── LifecycleManager.ts
|
|
│ │ └── StateMachine.ts
|
|
│ └── types/
|
|
│ └── index.ts
|
|
└── tests/
|
|
|
|
client/src/modules/skill-fabric/
|
|
├── visual-studio/
|
|
│ ├── components/
|
|
│ │ ├── Canvas.tsx
|
|
│ │ ├── NodePalette.tsx
|
|
│ │ ├── PropertyPanel.tsx
|
|
│ │ └── ConnectionLine.tsx
|
|
│ └── hooks/
|
|
│ ├── useCanvas.ts
|
|
│ └── useDragDrop.ts
|
|
├── code-ide/
|
|
│ ├── components/
|
|
│ │ ├── MonacoEditor.tsx
|
|
│ │ ├── IntelliSenseProvider.ts
|
|
│ │ └── DebuggerPanel.tsx
|
|
│ └── templates/
|
|
│ └── skill-template.ts
|
|
├── markdown-studio/
|
|
│ ├── components/
|
|
│ │ ├── MarkdownEditor.tsx
|
|
│ │ ├── AIAssistant.tsx
|
|
│ │ └── LivePreview.tsx
|
|
│ └── parser/
|
|
│ └── MarkdownParser.ts
|
|
└── shared/
|
|
├── components/
|
|
│ ├── SkillToolbar.tsx
|
|
│ ├── VersionSelector.tsx
|
|
│ └── ValidationPanel.tsx
|
|
└── utils/
|
|
└── referenceParser.ts
|
|
\`\`\`
|
|
|
|
\---
|
|
|
|
\#\# 2\. MÓDULOS DE IMPLEMENTAÇÃO
|
|
|
|
\#\#\# 2.1 Módulo: Core API (skills.api)
|
|
|
|
\*\*Arquivos:\*\*
|
|
\- \`server/modules/skill-fabric/src/api/routes/skills.routes.ts\`
|
|
\- \`server/modules/skill-fabric/src/api/controllers/skills.controller.ts\`
|
|
|
|
\*\*Funções:\*\*
|
|
|
|
\`\`\`typescript
|
|
// CRUD Básico
|
|
POST /api/skills // createSkill(dto: CreateSkillDTO)
|
|
GET /api/skills // listSkills(query: ListSkillsQuery)
|
|
GET /api/skills/:id // getSkill(id: string)
|
|
PUT /api/skills/:id // updateSkill(id: string, dto: UpdateSkillDTO)
|
|
DELETE /api/skills/:id // archiveSkill(id: string)
|
|
|
|
// Compilação
|
|
POST /api/skills/:id/compile // compileSkill(id: string)
|
|
GET /api/skills/:id/ast // getSkillAST(id: string)
|
|
|
|
// Validação
|
|
POST /api/skills/:id/validate // validateSkill(id: string)
|
|
GET /api/skills/:id/validation // getValidationResults(id: string)
|
|
|
|
// Execução
|
|
POST /api/skills/:id/execute // executeSkill(id: string, input: any)
|
|
GET /api/skills/:id/executions // listExecutions(id: string)
|
|
|
|
// Versionamento
|
|
GET /api/skills/:id/versions // listVersions(id: string)
|
|
POST /api/skills/:id/versions // createVersion(id: string, dto: VersionDTO)
|
|
POST /api/skills/:id/rollback // rollbackToVersion(id: string, version: string)
|
|
|
|
// Lifecycle
|
|
POST /api/skills/:id/submit // submitForReview(id: string)
|
|
POST /api/skills/:id/approve // approveSkill(id: string)
|
|
POST /api/skills/:id/reject // rejectSkill(id: string, reason: string)
|
|
POST /api/skills/:id/publish // publishSkill(id: string)
|
|
POST /api/skills/:id/deprecate // deprecateSkill(id: string)
|
|
|
|
// Marketplace
|
|
GET /api/skills/marketplace // listMarketplaceSkills(query: MarketplaceQuery)
|
|
POST /api/skills/:id/publish-marketplace // publishToMarketplace(id: string)
|
|
POST /api/skills/marketplace/:id/install // installFromMarketplace(id: string)
|
|
\`\`\`
|
|
|
|
\*\*DTOs:\*\*
|
|
|
|
\`\`\`typescript
|
|
interface CreateSkillDTO {
|
|
name: string;
|
|
slug: string;
|
|
description: string;
|
|
type: 'visual' | 'code' | 'markdown';
|
|
tenantId: number;
|
|
companyId?: number;
|
|
initialContent?: any;
|
|
}
|
|
|
|
interface UpdateSkillDTO {
|
|
name?: string;
|
|
description?: string;
|
|
content?: any;
|
|
metadata?: SkillMetadata;
|
|
}
|
|
|
|
interface ListSkillsQuery {
|
|
tenantId?: number;
|
|
companyId?: number;
|
|
userId?: number;
|
|
type?: 'visual' | 'code' | 'markdown';
|
|
status?: 'draft' | 'dev' | 'testing' | 'staging' | 'production';
|
|
tags?: string\[\];
|
|
search?: string;
|
|
limit?: number;
|
|
offset?: number;
|
|
}
|
|
\`\`\`
|
|
|
|
\---
|
|
|
|
\#\#\# 2.2 Módulo: Skill Entity (skill.entity)
|
|
|
|
\*\*Arquivo:\*\* \`server/modules/skill-fabric/src/core/skill/Skill.entity.ts\`
|
|
|
|
\*\*Classe:\*\*
|
|
|
|
\`\`\`typescript
|
|
export class Skill {
|
|
constructor(props: SkillProps) {
|
|
this.id \= props.id || uuid();
|
|
this.validateProps(props);
|
|
Object.assign(this, props);
|
|
}
|
|
|
|
// Identidade
|
|
id: UUID;
|
|
slug: string;
|
|
name: string;
|
|
description: string;
|
|
|
|
// Hierarquia
|
|
tenantId: number;
|
|
companyId?: number;
|
|
userId?: number;
|
|
namespace: 'system' | 'tenant' | 'company' | 'user';
|
|
|
|
// Implementação
|
|
type: 'visual' | 'code' | 'markdown';
|
|
content: VisualContent | CodeContent | MarkdownContent;
|
|
compiled?: CompiledSkill;
|
|
|
|
// Interface
|
|
inputSchema: JSONSchema;
|
|
outputSchema: JSONSchema;
|
|
|
|
// Runtime
|
|
timeout: number \= 30000;
|
|
memory: number \= 512;
|
|
retries: number \= 3;
|
|
|
|
// Lifecycle
|
|
status: SkillStatus \= 'draft';
|
|
version: SemanticVersion \= '0.0.1';
|
|
branch: string \= 'main';
|
|
|
|
// Métodos de domínio
|
|
compile(): CompiledSkill;
|
|
validate(): ValidationResult;
|
|
execute(context: ExecutionContext): Promise\<ExecutionResult\>;
|
|
changeStatus(newStatus: SkillStatus, reason?: string): void;
|
|
createVersion(message: string): Version;
|
|
rollback(version: string): void;
|
|
fork(newSlug: string): Skill;
|
|
|
|
// Validação
|
|
private validateProps(props: SkillProps): void;
|
|
private validateSlug(slug: string): boolean;
|
|
private validateContent(content: any): boolean;
|
|
}
|
|
\`\`\`
|
|
|
|
\---
|
|
|
|
\#\#\# 2.3 Módulo: Compiladores (compiler)
|
|
|
|
\*\*Arquivos:\*\*
|
|
\- \`server/modules/skill-fabric/src/core/compiler/VisualCompiler.ts\`
|
|
\- \`server/modules/skill-fabric/src/core/compiler/CodeCompiler.ts\`
|
|
\- \`server/modules/skill-fabric/src/core/compiler/MarkdownCompiler.ts\`
|
|
|
|
\*\*Interface:\*\*
|
|
|
|
\`\`\`typescript
|
|
interface Compiler {
|
|
compile(source: any): CompiledSkill;
|
|
parse(source: any): AST;
|
|
generateCode(ast: AST): string;
|
|
validateSyntax(source: any): SyntaxValidationResult;
|
|
}
|
|
|
|
// Visual Compiler
|
|
export class VisualCompiler implements Compiler {
|
|
compile(canvas: VisualCanvas): CompiledSkill {
|
|
// 1\. Valida conexões
|
|
// 2\. Ordena topologicamente
|
|
// 3\. Gera AST
|
|
// 4\. Compila para JavaScript
|
|
}
|
|
|
|
parse(canvas: VisualCanvas): VisualAST;
|
|
generateCode(ast: VisualAST): string;
|
|
validateSyntax(canvas: VisualCanvas): SyntaxValidationResult;
|
|
}
|
|
|
|
// Code Compiler
|
|
export class CodeCompiler implements Compiler {
|
|
compile(sourceCode: string): CompiledSkill {
|
|
// 1\. Parse TypeScript
|
|
// 2\. Type checking
|
|
// 3\. Transform decorators
|
|
// 4\. Bundle dependencies
|
|
}
|
|
|
|
parse(sourceCode: string): TypeScriptAST;
|
|
generateCode(ast: TypeScriptAST): string;
|
|
validateSyntax(sourceCode: string): SyntaxValidationResult;
|
|
}
|
|
|
|
// Markdown Compiler
|
|
export class MarkdownCompiler implements Compiler {
|
|
compile(markdown: string): CompiledSkill {
|
|
// 1\. Parse frontmatter
|
|
// 2\. Extrair blocos de código
|
|
// 3\. Resolver referências /xxx/
|
|
// 4\. Gerar JavaScript
|
|
}
|
|
|
|
parse(markdown: string): MarkdownAST;
|
|
generateCode(ast: MarkdownAST): string;
|
|
validateSyntax(markdown: string): SyntaxValidationResult;
|
|
}
|
|
\`\`\`
|
|
|
|
\*\*AST Types:\*\*
|
|
|
|
\`\`\`typescript
|
|
interface AST {
|
|
type: 'skill';
|
|
version: string;
|
|
metadata: SkillMetadata;
|
|
imports: ImportNode\[\];
|
|
exports: ExportNode\[\];
|
|
body: StatementNode\[\];
|
|
}
|
|
|
|
type StatementNode \=
|
|
| VariableDeclarationNode
|
|
| FunctionDeclarationNode
|
|
| ClassDeclarationNode
|
|
| ExpressionStatementNode
|
|
| IfStatementNode
|
|
| LoopStatementNode
|
|
| TryCatchNode
|
|
| SkillCallNode;
|
|
|
|
interface SkillCallNode {
|
|
type: 'skill-call';
|
|
reference: string; // /skill/xxx
|
|
arguments: ArgumentNode\[\];
|
|
await: boolean;
|
|
}
|
|
\`\`\`
|
|
|
|
\---
|
|
|
|
\#\#\# 2.4 Módulo: Validador (validator)
|
|
|
|
\*\*Arquivo:\*\* \`server/modules/skill-fabric/src/core/validator/ValidationPipeline.ts\`
|
|
|
|
\*\*Pipeline:\*\*
|
|
|
|
\`\`\`typescript
|
|
export class ValidationPipeline {
|
|
private rules: ValidationRule\[\] \= \[
|
|
new SyntaxRule(),
|
|
new TypeRule(),
|
|
new SecurityRule(),
|
|
new DependencyRule(),
|
|
new PerformanceRule(),
|
|
new DocumentationRule()
|
|
\];
|
|
|
|
async validate(skill: Skill): Promise\<ValidationResult\> {
|
|
const results: RuleResult\[\] \= \[\];
|
|
|
|
for (const rule of this.rules) {
|
|
const result \= await rule.check(skill);
|
|
results.push(result);
|
|
|
|
// Fail fast para erros críticos
|
|
if (result.severity \=== 'error' && rule.isBlocking) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return this.aggregateResults(results);
|
|
}
|
|
|
|
calculateScore(results: RuleResult\[\]): number {
|
|
return results.reduce((score, r) \=\> {
|
|
return r.passed ? score \+ r.weight : score;
|
|
}, 0);
|
|
}
|
|
}
|
|
|
|
// Regras individuais
|
|
export class SyntaxRule implements ValidationRule {
|
|
name \= 'syntax';
|
|
weight \= 10;
|
|
isBlocking \= true;
|
|
|
|
async check(skill: Skill): Promise\<RuleResult\> {
|
|
const compiler \= this.getCompiler(skill.type);
|
|
const result \= compiler.validateSyntax(skill.content);
|
|
|
|
return {
|
|
rule: this.name,
|
|
passed: result.valid,
|
|
weight: this.weight,
|
|
severity: result.valid ? 'info' : 'error',
|
|
details: result.errors
|
|
};
|
|
}
|
|
}
|
|
|
|
export class SecurityRule implements ValidationRule {
|
|
name \= 'security';
|
|
weight \= 20;
|
|
isBlocking \= true;
|
|
|
|
forbiddenPatterns \= \[
|
|
/eval\\s\*\\(/,
|
|
/Function\\s\*\\(/,
|
|
/child\_process/,
|
|
/fs\\.unlink/,
|
|
/process\\.env\\s\*=/,
|
|
/\_\_proto\_\_/,
|
|
/constructor\\s\*\\\[\\s\*\["'\]prototype\["'\]\\s\*\\\]/
|
|
\];
|
|
|
|
async check(skill: Skill): Promise\<RuleResult\> {
|
|
const code \= skill.compiled?.code || '';
|
|
const vulnerabilities: Vulnerability\[\] \= \[\];
|
|
|
|
for (const pattern of this.forbiddenPatterns) {
|
|
if (pattern.test(code)) {
|
|
vulnerabilities.push({
|
|
severity: 'critical',
|
|
pattern: pattern.source,
|
|
line: this.findLine(code, pattern),
|
|
message: \`Uso proibido de: ${pattern.source}\`
|
|
});
|
|
}
|
|
}
|
|
|
|
// Scan de dependências
|
|
const deps \= skill.compiled?.dependencies || \[\];
|
|
for (const dep of deps) {
|
|
const audit \= await this.auditDependency(dep);
|
|
if (audit.vulnerabilities.length \> 0\) {
|
|
vulnerabilities.push(...audit.vulnerabilities);
|
|
}
|
|
}
|
|
|
|
return {
|
|
rule: this.name,
|
|
passed: vulnerabilities.length \=== 0,
|
|
weight: this.weight,
|
|
severity: vulnerabilities.length \> 0 ? 'error' : 'info',
|
|
details: vulnerabilities
|
|
};
|
|
}
|
|
}
|
|
\`\`\`
|
|
|
|
\---
|
|
|
|
\#\#\# 2.5 Módulo: Executor (executor)
|
|
|
|
\*\*Arquivo:\*\* \`server/modules/skill-fabric/src/core/executor/SkillExecutor.ts\`
|
|
|
|
\*\*Implementação:\*\*
|
|
|
|
\`\`\`typescript
|
|
export class SkillExecutor {
|
|
constructor(
|
|
private sandbox: Sandbox,
|
|
private referenceResolver: ReferenceResolver,
|
|
private cache: CacheManager,
|
|
private logger: Logger
|
|
) {}
|
|
|
|
async execute(
|
|
skillId: string,
|
|
input: any,
|
|
context: ExecutionContext
|
|
): Promise\<ExecutionResult\> {
|
|
const skill \= await this.loadSkill(skillId);
|
|
|
|
// Check cache
|
|
const cacheKey \= this.generateCacheKey(skillId, input);
|
|
if (\!context.skipCache) {
|
|
const cached \= await this.cache.get(cacheKey);
|
|
if (cached) return { ...cached, cached: true };
|
|
}
|
|
|
|
// Pre-execution
|
|
const validatedInput \= this.validateInput(skill, input);
|
|
const executionContext \= this.buildContext(skill, context);
|
|
|
|
// Execute in sandbox
|
|
const startTime \= Date.now();
|
|
try {
|
|
const result \= await this.sandbox.run({
|
|
code: skill.compiled.code,
|
|
context: executionContext,
|
|
timeout: skill.timeout,
|
|
memory: skill.memory
|
|
});
|
|
|
|
// Post-execution
|
|
const duration \= Date.now() \- startTime;
|
|
const output \= this.validateOutput(skill, result);
|
|
|
|
// Cache result
|
|
await this.cache.set(cacheKey, output, skill.cacheConfig);
|
|
|
|
// Log execution
|
|
await this.logExecution(skill, input, output, duration);
|
|
|
|
return {
|
|
success: true,
|
|
data: output,
|
|
duration,
|
|
executionId: context.executionId
|
|
};
|
|
|
|
} catch (error) {
|
|
// Handle error
|
|
if (skill.retries \> 0 && this.isRetryable(error)) {
|
|
return this.retry(skillId, input, context, skill.retries);
|
|
}
|
|
|
|
// Fallback
|
|
if (skill.fallbackSkillId) {
|
|
return this.execute(skill.fallbackSkillId, input, context);
|
|
}
|
|
|
|
return {
|
|
success: false,
|
|
error: this.sanitizeError(error),
|
|
duration: Date.now() \- startTime
|
|
};
|
|
}
|
|
}
|
|
|
|
private buildContext(skill: Skill, parentContext: ExecutionContext): ExecutionContext {
|
|
return {
|
|
...parentContext,
|
|
skillId: skill.id,
|
|
tenantId: skill.tenantId,
|
|
variables: {
|
|
input: parentContext.input,
|
|
config: skill.config,
|
|
secrets: this.loadSecrets(skill.tenantId)
|
|
},
|
|
skills: {
|
|
execute: (ref: string, params: any) \=\> this.executeReference(ref, params, parentContext)
|
|
},
|
|
kg: {
|
|
query: (cypher: string, params: any) \=\> this.kg.query(cypher, params)
|
|
},
|
|
tools: {
|
|
call: (toolName: string, params: any) \=\> this.callTool(toolName, params)
|
|
}
|
|
};
|
|
}
|
|
}
|
|
\`\`\`
|
|
|
|
\*\*Sandbox:\*\*
|
|
|
|
\`\`\`typescript
|
|
export class Sandbox {
|
|
private vm: NodeVM;
|
|
|
|
constructor(config: SandboxConfig) {
|
|
this.vm \= new NodeVM({
|
|
timeout: config.timeout,
|
|
sandbox: config.context,
|
|
require: {
|
|
external: config.allowedModules || \[\],
|
|
builtin: \['path', 'util', 'crypto'\],
|
|
root: './',
|
|
mock: this.buildMocks()
|
|
},
|
|
compiler: (code: string) \=\> this.compile(code)
|
|
});
|
|
}
|
|
|
|
async run(options: RunOptions): Promise\<any\> {
|
|
const script \= new VMScript(options.code, {
|
|
filename: options.filename || 'skill.js'
|
|
});
|
|
|
|
const fn \= this.vm.run(script);
|
|
|
|
if (typeof fn \=== 'function') {
|
|
return await fn(options.context);
|
|
}
|
|
|
|
return fn;
|
|
}
|
|
|
|
private buildMocks(): Record\<string, any\> {
|
|
return {
|
|
fs: {
|
|
readFile: (path: string) \=\> { throw new Error('fs.readFile blocked'); },
|
|
writeFile: () \=\> { throw new Error('fs.writeFile blocked'); }
|
|
},
|
|
child\_process: new Proxy({}, {
|
|
get: () \=\> { throw new Error('child\_process blocked'); }
|
|
})
|
|
};
|
|
}
|
|
}
|
|
\`\`\`
|
|
|
|
\---
|
|
|
|
\#\#\# 2.6 Módulo: Visual Studio (Frontend)
|
|
|
|
\*\*Arquivo:\*\* \`client/src/modules/skill-fabric/visual-studio/components/Canvas.tsx\`
|
|
|
|
\*\*Componentes:\*\*
|
|
|
|
\`\`\`typescript
|
|
// Canvas principal
|
|
export const Canvas: React.FC\<CanvasProps\> \= ({ skill, onChange }) \=\> {
|
|
const \[nodes, setNodes\] \= useState\<Node\[\]\>(skill.content.nodes);
|
|
const \[edges, setEdges\] \= useState\<Edge\[\]\>(skill.content.edges);
|
|
const \[selectedNode, setSelectedNode\] \= useState\<Node | null\>(null);
|
|
|
|
const { dragRef, dropRef, isDragging } \= useDragDrop({
|
|
onDrop: (item, position) \=\> {
|
|
const newNode \= createNode(item.type, position);
|
|
setNodes(\[...nodes, newNode\]);
|
|
}
|
|
});
|
|
|
|
const onConnect \= (connection: Connection) \=\> {
|
|
const newEdge \= createEdge(connection);
|
|
if (validateConnection(newEdge, nodes, edges)) {
|
|
setEdges(\[...edges, newEdge\]);
|
|
}
|
|
};
|
|
|
|
const onNodeUpdate \= (nodeId: string, updates: Partial\<Node\>) \=\> {
|
|
setNodes(nodes.map(n \=\> n.id \=== nodeId ? { ...n, ...updates } : n));
|
|
};
|
|
|
|
const onCompile \= async () \=\> {
|
|
const compiled \= await compileVisualSkill({ nodes, edges });
|
|
onChange({ ...skill, content: { nodes, edges }, compiled });
|
|
};
|
|
|
|
return (
|
|
\<div className="canvas-container" ref={dropRef}\>
|
|
\<CanvasToolbar onCompile={onCompile} onRun={onRun} /\>
|
|
|
|
\<div className="canvas-workspace"\>
|
|
\<NodePalette ref={dragRef} /\>
|
|
|
|
\<ReactFlow
|
|
nodes={nodes}
|
|
edges={edges}
|
|
onNodesChange={setNodes}
|
|
onEdgesChange={setEdges}
|
|
onConnect={onConnect}
|
|
onNodeClick={(\_, node) \=\> setSelectedNode(node)}
|
|
nodeTypes={customNodeTypes}
|
|
edgeTypes={customEdgeTypes}
|
|
fitView
|
|
\>
|
|
\<Background /\>
|
|
\<Controls /\>
|
|
\<MiniMap /\>
|
|
\</ReactFlow\>
|
|
|
|
{selectedNode && (
|
|
\<PropertyPanel
|
|
node={selectedNode}
|
|
onChange={(updates) \=\> onNodeUpdate(selectedNode.id, updates)}
|
|
onClose={() \=\> setSelectedNode(null)}
|
|
/\>
|
|
)}
|
|
\</div\>
|
|
\</div\>
|
|
);
|
|
};
|
|
|
|
// Tipos de nós disponíveis
|
|
const nodeTypes \= {
|
|
trigger: TriggerNode,
|
|
action: ActionNode,
|
|
condition: ConditionNode,
|
|
loop: LoopNode,
|
|
transform: TransformNode,
|
|
output: OutputNode
|
|
};
|
|
\`\`\`
|
|
|
|
\---
|
|
|
|
\#\#\# 2.7 Módulo: Code IDE (Frontend)
|
|
|
|
\*\*Arquivo:\*\* \`client/src/modules/skill-fabric/code-ide/components/MonacoEditor.tsx\`
|
|
|
|
\*\*Implementação:\*\*
|
|
|
|
\`\`\`typescript
|
|
export const SkillCodeEditor: React.FC\<EditorProps\> \= ({ skill, onChange }) \=\> {
|
|
const editorRef \= useRef\<monaco.editor.IStandaloneCodeEditor\>();
|
|
const \[decorations, setDecorations\] \= useState\<string\[\]\>(\[\]);
|
|
|
|
// Configurar IntelliSense para referências /xxx/
|
|
useEffect(() \=\> {
|
|
if (\!editorRef.current) return;
|
|
|
|
const disposable \= monaco.languages.registerCompletionItemProvider(
|
|
'typescript',
|
|
{
|
|
triggerCharacters: \['/'\],
|
|
provideCompletionItems: async (model, position) \=\> {
|
|
const lineContent \= model.getLineContent(position.lineNumber);
|
|
const beforeCursor \= lineContent.substring(0, position.column \- 1);
|
|
|
|
if (beforeCursor.match(/\\/(\\w\*)$/)) {
|
|
const suggestions \= await fetchReferenceSuggestions(
|
|
beforeCursor,
|
|
skill.tenantId
|
|
);
|
|
|
|
return {
|
|
suggestions: suggestions.map(s \=\> ({
|
|
label: s.fullReference,
|
|
kind: monaco.languages.CompletionItemKind.Reference,
|
|
insertText: s.fullReference,
|
|
detail: s.description,
|
|
documentation: { value: s.documentation }
|
|
}))
|
|
};
|
|
}
|
|
|
|
return { suggestions: \[\] };
|
|
}
|
|
}
|
|
);
|
|
|
|
return () \=\> disposable.dispose();
|
|
}, \[skill.tenantId\]);
|
|
|
|
// Real-time validation
|
|
const onValidate \= async (code: string) \=\> {
|
|
const markers \= await validateCode(code);
|
|
monaco.editor.setModelMarkers(
|
|
editorRef.current\!.getModel()\!,
|
|
'skill-validator',
|
|
markers.map(m \=\> ({
|
|
severity: monaco.MarkerSeverity\[m.severity\],
|
|
message: m.message,
|
|
startLineNumber: m.line,
|
|
startColumn: m.column,
|
|
endLineNumber: m.endLine || m.line,
|
|
endColumn: m.endColumn || m.column \+ 1
|
|
}))
|
|
);
|
|
};
|
|
|
|
return (
|
|
\<div className="code-editor-container"\>
|
|
\<EditorToolbar
|
|
onRun={() \=\> executeSkill(skill.id, editorRef.current\!.getValue())}
|
|
onDebug={() \=\> startDebugger(skill.id)}
|
|
onFormat={() \=\> formatCode(editorRef.current\!)}
|
|
/\>
|
|
|
|
\<MonacoEditor
|
|
height="100%"
|
|
language="typescript"
|
|
value={skill.content.sourceCode}
|
|
onChange={onChange}
|
|
onMount={(editor) \=\> {
|
|
editorRef.current \= editor;
|
|
configureSkillEditor(editor);
|
|
}}
|
|
options={{
|
|
minimap: { enabled: true },
|
|
folding: true,
|
|
automaticLayout: true,
|
|
suggestOnTriggerCharacters: true,
|
|
quickSuggestions: true
|
|
}}
|
|
/\>
|
|
|
|
\<ValidationPanel markers={decorations} /\>
|
|
\</div\>
|
|
);
|
|
};
|
|
\`\`\`
|
|
|
|
\---
|
|
|
|
\#\#\# 2.8 Módulo: Referências (reference)
|
|
|
|
\*\*Arquivo:\*\* \`client/src/shared/utils/referenceParser.ts\`
|
|
|
|
\*\*Parser:\*\*
|
|
|
|
\`\`\`typescript
|
|
export class ReferenceParser {
|
|
// Padrão: /type:namespace/path?query
|
|
private static readonly PATTERN \=
|
|
/\\/(skill|kg|file|data|var|tool|agent)(?::(system|tenant|company|user))?\\/(\[a-zA-Z0-9\_\\/\\.\\-:\]+)(?:\\?(\[^\\s\]+))?/g;
|
|
|
|
parse(text: string): Reference\[\] {
|
|
const refs: Reference\[\] \= \[\];
|
|
let match;
|
|
|
|
while ((match \= ReferenceParser.PATTERN.exec(text)) \!== null) {
|
|
const \[fullMatch, type, namespace, path, queryString\] \= match;
|
|
|
|
refs.push({
|
|
type: type as ReferenceType,
|
|
namespace: namespace as ReferenceNamespace,
|
|
path,
|
|
queryParams: queryString ? parseQueryString(queryString) : undefined,
|
|
fullMatch,
|
|
position: {
|
|
start: match.index,
|
|
end: match.index \+ fullMatch.length
|
|
}
|
|
});
|
|
}
|
|
|
|
return refs;
|
|
}
|
|
|
|
async resolveReferences(
|
|
refs: Reference\[\],
|
|
context: ResolutionContext
|
|
): Promise\<ResolvedReference\[\]\> {
|
|
return Promise.all(refs.map(ref \=\> this.resolve(ref, context)));
|
|
}
|
|
|
|
private async resolve(ref: Reference, context: ResolutionContext): Promise\<ResolvedReference\> {
|
|
const resolvers: Record\<ReferenceType, Resolver\> \= {
|
|
skill: new SkillResolver(),
|
|
kg: new KGResolver(),
|
|
file: new FileResolver(),
|
|
data: new DataResolver(),
|
|
var: new VariableResolver(),
|
|
tool: new ToolResolver(),
|
|
agent: new AgentResolver()
|
|
};
|
|
|
|
const resolver \= resolvers\[ref.type\];
|
|
const value \= await resolver.resolve(ref, context);
|
|
|
|
return {
|
|
...ref,
|
|
resolved: true,
|
|
value,
|
|
metadata: await resolver.getMetadata(ref)
|
|
};
|
|
}
|
|
}
|
|
\`\`\`
|
|
|
|
\---
|
|
|
|
\#\# 3\. COMANDOS DE IMPLEMENTAÇÃO PARA CLAUDE CODE
|
|
|
|
\#\#\# 3.1 Setup Inicial
|
|
|
|
\`\`\`bash
|
|
\# Criar estrutura de diretórios
|
|
mkdir \-p server/modules/skill-fabric/src/{api/{routes,controllers},core/{skill,compiler,validator,executor,lifecycle},types}
|
|
mkdir \-p client/src/modules/skill-fabric/{visual-studio/{components,hooks},code-ide/{components,templates},markdown-studio/{components,parser},shared/{components,utils}}
|
|
|
|
\# Instalar dependências backend
|
|
cd server/modules/skill-fabric
|
|
npm init \-y
|
|
npm install typescript @types/node ts-node express zod uuid vm2 antlr4ts
|
|
npm install \-D jest @types/jest supertest
|
|
|
|
\# Instalar dependências frontend
|
|
cd ../../../client
|
|
npm install @monaco-editor/react react-flow-renderer @types/react-flow-renderer
|
|
npm install antlr4ts antlr4ts-cli
|
|
|
|
\# Gerar parser ANTLR
|
|
npx antlr4ts \-visitor \-listener server/modules/skill-fabric/src/core/compiler/grammar/SkillLexer.g4
|
|
npx antlr4ts \-visitor \-listener server/modules/skill-fabric/src/core/compiler/grammar/SkillParser.g4
|
|
\`\`\`
|
|
|
|
\#\#\# 3.2 Implementação por Fase
|
|
|
|
\*\*Fase 1: Core API e Entity\*\*
|
|
\`\`\`bash
|
|
\# Gerar arquivos base
|
|
claude generate server/modules/skill-fabric/src/core/skill/Skill.entity.ts
|
|
claude generate server/modules/skill-fabric/src/core/skill/Skill.repository.ts
|
|
claude generate server/modules/skill-fabric/src/api/routes/skills.routes.ts
|
|
claude generate server/modules/skill-fabric/src/api/controllers/skills.controller.ts
|
|
\`\`\`
|
|
|
|
\*\*Fase 2: Compiladores\*\*
|
|
\`\`\`bash
|
|
claude generate server/modules/skill-fabric/src/core/compiler/VisualCompiler.ts
|
|
claude generate server/modules/skill-fabric/src/core/compiler/CodeCompiler.ts
|
|
claude generate server/modules/skill-fabric/src/core/compiler/MarkdownCompiler.ts
|
|
\`\`\`
|
|
|
|
\*\*Fase 3: Validador\*\*
|
|
\`\`\`bash
|
|
claude generate server/modules/skill-fabric/src/core/validator/ValidationPipeline.ts
|
|
claude generate server/modules/skill-fabric/src/core/validator/rules/SyntaxRule.ts
|
|
claude generate server/modules/skill-fabric/src/core/validator/rules/SecurityRule.ts
|
|
\`\`\`
|
|
|
|
\*\*Fase 4: Executor\*\*
|
|
\`\`\`bash
|
|
claude generate server/modules/skill-fabric/src/core/executor/SkillExecutor.ts
|
|
claude generate server/modules/skill-fabric/src/core/executor/Sandbox.ts
|
|
claude generate server/modules/skill-fabric/src/core/executor/ReferenceResolver.ts
|
|
\`\`\`
|
|
|
|
\*\*Fase 5: Frontend Visual\*\*
|
|
\`\`\`bash
|
|
claude generate client/src/modules/skill-fabric/visual-studio/components/Canvas.tsx
|
|
claude generate client/src/modules/skill-fabric/visual-studio/components/NodePalette.tsx
|
|
claude generate client/src/modules/skill-fabric/visual-studio/hooks/useDragDrop.ts
|
|
\`\`\`
|
|
|
|
\*\*Fase 6: Frontend Code\*\*
|
|
\`\`\`bash
|
|
claude generate client/src/modules/skill-fabric/code-ide/components/MonacoEditor.tsx
|
|
claude generate client/src/modules/skill-fabric/code-ide/components/IntelliSenseProvider.ts
|
|
claude generate client/src/modules/skill-fabric/code-ide/templates/skill-template.ts
|
|
\`\`\`
|
|
|
|
\---
|
|
|
|
\#\# 4\. TESTES
|
|
|
|
\#\#\# 4.1 Estrutura de Testes
|
|
|
|
\`\`\`
|
|
tests/
|
|
├── unit/
|
|
│ ├── skill.entity.test.ts
|
|
│ ├── visual-compiler.test.ts
|
|
│ ├── code-compiler.test.ts
|
|
│ ├── markdown-compiler.test.ts
|
|
│ ├── validation-pipeline.test.ts
|
|
│ └── skill-executor.test.ts
|
|
├── integration/
|
|
│ ├── api.test.ts
|
|
│ ├── compile-execute.test.ts
|
|
│ └── reference-resolution.test.ts
|
|
└── e2e/
|
|
├── create-skill-flow.test.ts
|
|
├── visual-editor.test.ts
|
|
└── marketplace.test.ts
|
|
\`\`\`
|
|
|
|
\#\#\# 4.2 Exemplo de Teste
|
|
|
|
\`\`\`typescript
|
|
// tests/unit/skill.entity.test.ts
|
|
describe('Skill Entity', () \=\> {
|
|
it('should create skill with valid props', () \=\> {
|
|
const skill \= new Skill({
|
|
name: 'Test Skill',
|
|
slug: 'test\_skill',
|
|
type: 'code',
|
|
content: { sourceCode: 'export default () \=\> {}' },
|
|
tenantId: 1
|
|
});
|
|
|
|
expect(skill.id).toBeDefined();
|
|
expect(skill.status).toBe('draft');
|
|
expect(skill.version).toBe('0.0.1');
|
|
});
|
|
|
|
it('should validate slug format', () \=\> {
|
|
expect(() \=\> new Skill({ slug: 'invalid slug' })).toThrow();
|
|
expect(() \=\> new Skill({ slug: 'valid\_slug' })).not.toThrow();
|
|
});
|
|
|
|
it('should compile skill', async () \=\> {
|
|
const skill \= createTestSkill('code');
|
|
const compiled \= await skill.compile();
|
|
|
|
expect(compiled.code).toBeDefined();
|
|
expect(compiled.ast).toBeDefined();
|
|
expect(compiled.dependencies).toBeInstanceOf(Array);
|
|
});
|
|
});
|
|
\`\`\`
|
|
|
|
\---
|
|
|
|
\#\# 5\. MIGRAÇÃO E DEPLOY
|
|
|
|
\#\#\# 5.1 Migração de Dados
|
|
|
|
\`\`\`typescript
|
|
// scripts/migrate-skills.ts
|
|
export async function migrateLegacySkills() {
|
|
const legacySkills \= await db.query('SELECT \* FROM old\_automations');
|
|
|
|
for (const old of legacySkills) {
|
|
const skill \= new Skill({
|
|
name: old.name,
|
|
slug: generateSlug(old.name),
|
|
type: inferType(old),
|
|
content: convertContent(old),
|
|
tenantId: old.tenant\_id,
|
|
status: 'production'
|
|
});
|
|
|
|
await skillRepo.save(skill);
|
|
}
|
|
}
|
|
\`\`\`
|
|
|
|
\#\#\# 5.2 Feature Flags
|
|
|
|
\`\`\`typescript
|
|
// Configuração gradual
|
|
const featureFlags \= {
|
|
'skill-fabric.enabled': true,
|
|
'skill-fabric.visual-editor': true,
|
|
'skill-fabric.code-ide': true,
|
|
'skill-fabric.markdown-studio': false, // Beta
|
|
'skill-fabric.marketplace': false // Próxima release
|
|
};
|
|
\`\`\`
|
|
|
|
\---
|
|
|
|
\*\*Fim do Plano Técnico\*\*
|
|
\`\`\`
|
|
|
|
\---
|
|
|
|
Este plano técnico está pronto para gerar comandos no Claude Code. Ele contém:
|
|
|
|
✅ \*\*Estrutura de diretórios\*\* completa
|
|
✅ \*\*Funções e métodos\*\* detalhados para cada módulo
|
|
✅ \*\*Interfaces e tipos\*\* TypeScript
|
|
✅ \*\*Comandos de implementação\*\* por fase
|
|
✅ \*\*Testes\*\* estruturados
|
|
|
|
\*\*Para usar no Claude Code:\*\*
|
|
\`\`\`bash
|
|
\# Exemplo de comando
|
|
claude generate server/modules/skill-fabric/src/core/skill/Skill.entity.ts \--spec "Plano Técnico Skill Fabric v1.0"
|
|
\`\`\`
|
|
|
|
Quer que eu gere comandos específicos para algum módulo ou adicione mais detalhes de implementação?
|