diff --git a/.aios-core/core/synapse/layers/layer-processor.js b/.aios-core/core/synapse/layers/layer-processor.js index ab9273f33..28c416dee 100644 --- a/.aios-core/core/synapse/layers/layer-processor.js +++ b/.aios-core/core/synapse/layers/layer-processor.js @@ -50,7 +50,7 @@ class LayerProcessor { * @param {object[]} context.previousLayers - Results from previous layers * @returns {{ rules: string[], metadata: object } | null} Rules and metadata, or null to skip */ - process(context) { + process(_context) { throw new Error(`${this.name}: process() must be implemented by subclass`); } @@ -80,3 +80,5 @@ class LayerProcessor { } module.exports = LayerProcessor; + + diff --git a/.aios-core/infrastructure/scripts/validate-claude-integration.js b/.aios-core/infrastructure/scripts/validate-claude-integration.js new file mode 100644 index 000000000..534410f89 --- /dev/null +++ b/.aios-core/infrastructure/scripts/validate-claude-integration.js @@ -0,0 +1,105 @@ +#!/usr/bin/env node +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const { loadConfig } = require('./ide-sync/index'); + +function parseArgs(argv = process.argv.slice(2)) { + const args = new Set(argv); + return { + quiet: args.has('--quiet') || args.has('-q'), + json: args.has('--json'), + }; +} + +function countMarkdownFiles(dirPath) { + if (!fs.existsSync(dirPath)) return 0; + return fs.readdirSync(dirPath).filter((f) => f.endsWith('.md')).length; +} + +function validateClaudeIntegration(options = {}) { + const projectRoot = options.projectRoot || process.cwd(); + const rulesFile = options.rulesFile || path.join(projectRoot, '.claude', 'CLAUDE.md'); + const agentsDir = options.agentsDir || path.join(projectRoot, '.claude', 'commands', 'AIOS', 'agents'); + const hooksDir = options.hooksDir || path.join(projectRoot, '.claude', 'hooks'); + const sourceAgentsDir = + options.sourceAgentsDir || path.join(projectRoot, '.aios-core', 'development', 'agents'); + + const errors = []; + const warnings = []; + + if (!fs.existsSync(agentsDir)) { + errors.push(`Missing Claude agents dir: ${path.relative(projectRoot, agentsDir)}`); + } + if (!fs.existsSync(rulesFile)) { + warnings.push(`Claude rules file not found yet: ${path.relative(projectRoot, rulesFile)}`); + } + if (!fs.existsSync(hooksDir)) { + warnings.push(`Claude hooks dir not found yet: ${path.relative(projectRoot, hooksDir)}`); + } + + const sourceCount = countMarkdownFiles(sourceAgentsDir); + const claudeCount = countMarkdownFiles(agentsDir); + const redirectCount = Object.keys((loadConfig(projectRoot).redirects || {})).length; + const expectedCount = sourceCount > 0 ? sourceCount + redirectCount : sourceCount; + if (expectedCount > 0 && claudeCount !== expectedCount) { + warnings.push(`Claude agent count differs from expected (${claudeCount}/${expectedCount})`); + } + + return { + ok: errors.length === 0, + errors, + warnings, + metrics: { + sourceAgents: sourceCount, + claudeAgents: claudeCount, + expectedAgents: expectedCount, + }, + }; +} + +function formatHumanReport(result) { + if (result.ok) { + const lines = [`✅ Claude integration validation passed (agents: ${result.metrics.claudeAgents})`]; + if (result.warnings.length > 0) { + lines.push(...result.warnings.map((w) => `⚠️ ${w}`)); + } + return lines.join('\n'); + } + const lines = [ + `❌ Claude integration validation failed (${result.errors.length} issue(s))`, + ...result.errors.map((e) => `- ${e}`), + ]; + if (result.warnings.length > 0) { + lines.push(...result.warnings.map((w) => `⚠️ ${w}`)); + } + return lines.join('\n'); +} + +function main() { + const args = parseArgs(); + const result = validateClaudeIntegration(args); + + if (!args.quiet) { + if (args.json) { + console.log(JSON.stringify(result, null, 2)); + } else { + console.log(formatHumanReport(result)); + } + } + + if (!result.ok) { + process.exitCode = 1; + } +} + +if (require.main === module) { + main(); +} + +module.exports = { + validateClaudeIntegration, + parseArgs, + countMarkdownFiles, +}; diff --git a/.aios-core/infrastructure/scripts/validate-codex-integration.js b/.aios-core/infrastructure/scripts/validate-codex-integration.js new file mode 100644 index 000000000..f1cb286a4 --- /dev/null +++ b/.aios-core/infrastructure/scripts/validate-codex-integration.js @@ -0,0 +1,145 @@ +#!/usr/bin/env node +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const { loadConfig } = require('./ide-sync/index'); + +function getDefaultOptions() { + const projectRoot = process.cwd(); + return { + projectRoot, + instructionsFile: path.join(projectRoot, 'AGENTS.md'), + agentsDir: path.join(projectRoot, '.codex', 'agents'), + skillsDir: path.join(projectRoot, '.codex', 'skills'), + sourceAgentsDir: path.join(projectRoot, '.aios-core', 'development', 'agents'), + quiet: false, + json: false, + }; +} + +function parseArgs(argv = process.argv.slice(2)) { + const args = new Set(argv); + return { + quiet: args.has('--quiet') || args.has('-q'), + json: args.has('--json'), + }; +} + +function countMarkdownFiles(dirPath) { + if (!fs.existsSync(dirPath)) return 0; + return fs.readdirSync(dirPath).filter((f) => f.endsWith('.md')).length; +} + +function countSkillFiles(skillsDir) { + if (!fs.existsSync(skillsDir)) return 0; + const entries = fs.readdirSync(skillsDir, { withFileTypes: true }); + return entries + .filter((entry) => entry.isDirectory() && entry.name.startsWith('aios-')) + .filter((entry) => fs.existsSync(path.join(skillsDir, entry.name, 'SKILL.md'))) + .length; +} + +function validateCodexIntegration(options = {}) { + const projectRoot = options.projectRoot || process.cwd(); + const resolved = { + ...getDefaultOptions(), + ...options, + projectRoot, + instructionsFile: options.instructionsFile || path.join(projectRoot, 'AGENTS.md'), + agentsDir: options.agentsDir || path.join(projectRoot, '.codex', 'agents'), + skillsDir: options.skillsDir || path.join(projectRoot, '.codex', 'skills'), + sourceAgentsDir: options.sourceAgentsDir || path.join(projectRoot, '.aios-core', 'development', 'agents'), + }; + const errors = []; + const warnings = []; + + if (!fs.existsSync(resolved.instructionsFile)) { + warnings.push( + `Codex instructions file not found yet: ${path.relative(resolved.projectRoot, resolved.instructionsFile)}`, + ); + } + + if (!fs.existsSync(resolved.agentsDir)) { + errors.push(`Missing Codex agents dir: ${path.relative(resolved.projectRoot, resolved.agentsDir)}`); + } + + if (!fs.existsSync(resolved.skillsDir)) { + errors.push(`Missing Codex skills dir: ${path.relative(resolved.projectRoot, resolved.skillsDir)}`); + } + + const sourceCount = countMarkdownFiles(resolved.sourceAgentsDir); + const codexAgentsCount = countMarkdownFiles(resolved.agentsDir); + const codexSkillsCount = countSkillFiles(resolved.skillsDir); + const redirectCount = Object.keys((loadConfig(projectRoot).redirects || {})).length; + const expectedAgents = sourceCount > 0 ? sourceCount + redirectCount : sourceCount; + + if (expectedAgents > 0 && codexAgentsCount !== expectedAgents) { + warnings.push(`Codex agent count differs from expected (${codexAgentsCount}/${expectedAgents})`); + } + + if (sourceCount > 0 && codexSkillsCount !== sourceCount) { + warnings.push(`Codex skill count differs from source (${codexSkillsCount}/${sourceCount})`); + } + + return { + ok: errors.length === 0, + errors, + warnings, + metrics: { + sourceAgents: sourceCount, + expectedAgents, + codexAgents: codexAgentsCount, + codexSkills: codexSkillsCount, + }, + }; +} + +function formatHumanReport(result) { + if (result.ok) { + const lines = [ + `✅ Codex integration validation passed (agents: ${result.metrics.codexAgents}, skills: ${result.metrics.codexSkills})`, + ]; + if (result.warnings.length > 0) { + lines.push(...result.warnings.map((w) => `⚠️ ${w}`)); + } + return lines.join('\n'); + } + const lines = [ + `❌ Codex integration validation failed (${result.errors.length} issue(s))`, + ...result.errors.map((e) => `- ${e}`), + ]; + if (result.warnings.length > 0) { + lines.push(...result.warnings.map((w) => `⚠️ ${w}`)); + } + return lines.join('\n'); +} + +function main() { + const args = parseArgs(); + const result = validateCodexIntegration(args); + + if (!args.quiet) { + if (args.json) { + console.log(JSON.stringify(result, null, 2)); + } else { + console.log(formatHumanReport(result)); + } + } + + if (!result.ok) { + process.exitCode = 1; + } +} + +if (require.main === module) { + main(); +} + +module.exports = { + validateCodexIntegration, + parseArgs, + getDefaultOptions, + countMarkdownFiles, + countSkillFiles, +}; diff --git a/.aios-core/infrastructure/scripts/validate-gemini-integration.js b/.aios-core/infrastructure/scripts/validate-gemini-integration.js new file mode 100644 index 000000000..71a112e7c --- /dev/null +++ b/.aios-core/infrastructure/scripts/validate-gemini-integration.js @@ -0,0 +1,151 @@ +#!/usr/bin/env node +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const { loadConfig } = require('./ide-sync/index'); + +function getDefaultOptions() { + const projectRoot = process.cwd(); + return { + projectRoot, + rulesFile: path.join(projectRoot, '.gemini', 'rules.md'), + agentsDir: path.join(projectRoot, '.gemini', 'rules', 'AIOS', 'agents'), + commandsDir: path.join(projectRoot, '.gemini', 'commands'), + extensionDir: path.join(projectRoot, 'packages', 'gemini-aios-extension'), + sourceAgentsDir: path.join(projectRoot, '.aios-core', 'development', 'agents'), + quiet: false, + json: false, + }; +} + +function parseArgs(argv = process.argv.slice(2)) { + const args = new Set(argv); + return { + quiet: args.has('--quiet') || args.has('-q'), + json: args.has('--json'), + }; +} + +function countMarkdownFiles(dirPath) { + if (!fs.existsSync(dirPath)) return 0; + return fs.readdirSync(dirPath).filter((f) => f.endsWith('.md')).length; +} + +function validateGeminiIntegration(options = {}) { + const projectRoot = options.projectRoot || process.cwd(); + const resolved = { + ...getDefaultOptions(), + ...options, + projectRoot, + rulesFile: options.rulesFile || path.join(projectRoot, '.gemini', 'rules.md'), + agentsDir: options.agentsDir || path.join(projectRoot, '.gemini', 'rules', 'AIOS', 'agents'), + commandsDir: options.commandsDir || path.join(projectRoot, '.gemini', 'commands'), + extensionDir: options.extensionDir || path.join(projectRoot, 'packages', 'gemini-aios-extension'), + sourceAgentsDir: options.sourceAgentsDir || path.join(projectRoot, '.aios-core', 'development', 'agents'), + }; + const errors = []; + const warnings = []; + + if (!fs.existsSync(resolved.agentsDir)) { + errors.push(`Missing Gemini agents dir: ${path.relative(resolved.projectRoot, resolved.agentsDir)}`); + } + if (!fs.existsSync(resolved.commandsDir)) { + errors.push(`Missing Gemini commands dir: ${path.relative(resolved.projectRoot, resolved.commandsDir)}`); + } + + const sourceCount = countMarkdownFiles(resolved.sourceAgentsDir); + const geminiCount = countMarkdownFiles(resolved.agentsDir); + const redirectCount = Object.keys((loadConfig(projectRoot).redirects || {})).length; + const expectedAgents = sourceCount > 0 ? sourceCount + redirectCount : sourceCount; + const commandFiles = fs.existsSync(resolved.commandsDir) + ? fs.readdirSync(resolved.commandsDir).filter((f) => f.endsWith('.toml')) + : []; + const expectedCommandCount = sourceCount > 0 ? sourceCount + 1 : 0; + + if (sourceCount > 0 && commandFiles.length !== expectedCommandCount) { + warnings.push(`Gemini command count differs from source (${commandFiles.length}/${expectedCommandCount})`); + } + if (!commandFiles.includes('aios-menu.toml')) { + errors.push(`Missing Gemini command file: ${path.relative(resolved.projectRoot, path.join(resolved.commandsDir, 'aios-menu.toml'))}`); + } + if (expectedAgents > 0 && geminiCount !== expectedAgents) { + warnings.push(`Gemini agent count differs from expected (${geminiCount}/${expectedAgents})`); + } + + const requiredExtensionFiles = [ + 'extension.json', + 'README.md', + path.join('commands', 'aios-status.js'), + path.join('commands', 'aios-agents.js'), + path.join('commands', 'aios-validate.js'), + path.join('hooks', 'hooks.json'), + ]; + + for (const rel of requiredExtensionFiles) { + const abs = path.join(resolved.extensionDir, rel); + if (!fs.existsSync(abs)) { + errors.push(`Missing Gemini extension file: ${path.relative(resolved.projectRoot, abs)}`); + } + } + + return { + ok: errors.length === 0, + errors, + warnings, + metrics: { + sourceAgents: sourceCount, + expectedAgents, + geminiAgents: geminiCount, + geminiCommands: commandFiles.length, + }, + }; +} + +function formatHumanReport(result) { + if (result.ok) { + const lines = [ + `✅ Gemini integration validation passed (agents: ${result.metrics.geminiAgents}, commands: ${result.metrics.geminiCommands})`, + ]; + if (result.warnings.length > 0) { + lines.push(...result.warnings.map((w) => `⚠️ ${w}`)); + } + return lines.join('\n'); + } + const lines = [ + `❌ Gemini integration validation failed (${result.errors.length} issue(s))`, + ...result.errors.map((e) => `- ${e}`), + ]; + if (result.warnings.length > 0) { + lines.push(...result.warnings.map((w) => `⚠️ ${w}`)); + } + return lines.join('\n'); +} + +function main() { + const args = parseArgs(); + const result = validateGeminiIntegration(args); + + if (!args.quiet) { + if (args.json) { + console.log(JSON.stringify(result, null, 2)); + } else { + console.log(formatHumanReport(result)); + } + } + + if (!result.ok) { + process.exitCode = 1; + } +} + +if (require.main === module) { + main(); +} + +module.exports = { + validateGeminiIntegration, + parseArgs, + getDefaultOptions, + countMarkdownFiles, +}; diff --git a/.aios-core/infrastructure/scripts/validate-parity.js b/.aios-core/infrastructure/scripts/validate-parity.js new file mode 100644 index 000000000..25661a826 --- /dev/null +++ b/.aios-core/infrastructure/scripts/validate-parity.js @@ -0,0 +1,425 @@ +#!/usr/bin/env node +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const yaml = require('js-yaml'); +const { validateClaudeIntegration } = require('./validate-claude-integration'); +const { validateCodexIntegration } = require('./validate-codex-integration'); +const { validateGeminiIntegration } = require('./validate-gemini-integration'); +const { validateCodexSkills } = require('./codex-skills-sync/validate'); +const { validatePaths } = require('./validate-paths'); +const { loadConfig, getTransformer } = require('./ide-sync/index'); +const { parseAllAgents } = require('./ide-sync/agent-parser'); +const { generateAllRedirects } = require('./ide-sync/redirect-generator'); +const { validateAllIdes } = require('./ide-sync/validator'); +const { buildGeminiCommandFiles } = require('./ide-sync/gemini-commands'); + +function parseArgs(argv = process.argv.slice(2)) { + const args = new Set( + argv.filter((arg) => !arg.startsWith('--contract=') && !arg.startsWith('--diff=')), + ); + const contractArg = argv.find((arg) => arg.startsWith('--contract=')); + const diffArg = argv.find((arg) => arg.startsWith('--diff=')); + return { + quiet: args.has('--quiet') || args.has('-q'), + json: args.has('--json'), + contractPath: contractArg ? contractArg.slice('--contract='.length) : null, + diffPath: diffArg ? diffArg.slice('--diff='.length) : null, + }; +} + +function runSyncValidate(ide, projectRoot) { + const config = loadConfig(projectRoot); + const ideConfig = config.targets?.[ide]; + + if (!ideConfig || !ideConfig.enabled) { + return { + ok: false, + errors: [`IDE not configured or disabled: ${ide}`], + warnings: [], + raw: '', + }; + } + + const agentsDir = path.join(projectRoot, config.source); + const agents = parseAllAgents(agentsDir); + const transformer = getTransformer(ideConfig.format); + const expectedFiles = []; + + for (const agent of agents) { + if (agent.error) { + continue; + } + try { + const content = transformer.transform(agent); + const filename = transformer.getFilename(agent); + expectedFiles.push({ filename, content }); + } catch (_error) { + // Ignore transform failures here to match ide-sync validate behavior. + } + } + + const redirects = generateAllRedirects( + config.redirects, + path.join(projectRoot, ideConfig.path), + ideConfig.format, + ); + for (const redirect of redirects) { + expectedFiles.push({ + filename: redirect.filename, + content: redirect.content, + }); + } + + const ideConfigs = { + [ide]: { + expectedFiles, + targetDir: path.join(projectRoot, ideConfig.path), + }, + }; + + if (ide === 'gemini') { + const commandFiles = buildGeminiCommandFiles(agents).map((entry) => ({ + filename: entry.filename, + content: entry.content, + })); + ideConfigs['gemini-commands'] = { + expectedFiles: commandFiles, + targetDir: path.join(projectRoot, '.gemini', 'commands'), + }; + } + + const results = validateAllIdes(ideConfigs, config.redirects); + const ideResult = results.ides[ide] || { total: {} }; + const errors = []; + const warnings = []; + if (ideResult.total.missing > 0 || ideResult.total.drift > 0) { + errors.push(`Sync validation failed for ${ide}`); + } + if (ideResult.total.orphaned > 0) { + warnings.push(`${ideResult.total.orphaned} orphaned files found for ${ide}`); + } + + return { + ok: results.summary.pass, + errors, + warnings, + raw: JSON.stringify(results.summary), + }; +} +function getDefaultContractPath(projectRoot = process.cwd()) { + return path.join( + projectRoot, + '.aios-core', + 'infrastructure', + 'contracts', + 'compatibility', + 'aios-4.0.4.yaml', + ); +} + +function loadCompatibilityContract(contractPath) { + if (!contractPath || !fs.existsSync(contractPath)) { + return null; + } + const raw = fs.readFileSync(contractPath, 'utf8'); + return yaml.load(raw); +} + +function normalizeResult(input) { + if (!input || typeof input !== 'object') { + return { ok: false, errors: ['Validator returned invalid result'], warnings: [] }; + } + return { + ok: Boolean(input.ok), + errors: Array.isArray(input.errors) ? input.errors : [], + warnings: Array.isArray(input.warnings) ? input.warnings : [], + metrics: input.metrics || {}, + }; +} + +function escapeRegex(value) { + return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +} + +function validateCompatibilityContract(contract, resultById, options = {}) { + const violations = []; + + if (!contract || typeof contract !== 'object') { + return ['Compatibility contract is missing or invalid']; + } + + const matrix = Array.isArray(contract.ide_matrix) ? contract.ide_matrix : []; + if (matrix.length === 0) { + return ['Compatibility contract ide_matrix is empty']; + } + + const docsPath = options.docsPath; + if (!docsPath || !fs.existsSync(docsPath)) { + violations.push(`Compatibility matrix document not found: ${docsPath || 'undefined'}`); + return violations; + } + const docsContent = fs.readFileSync(docsPath, 'utf8'); + + for (const ide of matrix) { + const ideName = ide.ide || 'unknown'; + const displayName = ide.display_name || ideName; + const requiredChecks = Array.isArray(ide.required_checks) ? ide.required_checks : []; + const expectedStatus = ide.expected_status; + + if (!expectedStatus) { + violations.push(`Contract missing expected_status for IDE "${ideName}"`); + } + + const rowRegex = new RegExp( + `\\|\\s*${escapeRegex(displayName)}\\s*\\|\\s*${escapeRegex(expectedStatus || '')}\\s*\\|`, + 'i', + ); + if (!rowRegex.test(docsContent)) { + violations.push( + `Docs matrix mismatch for "${displayName}": expected status "${expectedStatus}" in ${options.docsPathRelative}`, + ); + } + + for (const checkId of requiredChecks) { + const checkResult = resultById[checkId]; + if (!checkResult) { + violations.push(`Contract requires unknown check "${checkId}" for IDE "${ideName}"`); + continue; + } + if (!checkResult.ok) { + violations.push(`Contract violation for "${ideName}": required check "${checkId}" failed`); + } + } + } + + const globalRequiredChecks = Array.isArray(contract.global_required_checks) + ? contract.global_required_checks + : []; + for (const checkId of globalRequiredChecks) { + const checkResult = resultById[checkId]; + if (!checkResult) { + violations.push(`Contract requires unknown global check "${checkId}"`); + continue; + } + if (!checkResult.ok) { + violations.push(`Contract violation: global required check "${checkId}" failed`); + } + } + + return violations; +} + +function sortUnique(values = []) { + return [...new Set(values)].sort(); +} + +function diffCompatibilityContracts(currentContract, previousContract) { + if (!currentContract || !previousContract) { + return null; + } + + const currentRelease = currentContract.release || null; + const previousRelease = previousContract.release || null; + const releaseChanged = currentRelease !== previousRelease; + + const currentGlobalChecks = sortUnique(currentContract.global_required_checks || []); + const previousGlobalChecks = sortUnique(previousContract.global_required_checks || []); + const globalChecksAdded = currentGlobalChecks.filter((item) => !previousGlobalChecks.includes(item)); + const globalChecksRemoved = previousGlobalChecks.filter((item) => !currentGlobalChecks.includes(item)); + + const currentByIde = Object.fromEntries((currentContract.ide_matrix || []).map((item) => [item.ide, item])); + const previousByIde = Object.fromEntries((previousContract.ide_matrix || []).map((item) => [item.ide, item])); + const ideKeys = sortUnique([...Object.keys(currentByIde), ...Object.keys(previousByIde)]); + + const ideChanges = []; + for (const ide of ideKeys) { + const current = currentByIde[ide]; + const previous = previousByIde[ide]; + + if (!previous && current) { + ideChanges.push({ ide, type: 'added', current }); + continue; + } + if (previous && !current) { + ideChanges.push({ ide, type: 'removed', previous }); + continue; + } + + const currentStatus = current.expected_status || null; + const previousStatus = previous.expected_status || null; + const statusChanged = currentStatus !== previousStatus; + const currentChecks = sortUnique(current.required_checks || []); + const previousChecks = sortUnique(previous.required_checks || []); + const checksAdded = currentChecks.filter((item) => !previousChecks.includes(item)); + const checksRemoved = previousChecks.filter((item) => !currentChecks.includes(item)); + + if (statusChanged || checksAdded.length > 0 || checksRemoved.length > 0) { + ideChanges.push({ + ide, + type: 'changed', + status: { previous: previousStatus, current: currentStatus }, + required_checks: { + added: checksAdded, + removed: checksRemoved, + }, + }); + } + } + + return { + from_release: previousRelease, + to_release: currentRelease, + release_changed: releaseChanged, + global_required_checks: { + added: globalChecksAdded, + removed: globalChecksRemoved, + }, + ide_changes: ideChanges, + has_changes: + releaseChanged + || globalChecksAdded.length > 0 + || globalChecksRemoved.length > 0 + || ideChanges.length > 0, + }; +} + +function runParityValidation(options = {}, deps = {}) { + const projectRoot = options.projectRoot || process.cwd(); + const runSync = deps.runSyncValidate || runSyncValidate; + const runClaudeIntegration = deps.validateClaudeIntegration || validateClaudeIntegration; + const runCodexIntegration = deps.validateCodexIntegration || validateCodexIntegration; + const runGeminiIntegration = deps.validateGeminiIntegration || validateGeminiIntegration; + const runCodexSkills = deps.validateCodexSkills || validateCodexSkills; + const runPaths = deps.validatePaths || validatePaths; + const resolvedContractPath = options.contractPath + ? path.resolve(projectRoot, options.contractPath) + : getDefaultContractPath(projectRoot); + const loadContract = deps.loadCompatibilityContract || loadCompatibilityContract; + const contract = loadContract(resolvedContractPath); + const resolvedDiffPath = options.diffPath ? path.resolve(projectRoot, options.diffPath) : null; + const previousContract = resolvedDiffPath ? loadContract(resolvedDiffPath) : null; + const docsPath = path.join(projectRoot, 'docs', 'ide-integration.md'); + const docsPathRelative = path.relative(projectRoot, docsPath); + const checks = [ + { id: 'claude-sync', exec: () => runSync('claude-code', projectRoot) }, + { id: 'claude-integration', exec: () => runClaudeIntegration({ projectRoot }) }, + { id: 'codex-sync', exec: () => runSync('codex', projectRoot) }, + { id: 'codex-integration', exec: () => runCodexIntegration({ projectRoot }) }, + { id: 'gemini-sync', exec: () => runSync('gemini', projectRoot) }, + { id: 'gemini-integration', exec: () => runGeminiIntegration({ projectRoot }) }, + { id: 'cursor-sync', exec: () => runSync('cursor', projectRoot) }, + { id: 'github-copilot-sync', exec: () => runSync('github-copilot', projectRoot) }, + { id: 'antigravity-sync', exec: () => runSync('antigravity', projectRoot) }, + { id: 'codex-skills', exec: () => runCodexSkills({ projectRoot, strict: true, quiet: true }) }, + { id: 'paths', exec: () => runPaths({ projectRoot }) }, + ]; + + const results = checks.map((check) => { + const normalized = normalizeResult(check.exec()); + return { id: check.id, ...normalized }; + }); + const resultById = Object.fromEntries(results.map((r) => [r.id, r])); + const contractViolations = validateCompatibilityContract(contract, resultById, { + docsPath, + docsPathRelative, + }); + const contractSummary = contract + ? { + release: contract.release || null, + path: path.relative(projectRoot, resolvedContractPath), + } + : { + release: null, + path: path.relative(projectRoot, resolvedContractPath), + }; + + return { + ok: results.every((r) => r.ok) && contractViolations.length === 0, + checks: results, + contract: contractSummary, + contractDiff: diffCompatibilityContracts(contract, previousContract), + contractViolations, + }; +} + +function formatHumanReport(result) { + const lines = []; + if (result.contract && result.contract.release) { + lines.push(`Compatibility Contract: ${result.contract.release} (${result.contract.path})`); + lines.push(''); + } + if (result.contractDiff) { + lines.push( + `Contract Diff: ${result.contractDiff.from_release || 'unknown'} -> ${result.contractDiff.to_release || 'unknown'}`, + ); + if (!result.contractDiff.has_changes) { + lines.push('- no changes'); + } else { + if (result.contractDiff.release_changed) { + lines.push('- release changed'); + } + const globalAdded = result.contractDiff.global_required_checks.added || []; + const globalRemoved = result.contractDiff.global_required_checks.removed || []; + if (globalAdded.length > 0) { + lines.push(`- global checks added: ${globalAdded.join(', ')}`); + } + if (globalRemoved.length > 0) { + lines.push(`- global checks removed: ${globalRemoved.join(', ')}`); + } + for (const ideChange of result.contractDiff.ide_changes || []) { + lines.push(`- ${ideChange.ide}: ${ideChange.type}`); + } + } + lines.push(''); + } + for (const check of result.checks) { + lines.push(`${check.ok ? '✅' : '❌'} ${check.id}`); + if (check.errors.length > 0) { + lines.push(...check.errors.map((e) => `- ${e}`)); + } + if (check.warnings.length > 0) { + lines.push(...check.warnings.map((w) => `⚠️ ${w}`)); + } + } + if (Array.isArray(result.contractViolations) && result.contractViolations.length > 0) { + lines.push(''); + lines.push('❌ Compatibility Contract Violations'); + lines.push(...result.contractViolations.map((v) => `- ${v}`)); + } + lines.push(''); + lines.push(result.ok ? '✅ Parity validation passed' : '❌ Parity validation failed'); + return lines.join('\n'); +} + +function main() { + const args = parseArgs(); + const result = runParityValidation(args); + + if (!args.quiet) { + if (args.json) { + console.log(JSON.stringify(result, null, 2)); + } else { + console.log(formatHumanReport(result)); + } + } + + if (!result.ok) { + process.exitCode = 1; + } +} + +if (require.main === module) { + main(); +} + +module.exports = { + parseArgs, + runSyncValidate, + runParityValidation, + normalizeResult, + formatHumanReport, + diffCompatibilityContracts, +}; + diff --git a/.codex/skills/aios-analyst/SKILL.md b/.codex/skills/aios-analyst/SKILL.md new file mode 100644 index 000000000..084553cbb --- /dev/null +++ b/.codex/skills/aios-analyst/SKILL.md @@ -0,0 +1,28 @@ +--- +name: aios-analyst +description: Business Analyst (Atlas). Use for market research, competitive analysis, user research, brainstorming session facilitation, structured ideation workshops, feasibility studies, i... +--- + +# AIOS Business Analyst Activator + +## When To Use +Use for market research, competitive analysis, user research, brainstorming session facilitation, structured ideation workshops, feasibility studies, industry trends analysis, project discovery (brownfield documentati... + +## Activation Protocol +1. Load `.aios-core/development/agents/analyst.md` as source of truth (fallback: `.codex/agents/analyst.md`). +2. Adopt this agent persona and command system. +3. Generate greeting via `node .aios-core/development/scripts/generate-greeting.js analyst` and show it first. +4. Stay in this persona until the user asks to switch or exit. + +## Starter Commands +- `*help` - Show all available commands with descriptions +- `*create-project-brief` - Create project brief document +- `*perform-market-research` - Create market research analysis +- `*create-competitor-analysis` - Create competitive analysis +- `*brainstorm` - Facilitate structured brainstorming +- `*guide` - Show comprehensive usage guide for this agent + +## Non-Negotiables +- Follow `.aios-core/constitution.md`. +- Execute workflows/tasks only from declared dependencies. +- Do not invent requirements outside the project artifacts. diff --git a/.codex/skills/aios-architect/SKILL.md b/.codex/skills/aios-architect/SKILL.md new file mode 100644 index 000000000..c9bec35a4 --- /dev/null +++ b/.codex/skills/aios-architect/SKILL.md @@ -0,0 +1,30 @@ +--- +name: aios-architect +description: Architect (Aria). Use for system architecture (fullstack, backend, frontend, infrastructure), technology stack selection (technical evaluation), API design (REST/GraphQL/tRPC/We... +--- + +# AIOS Architect Activator + +## When To Use +Use for system architecture (fullstack, backend, frontend, infrastructure), technology stack selection (technical evaluation), API design (REST/GraphQL/tRPC/WebSocket), security architecture, performance optimization,... + +## Activation Protocol +1. Load `.aios-core/development/agents/architect.md` as source of truth (fallback: `.codex/agents/architect.md`). +2. Adopt this agent persona and command system. +3. Generate greeting via `node .aios-core/development/scripts/generate-greeting.js architect` and show it first. +4. Stay in this persona until the user asks to switch or exit. + +## Starter Commands +- `*help` - Show all available commands with descriptions +- `*create-full-stack-architecture` - Complete system architecture +- `*create-backend-architecture` - Backend architecture design +- `*create-front-end-architecture` - Frontend architecture design +- `*document-project` - Generate project documentation +- `*research` - Generate deep research prompt +- `*analyze-project-structure` - Analyze project for new feature implementation (WIS-15) +- `*guide` - Show comprehensive usage guide for this agent + +## Non-Negotiables +- Follow `.aios-core/constitution.md`. +- Execute workflows/tasks only from declared dependencies. +- Do not invent requirements outside the project artifacts. diff --git a/.codex/skills/aios-data-engineer/SKILL.md b/.codex/skills/aios-data-engineer/SKILL.md new file mode 100644 index 000000000..f6b8e0def --- /dev/null +++ b/.codex/skills/aios-data-engineer/SKILL.md @@ -0,0 +1,30 @@ +--- +name: aios-data-engineer +description: Database Architect & Operations Engineer (Dara). Use for database design, schema architecture, Supabase configuration, RLS policies, migrations, query optimization, data modelin... +--- + +# AIOS Database Architect & Operations Engineer Activator + +## When To Use +Use for database design, schema architecture, Supabase configuration, RLS policies, migrations, query optimization, data modeling, operations, and monitoring + +## Activation Protocol +1. Load `.aios-core/development/agents/data-engineer.md` as source of truth (fallback: `.codex/agents/data-engineer.md`). +2. Adopt this agent persona and command system. +3. Generate greeting via `node .aios-core/development/scripts/generate-greeting.js data-engineer` and show it first. +4. Stay in this persona until the user asks to switch or exit. + +## Starter Commands +- `*help` - Show all available commands with descriptions +- `*guide` - Show comprehensive usage guide for this agent +- `*yolo` - Toggle permission mode (cycle: ask > auto > explore) +- `*exit` - Exit data-engineer mode +- `*doc-out` - Output complete document +- `*execute-checklist {checklist}` - Run DBA checklist +- `*create-schema` - Design database schema +- `*create-rls-policies` - Design RLS policies + +## Non-Negotiables +- Follow `.aios-core/constitution.md`. +- Execute workflows/tasks only from declared dependencies. +- Do not invent requirements outside the project artifacts. diff --git a/.codex/skills/aios-dev/SKILL.md b/.codex/skills/aios-dev/SKILL.md new file mode 100644 index 000000000..ce94eeaf8 --- /dev/null +++ b/.codex/skills/aios-dev/SKILL.md @@ -0,0 +1,30 @@ +--- +name: aios-dev +description: Full Stack Developer (Dex). Use for code implementation, debugging, refactoring, and development best practices +--- + +# AIOS Full Stack Developer Activator + +## When To Use +Use for code implementation, debugging, refactoring, and development best practices + +## Activation Protocol +1. Load `.aios-core/development/agents/dev.md` as source of truth (fallback: `.codex/agents/dev.md`). +2. Adopt this agent persona and command system. +3. Generate greeting via `node .aios-core/development/scripts/generate-greeting.js dev` and show it first. +4. Stay in this persona until the user asks to switch or exit. + +## Starter Commands +- `*help` - Show all available commands with descriptions +- `*develop` - Implement story tasks (modes: yolo, interactive, preflight) +- `*develop-yolo` - Autonomous development mode +- `*execute-subtask` - Execute a single subtask from implementation.yaml (13-step Coder Agent workflow) +- `*verify-subtask` - Verify subtask completion using configured verification (command, api, browser, e2e) +- `*track-attempt` - Track implementation attempt for a subtask (registers in recovery/attempts.json) +- `*rollback` - Rollback to last good state for a subtask (--hard to skip confirmation) +- `*build-resume` - Resume autonomous build from last checkpoint + +## Non-Negotiables +- Follow `.aios-core/constitution.md`. +- Execute workflows/tasks only from declared dependencies. +- Do not invent requirements outside the project artifacts. diff --git a/.codex/skills/aios-devops/SKILL.md b/.codex/skills/aios-devops/SKILL.md new file mode 100644 index 000000000..6955c6b4e --- /dev/null +++ b/.codex/skills/aios-devops/SKILL.md @@ -0,0 +1,30 @@ +--- +name: aios-devops +description: GitHub Repository Manager & DevOps Specialist (Gage). Use for repository operations, version management, CI/CD, quality gates, and GitHub push operations. ONLY agent authorized... +--- + +# AIOS GitHub Repository Manager & DevOps Specialist Activator + +## When To Use +Use for repository operations, version management, CI/CD, quality gates, and GitHub push operations. ONLY agent authorized to push to remote repository. + +## Activation Protocol +1. Load `.aios-core/development/agents/devops.md` as source of truth (fallback: `.codex/agents/devops.md`). +2. Adopt this agent persona and command system. +3. Generate greeting via `node .aios-core/development/scripts/generate-greeting.js devops` and show it first. +4. Stay in this persona until the user asks to switch or exit. + +## Starter Commands +- `*help` - Show all available commands with descriptions +- `*detect-repo` - Detect repository context (framework-dev vs project-dev) +- `*version-check` - Analyze version and recommend next +- `*pre-push` - Run all quality checks before push +- `*push` - Execute git push after quality gates pass +- `*create-pr` - Create pull request from current branch +- `*configure-ci` - Setup/update GitHub Actions workflows +- `*release` - Create versioned release with changelog + +## Non-Negotiables +- Follow `.aios-core/constitution.md`. +- Execute workflows/tasks only from declared dependencies. +- Do not invent requirements outside the project artifacts. diff --git a/.codex/skills/aios-master/SKILL.md b/.codex/skills/aios-master/SKILL.md new file mode 100644 index 000000000..37c0693d5 --- /dev/null +++ b/.codex/skills/aios-master/SKILL.md @@ -0,0 +1,30 @@ +--- +name: aios-master +description: AIOS Master Orchestrator & Framework Developer (Orion). Use when you need comprehensive expertise across all domains, framework component creation/modification, workflow orchest... +--- + +# AIOS AIOS Master Orchestrator & Framework Developer Activator + +## When To Use +Use when you need comprehensive expertise across all domains, framework component creation/modification, workflow orchestration, or running tasks that don't require a specialized persona. + +## Activation Protocol +1. Load `.aios-core/development/agents/aios-master.md` as source of truth (fallback: `.codex/agents/aios-master.md`). +2. Adopt this agent persona and command system. +3. Generate greeting via `node .aios-core/development/scripts/generate-greeting.js aios-master` and show it first. +4. Stay in this persona until the user asks to switch or exit. + +## Starter Commands +- `*help` - Show all available commands with descriptions +- `*kb` - Toggle KB mode (loads AIOS Method knowledge) +- `*status` - Show current context and progress +- `*guide` - Show comprehensive usage guide for this agent +- `*exit` - Exit agent mode +- `*create` - Create new AIOS component (agent, task, workflow, template, checklist) +- `*modify` - Modify existing AIOS component +- `*update-manifest` - Update team manifest + +## Non-Negotiables +- Follow `.aios-core/constitution.md`. +- Execute workflows/tasks only from declared dependencies. +- Do not invent requirements outside the project artifacts. diff --git a/.codex/skills/aios-pm/SKILL.md b/.codex/skills/aios-pm/SKILL.md new file mode 100644 index 000000000..40697447f --- /dev/null +++ b/.codex/skills/aios-pm/SKILL.md @@ -0,0 +1,30 @@ +--- +name: aios-pm +description: Product Manager (Morgan). Use for PRD creation (greenfield and brownfield), epic creation and management, product strategy and vision, feature prioritization (MoSCoW, RICE), roa... +--- + +# AIOS Product Manager Activator + +## When To Use +Use for PRD creation (greenfield and brownfield), epic creation and management, product strategy and vision, feature prioritization (MoSCoW, RICE), roadmap planning, business case development, go/no-go decisions, scop... + +## Activation Protocol +1. Load `.aios-core/development/agents/pm.md` as source of truth (fallback: `.codex/agents/pm.md`). +2. Adopt this agent persona and command system. +3. Generate greeting via `node .aios-core/development/scripts/generate-greeting.js pm` and show it first. +4. Stay in this persona until the user asks to switch or exit. + +## Starter Commands +- `*help` - Show all available commands with descriptions +- `*create-prd` - Create product requirements document +- `*create-brownfield-prd` - Create PRD for existing projects +- `*create-epic` - Create epic for brownfield +- `*create-story` - Create user story +- `*research` - Generate deep research prompt +- `*execute-epic` - Execute epic plan with wave-based parallel development +- `*gather-requirements` - Elicit and document requirements from stakeholders + +## Non-Negotiables +- Follow `.aios-core/constitution.md`. +- Execute workflows/tasks only from declared dependencies. +- Do not invent requirements outside the project artifacts. diff --git a/.codex/skills/aios-po/SKILL.md b/.codex/skills/aios-po/SKILL.md new file mode 100644 index 000000000..9990bd429 --- /dev/null +++ b/.codex/skills/aios-po/SKILL.md @@ -0,0 +1,30 @@ +--- +name: aios-po +description: Product Owner (Pax). Use for backlog management, story refinement, acceptance criteria, sprint planning, and prioritization decisions +--- + +# AIOS Product Owner Activator + +## When To Use +Use for backlog management, story refinement, acceptance criteria, sprint planning, and prioritization decisions + +## Activation Protocol +1. Load `.aios-core/development/agents/po.md` as source of truth (fallback: `.codex/agents/po.md`). +2. Adopt this agent persona and command system. +3. Generate greeting via `node .aios-core/development/scripts/generate-greeting.js po` and show it first. +4. Stay in this persona until the user asks to switch or exit. + +## Starter Commands +- `*help` - Show all available commands with descriptions +- `*backlog-add` - Add item to story backlog (follow-up/tech-debt/enhancement) +- `*backlog-review` - Generate backlog review for sprint planning +- `*backlog-summary` - Quick backlog status summary +- `*stories-index` - Regenerate story index from docs/stories/ +- `*validate-story-draft` - Validate story quality and completeness (START of story lifecycle) +- `*close-story` - Close completed story, update epic/backlog, suggest next (END of story lifecycle) +- `*execute-checklist-po` - Run PO master checklist + +## Non-Negotiables +- Follow `.aios-core/constitution.md`. +- Execute workflows/tasks only from declared dependencies. +- Do not invent requirements outside the project artifacts. diff --git a/.codex/skills/aios-qa/SKILL.md b/.codex/skills/aios-qa/SKILL.md new file mode 100644 index 000000000..012a3b0d7 --- /dev/null +++ b/.codex/skills/aios-qa/SKILL.md @@ -0,0 +1,30 @@ +--- +name: aios-qa +description: Test Architect & Quality Advisor (Quinn). Use for comprehensive test architecture review, quality gate decisions, and code improvement. Provides thorough analysis including requ... +--- + +# AIOS Test Architect & Quality Advisor Activator + +## When To Use +Use for comprehensive test architecture review, quality gate decisions, and code improvement. Provides thorough analysis including requirements traceability, risk assessment, and test strategy. Advisory only - teams c... + +## Activation Protocol +1. Load `.aios-core/development/agents/qa.md` as source of truth (fallback: `.codex/agents/qa.md`). +2. Adopt this agent persona and command system. +3. Generate greeting via `node .aios-core/development/scripts/generate-greeting.js qa` and show it first. +4. Stay in this persona until the user asks to switch or exit. + +## Starter Commands +- `*help` - Show all available commands with descriptions +- `*code-review` - Run automated review (scope: uncommitted or committed) +- `*review` - Comprehensive story review with gate decision +- `*gate` - Create quality gate decision +- `*nfr-assess` - Validate non-functional requirements +- `*risk-profile` - Generate risk assessment matrix +- `*security-check` - Run 8-point security vulnerability scan +- `*test-design` - Create comprehensive test scenarios + +## Non-Negotiables +- Follow `.aios-core/constitution.md`. +- Execute workflows/tasks only from declared dependencies. +- Do not invent requirements outside the project artifacts. diff --git a/.codex/skills/aios-sm/SKILL.md b/.codex/skills/aios-sm/SKILL.md new file mode 100644 index 000000000..e1ef9f25c --- /dev/null +++ b/.codex/skills/aios-sm/SKILL.md @@ -0,0 +1,26 @@ +--- +name: aios-sm +description: Scrum Master (River). Use for user story creation from PRD, story validation and completeness checking, acceptance criteria definition, story refinement, sprint planning, backlo... +--- + +# AIOS Scrum Master Activator + +## When To Use +Use for user story creation from PRD, story validation and completeness checking, acceptance criteria definition, story refinement, sprint planning, backlog grooming, retrospectives, daily standup facilitation, and lo... + +## Activation Protocol +1. Load `.aios-core/development/agents/sm.md` as source of truth (fallback: `.codex/agents/sm.md`). +2. Adopt this agent persona and command system. +3. Generate greeting via `node .aios-core/development/scripts/generate-greeting.js sm` and show it first. +4. Stay in this persona until the user asks to switch or exit. + +## Starter Commands +- `*help` - Show all available commands with descriptions +- `*draft` - Create next user story +- `*story-checklist` - Run story draft checklist +- `*guide` - Show comprehensive usage guide for this agent + +## Non-Negotiables +- Follow `.aios-core/constitution.md`. +- Execute workflows/tasks only from declared dependencies. +- Do not invent requirements outside the project artifacts. diff --git a/.codex/skills/aios-squad-creator/SKILL.md b/.codex/skills/aios-squad-creator/SKILL.md new file mode 100644 index 000000000..739127cce --- /dev/null +++ b/.codex/skills/aios-squad-creator/SKILL.md @@ -0,0 +1,30 @@ +--- +name: aios-squad-creator +description: Squad Creator (Craft). Use to create, validate, publish and manage squads +--- + +# AIOS Squad Creator Activator + +## When To Use +Use to create, validate, publish and manage squads + +## Activation Protocol +1. Load `.aios-core/development/agents/squad-creator.md` as source of truth (fallback: `.codex/agents/squad-creator.md`). +2. Adopt this agent persona and command system. +3. Generate greeting via `node .aios-core/development/scripts/generate-greeting.js squad-creator` and show it first. +4. Stay in this persona until the user asks to switch or exit. + +## Starter Commands +- `*help` - Show all available commands with descriptions +- `*design-squad` - Design squad from documentation with intelligent recommendations +- `*create-squad` - Create new squad following task-first architecture +- `*validate-squad` - Validate squad against JSON Schema and AIOS standards +- `*list-squads` - List all local squads in the project +- `*migrate-squad` - Migrate legacy squad to AIOS 2.1 format +- `*analyze-squad` - Analyze squad structure, coverage, and get improvement suggestions +- `*extend-squad` - Add new components (agents, tasks, templates, etc.) to existing squad + +## Non-Negotiables +- Follow `.aios-core/constitution.md`. +- Execute workflows/tasks only from declared dependencies. +- Do not invent requirements outside the project artifacts. diff --git a/.codex/skills/aios-ux-design-expert/SKILL.md b/.codex/skills/aios-ux-design-expert/SKILL.md new file mode 100644 index 000000000..f2b94fe42 --- /dev/null +++ b/.codex/skills/aios-ux-design-expert/SKILL.md @@ -0,0 +1,23 @@ +--- +name: aios-ux-design-expert +description: UX/UI Designer & Design System Architect (Uma). Complete design workflow - user research, wireframes, design systems, token extraction, component building, and quality assurance +--- + +# AIOS UX/UI Designer & Design System Architect Activator + +## When To Use +Complete design workflow - user research, wireframes, design systems, token extraction, component building, and quality assurance + +## Activation Protocol +1. Load `.aios-core/development/agents/ux-design-expert.md` as source of truth (fallback: `.codex/agents/ux-design-expert.md`). +2. Adopt this agent persona and command system. +3. Generate greeting via `node .aios-core/development/scripts/generate-greeting.js ux-design-expert` and show it first. +4. Stay in this persona until the user asks to switch or exit. + +## Starter Commands +- `*help` - List available commands + +## Non-Negotiables +- Follow `.aios-core/constitution.md`. +- Execute workflows/tasks only from declared dependencies. +- Do not invent requirements outside the project artifacts. diff --git a/README.md b/README.md index b8a12f27d..34bf94e1f 100644 --- a/README.md +++ b/README.md @@ -190,6 +190,17 @@ Estas regras fornecem: 4. **Use comandos AIOS**: Digite `*help` para ver comandos disponíveis 5. **Siga o fluxo**: Veja o [Guia do usuário](docs/guides/user-guide.md) para mais detalhes +### Interface Web de Planejamento + +O diretório `web-app/` contém uma interface opcional de planejamento em formato chat para apoiar a fase de descoberta e classificação inicial do projeto. Ela segue o princípio do repositório de `UI Third`: a CLI continua sendo a fonte da verdade, e a interface serve como apoio para coleta orientada de contexto, preview e geração de artefatos. + +Comandos úteis: + +```bash +npm run web:install +npm run web:dev +npm run web:build +``` ### Referência de Comandos CLI O Synkra AIOS oferece uma CLI moderna e cross-platform com comandos intuitivos: @@ -668,3 +679,4 @@ Veja também: --- **[⬆ Voltar ao topo](#synkra-aios-framework-universal-de-agentes-ia-)** + diff --git a/docs/ide-integration.md b/docs/ide-integration.md index 4ac2c1916..dea4788ae 100644 --- a/docs/ide-integration.md +++ b/docs/ide-integration.md @@ -15,6 +15,17 @@ Guide for integrating AIOS with supported IDEs and AI development platforms. AIOS supports 9 AI-powered development platforms. Choose the one that best fits your workflow. +### AIOS Compatibility Status + +| IDE | Status | +|-----|--------| +| Claude Code | Works | +| Gemini CLI | Works | +| Codex CLI | Limited | +| Cursor | Limited | +| GitHub Copilot | Limited | +| AntiGravity | Limited | + ### Quick Comparison Table | Feature | Claude Code | Cursor | Windsurf | Cline | Copilot | AntiGravity | Roo Code | Gemini CLI | Trae | diff --git a/eslint.config.js b/eslint.config.js index 4b41d3c7a..9b1fcce2a 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -19,6 +19,7 @@ module.exports = [ '**/coverage/**', '**/build/**', '**/dist/**', + 'aios-core/**', '**/.next/**', // Dashboard has its own ESLint config 'apps/dashboard/**', @@ -165,6 +166,20 @@ module.exports = [ }, }, + // Browser app files + { + files: ['web-app/**/*.js'], + languageOptions: { + sourceType: 'module', + globals: { + document: 'readonly', + window: 'readonly', + navigator: 'readonly', + fetch: 'readonly', + location: 'readonly', + }, + }, + }, // Test files - more relaxed rules { files: ['**/*.test.js', '**/*.spec.js', '**/tests/**/*.js'], @@ -174,3 +189,5 @@ module.exports = [ }, }, ]; + + diff --git a/jest.config.js b/jest.config.js index 6600e5b88..3a0ff8645 100644 --- a/jest.config.js +++ b/jest.config.js @@ -129,6 +129,7 @@ module.exports = { roots: [''], moduleDirectories: ['node_modules', '.'], setupFilesAfterEnv: ['/tests/setup.js'], + modulePathIgnorePatterns: ['/aios-core/'], // Cross-platform config from REMOTE globals: { @@ -137,3 +138,4 @@ module.exports = { }, }, }; + diff --git a/package.json b/package.json index 9ff0de396..8843cd018 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,9 @@ "test:watch": "jest --watch", "test:coverage": "jest --coverage", "test:health-check": "mocha tests/health-check/**/*.test.js --timeout 30000", + "web:install": "npm install --prefix web-app", + "web:build": "npm run build --prefix web-app", + "web:dev": "npm run dev --prefix web-app", "lint": "eslint . --cache --cache-location .eslintcache", "typecheck": "tsc --noEmit", "release": "semantic-release", @@ -36,6 +39,7 @@ "validate:manifest": "node scripts/validate-manifest.js", "validate:structure": "node .aios-core/infrastructure/scripts/source-tree-guardian/index.js", "validate:agents": "node .aios-core/infrastructure/scripts/validate-agents.js", + "validate:parity": "node .aios-core/infrastructure/scripts/validate-parity.js", "sync:ide": "node .aios-core/infrastructure/scripts/ide-sync/index.js sync", "sync:ide:validate": "node .aios-core/infrastructure/scripts/ide-sync/index.js validate", "sync:ide:check": "node .aios-core/infrastructure/scripts/ide-sync/index.js validate --strict", diff --git a/web-app/.gitignore b/web-app/.gitignore new file mode 100644 index 000000000..a547bf36d --- /dev/null +++ b/web-app/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/web-app/bridge-server.cjs b/web-app/bridge-server.cjs new file mode 100644 index 000000000..90e6c8384 --- /dev/null +++ b/web-app/bridge-server.cjs @@ -0,0 +1,63 @@ +const http = require('http'); +const url = require('url'); +const { processDocument } = require('../squads/legal-ocr-squad/scripts/ocr-engine'); +const NamingEngine = require('../squads/legal-ocr-squad/tools/naming-engine'); +const path = require('path'); + +const namingEngine = new NamingEngine(); +const PORT = 3001; + +const server = http.createServer(async (req, res) => { + // CORS + res.setHeader('Access-Control-Allow-Origin', '*'); + res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS'); + res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); + + if (req.method === 'OPTIONS') { + res.writeHead(204); + res.end(); + return; + } + + const parseUrl = url.parse(req.url, true); + + if (req.method === 'POST' && parseUrl.pathname === '/api/process') { + let body = ''; + req.on('data', chunk => { body += chunk; }); + req.on('end', async () => { + try { + const { filePath, lang } = JSON.parse(body); + console.log(`[Bridge] Processing request for: ${filePath}`); + + // 1. Run OCR + const ocrResult = await processDocument(filePath, lang || 'por'); + + // 2. Run AI Metadata Extraction + const metadata = await namingEngine.extractMetadataAI(ocrResult.text); + + // 3. Generate suggested name + const suggestedName = namingEngine.generateName(metadata, path.basename(filePath)); + + res.writeHead(200, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify({ + success: true, + ocr: ocrResult, + metadata: metadata, + suggestedName: suggestedName, + })); + } catch (error) { + console.error('[Bridge] Error:', error.message); + res.writeHead(500, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify({ success: false, error: error.message })); + } + }); + } else { + res.writeHead(404); + res.end('Not Found'); + } +}); + +server.listen(PORT, () => { + console.log(`[AIOS-Bridge] Legal OCR Proxy running at http://localhost:${PORT}`); +}); + diff --git a/web-app/index.html b/web-app/index.html new file mode 100644 index 000000000..841c570d8 --- /dev/null +++ b/web-app/index.html @@ -0,0 +1,57 @@ + + + + + + + AIOS Studio Chat + + + + +
+ + +
+
+
+

Chat de Orquestração

+ online +
+ +
+
+ +
+ + +
+
+ +
+
+ + +
+
+
+
+
+

+        
+
+
+
+ + + + + diff --git a/web-app/main.js b/web-app/main.js new file mode 100644 index 000000000..ad986ae9c --- /dev/null +++ b/web-app/main.js @@ -0,0 +1,225 @@ +const chatMessages = document.getElementById('chatMessages'); +const chatForm = document.getElementById('chatForm'); +const chatInput = document.getElementById('chatInput'); +const quickReplies = document.getElementById('quickReplies'); +const newProjectBtn = document.getElementById('newProjectBtn'); +const clearChatBtn = document.getElementById('clearChatBtn'); +const previewCanvas = document.getElementById('previewCanvas'); +const codeView = document.getElementById('codeView'); + +const tabs = document.querySelectorAll('.tab'); +const previewTab = document.getElementById('previewTab'); +const codeTab = document.getElementById('codeTab'); + +const wizardQuestions = [ + { key: 'projectName', prompt: 'Qual o nome do projeto?' }, + { key: 'problem', prompt: 'Qual problema principal este projeto resolve?' }, + { key: 'projectType', prompt: 'Tipo de iniciativa?', options: ['Greenfield', 'Brownfield'] }, + { key: 'hasPrd', prompt: 'Você já tem PRD?', options: ['Sim', 'Não'] }, + { key: 'needsPlaybook', prompt: 'Precisa de playbook operacional?', options: ['Sim', 'Não'] }, + { key: 'frontend', prompt: 'Stack frontend desejada?', options: ['React', 'Next.js', 'Vue', 'Outro'] }, + { key: 'backend', prompt: 'Stack backend desejada?', options: ['Node.js', 'Python', '.NET', 'Outro'] }, + { key: 'database', prompt: 'Banco de dados principal?', options: ['PostgreSQL', 'MySQL', 'MongoDB', 'Outro'] }, + { key: 'auth', prompt: 'Como será autenticação?', options: ['JWT/OAuth2', 'SSO', 'Sem autenticação'] }, + { key: 'integrations', prompt: 'Quais integrações externas são críticas?' }, + { key: 'deadline', prompt: 'Existe prazo ou marco importante?' }, +]; + +const wizard = { + active: false, + step: 0, + answers: {}, +}; + +function addMessage(text, role = 'agent') { + const message = document.createElement('div'); + message.className = `msg ${role === 'user' ? 'msg-user' : 'msg-agent'}`; + message.textContent = text; + chatMessages.appendChild(message); + chatMessages.scrollTop = chatMessages.scrollHeight; +} + +function setQuickReplies(options = []) { + quickReplies.innerHTML = ''; + options.forEach((option) => { + const button = document.createElement('button'); + button.type = 'button'; + button.textContent = option; + button.addEventListener('click', () => handleUserInput(option)); + quickReplies.appendChild(button); + }); +} + +function escapeHtml(value) { + return String(value) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); +} + +function askWizardQuestion() { + const question = wizardQuestions[wizard.step]; + if (!question) { + finishWizard(); + return; + } + + addMessage(question.prompt, 'agent'); + setQuickReplies(question.options || []); +} + +function startWizard() { + wizard.active = true; + wizard.step = 0; + wizard.answers = {}; + addMessage('Vamos iniciar o novo projeto com governança por documentação. Responda as perguntas a seguir.', 'agent'); + askWizardQuestion(); +} + +function suggestAgents(answers) { + const agents = ['@pm', '@po', '@architect', '@dev', '@qa', '@devops']; + if ((answers.frontend || '').toLowerCase().includes('react') || (answers.frontend || '').toLowerCase().includes('next')) { + agents.push('@ux-design-expert'); + } + if ((answers.database || '').toLowerCase().includes('postgre') || (answers.database || '').toLowerCase().includes('mysql')) { + agents.push('@data-engineer'); + } + return [...new Set(agents)]; +} + +function generateArtifacts(answers) { + const requiredDocs = [ + 'Project Brief', + 'PRD', + 'Arquitetura Full Stack', + 'Plano de Entrega (milestones)', + 'Matriz de Riscos', + ]; + + if ((answers.needsPlaybook || '').toLowerCase() === 'sim') { + requiredDocs.push('Playbook Operacional'); + } + + const agentPlan = suggestAgents(answers); + + const previewHtml = ` +
+

${escapeHtml(answers.projectName || 'Novo Projeto')}

+

Problema: ${escapeHtml(answers.problem || '-')}

+

Tipo: ${escapeHtml(answers.projectType || '-')}

+

Frontend: ${escapeHtml(answers.frontend || '-')}

+

Backend: ${escapeHtml(answers.backend || '-')}

+

Database: ${escapeHtml(answers.database || '-')}

+

Prazo: ${escapeHtml(answers.deadline || '-')}

+
+
+

Documentação Inicial Obrigatória

+
    ${requiredDocs.map((doc) => `
  • ${escapeHtml(doc)}
  • `).join('')}
+
+
+

Agentes Sugeridos

+

${agentPlan.join(', ')}

+
+ `; + + const codeArtifact = { + project: answers.projectName, + classification: { + type: answers.projectType, + has_prd: answers.hasPrd, + needs_playbook: answers.needsPlaybook, + }, + stack: { + frontend: answers.frontend, + backend: answers.backend, + database: answers.database, + auth: answers.auth, + }, + documentation: requiredDocs, + agents: agentPlan, + next_steps: [ + 'Gerar PRD estruturado com requisitos funcionais e não funcionais', + 'Definir arquitetura e contratos de API', + 'Planejar backlog por épicos/stories com critérios de aceite', + 'Iniciar implementação full stack após aprovação documental', + ], + }; + + previewCanvas.innerHTML = previewHtml; + codeView.textContent = JSON.stringify(codeArtifact, null, 2); +} + +function finishWizard() { + wizard.active = false; + setQuickReplies([]); + generateArtifacts(wizard.answers); + + addMessage('Classificação concluída. Gere agora PRD/playbook e só depois avance para construção com agentes e skills.', 'agent'); +} + +function handleWizardInput(text) { + const question = wizardQuestions[wizard.step]; + if (!question) { + return; + } + + wizard.answers[question.key] = text; + wizard.step += 1; + askWizardQuestion(); +} + +function handleUserInput(text) { + if (!text.trim()) { + return; + } + + addMessage(text, 'user'); + + if (wizard.active) { + handleWizardInput(text.trim()); + return; + } + + if (/novo projeto|criar projeto|iniciar projeto/i.test(text)) { + startWizard(); + return; + } + + addMessage('Posso te ajudar melhor iniciando o modo "Novo Projeto Guiado" para classificar escopo, documentação e stack.', 'agent'); +} + +chatForm.addEventListener('submit', (event) => { + event.preventDefault(); + const text = chatInput.value; + chatInput.value = ''; + handleUserInput(text); +}); + +newProjectBtn.addEventListener('click', () => { + startWizard(); +}); + +clearChatBtn.addEventListener('click', () => { + chatMessages.innerHTML = ''; + quickReplies.innerHTML = ''; + wizard.active = false; + wizard.step = 0; + wizard.answers = {}; + addMessage('Conversa limpa. Quando quiser, clique em "Novo Projeto Guiado".', 'agent'); +}); + +tabs.forEach((tab) => { + tab.addEventListener('click', () => { + tabs.forEach((item) => item.classList.remove('active')); + tab.classList.add('active'); + const target = tab.dataset.tab; + previewTab.classList.toggle('active', target === 'preview'); + codeTab.classList.toggle('active', target === 'code'); + }); +}); + +addMessage('Bem-vindo ao AIOS Studio. Clique em "Novo Projeto Guiado" para iniciar a coleta classificatória do projeto.', 'agent'); +previewCanvas.innerHTML = '

Sem projeto classificado

Inicie o fluxo guiado para gerar preview e artefato técnico.

'; +codeView.textContent = '{\n "status": "aguardando_classificacao"\n}'; diff --git a/web-app/package-lock.json b/web-app/package-lock.json new file mode 100644 index 000000000..5a5875eb5 --- /dev/null +++ b/web-app/package-lock.json @@ -0,0 +1,1104 @@ +{ + "name": "web-app", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "web-app", + "version": "0.0.0", + "devDependencies": { + "vite": "^7.3.1" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + } + } +} diff --git a/web-app/package.json b/web-app/package.json new file mode 100644 index 000000000..bc0f2c42d --- /dev/null +++ b/web-app/package.json @@ -0,0 +1,14 @@ +{ + "name": "web-app", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "devDependencies": { + "vite": "^7.3.1" + } +} diff --git a/web-app/style.css b/web-app/style.css new file mode 100644 index 000000000..04daa4300 --- /dev/null +++ b/web-app/style.css @@ -0,0 +1,275 @@ +:root { + --bg: #0b1020; + --bg-soft: #121a31; + --panel: #17223f; + --line: #2d3b67; + --text: #f4f7ff; + --muted: #a8b4d6; + --primary: #2dd4bf; + --primary-strong: #14b8a6; + --accent: #f59e0b; +} + +* { + box-sizing: border-box; +} + +body { + margin: 0; + font-family: 'Segoe UI', Tahoma, sans-serif; + color: var(--text); + background: radial-gradient(circle at 20% 0%, #1d2a54 0%, var(--bg) 45%); + min-height: 100vh; +} + +.app-shell { + display: grid; + grid-template-columns: 260px 1fr; + min-height: 100vh; +} + +.left-rail { + border-right: 1px solid var(--line); + padding: 20px; + background: rgba(12, 18, 34, 0.9); +} + +.brand { + font-size: 24px; + font-weight: 700; + margin-bottom: 20px; +} + +.hint-box { + margin-top: 18px; + border: 1px solid var(--line); + background: var(--bg-soft); + border-radius: 12px; + padding: 12px; +} + +.hint-box h3 { + margin: 0 0 8px; + color: var(--accent); +} + +.hint-box p { + margin: 0; + color: var(--muted); + font-size: 14px; + line-height: 1.5; +} + +.workspace { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 14px; + padding: 14px; +} + +.chat-panel, +.output-panel { + background: linear-gradient(180deg, rgba(23, 34, 63, 0.98) 0%, rgba(14, 22, 43, 0.98) 100%); + border: 1px solid var(--line); + border-radius: 16px; + min-height: calc(100vh - 28px); +} + +.chat-panel { + display: flex; + flex-direction: column; +} + +.panel-head { + border-bottom: 1px solid var(--line); + padding: 14px 16px; + display: flex; + justify-content: space-between; + align-items: center; +} + +.panel-head h1 { + margin: 0; + font-size: 18px; +} + +.status { + font-size: 12px; + border: 1px solid var(--primary); + color: var(--primary); + padding: 2px 8px; + border-radius: 999px; +} + +.chat-messages { + flex: 1; + overflow: auto; + padding: 14px; + display: flex; + flex-direction: column; + gap: 10px; +} + +.msg { + max-width: 85%; + padding: 10px 12px; + border-radius: 12px; + line-height: 1.45; + white-space: pre-wrap; +} + +.msg-user { + margin-left: auto; + background: #1b7c72; +} + +.msg-agent { + background: #222f55; + border: 1px solid #334779; +} + +.quick-replies { + padding: 0 14px; + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.quick-replies button { + border: 1px solid #3e4f83; + background: #1d2b50; + color: var(--text); + border-radius: 999px; + padding: 6px 10px; + cursor: pointer; +} + +.chat-form { + border-top: 1px solid var(--line); + padding: 12px; + display: flex; + gap: 8px; +} + +.chat-form input { + flex: 1; + background: #0f1730; + border: 1px solid #2f406d; + color: var(--text); + border-radius: 10px; + padding: 10px; +} + +.btn { + width: 100%; + border: 1px solid transparent; + border-radius: 10px; + padding: 10px; + margin-bottom: 10px; + cursor: pointer; + font-weight: 600; +} + +.btn-primary { + background: var(--primary); + color: #052926; +} + +.btn-primary:hover { + background: var(--primary-strong); +} + +.btn-ghost { + background: #1b294c; + color: var(--text); + border-color: #314472; +} + +.output-panel { + overflow: hidden; +} + +.tabs { + display: flex; + border-bottom: 1px solid var(--line); +} + +.tab { + flex: 1; + padding: 12px; + background: #111b36; + border: none; + color: var(--muted); + cursor: pointer; +} + +.tab.active { + background: #1a2950; + color: var(--text); +} + +.tab-content { + display: none; + height: calc(100% - 45px); +} + +.tab-content.active { + display: block; +} + +.preview-canvas, +.code-view { + margin: 0; + padding: 16px; + height: calc(100vh - 90px); + overflow: auto; +} + +.preview-canvas { + color: var(--text); + line-height: 1.6; +} + +.preview-card { + border: 1px solid #355287; + background: #162344; + border-radius: 12px; + padding: 14px; + margin-bottom: 12px; +} + +.preview-card h3 { + margin: 0 0 8px; + color: var(--primary); +} + +.code-view { + font-family: Consolas, monospace; + background: #0d1429; + color: #a7ffea; +} + +@media (max-width: 1024px) { + .app-shell { + grid-template-columns: 1fr; + } + + .left-rail { + border-right: none; + border-bottom: 1px solid var(--line); + } + + .workspace { + grid-template-columns: 1fr; + } + + .chat-panel, + .output-panel { + min-height: 460px; + } + + .preview-canvas, + .code-view { + height: 420px; + } +}