claude-flow-novice 2.15.2 → 2.15.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/hooks/cfn-BACKUP_USAGE.md +243 -243
- package/.claude/hooks/cfn-invoke-security-validation.sh +69 -69
- package/.claude/hooks/cfn-post-edit-cfn-retrospective.sh +78 -78
- package/.claude/hooks/cfn-post-edit.config.json +44 -44
- package/.claude/skills/agent-lifecycle/SKILL.md +60 -0
- package/.claude/skills/agent-lifecycle/execute-lifecycle-hook.sh +573 -0
- package/.claude/skills/agent-lifecycle/simple-audit.sh +31 -0
- package/.claude/skills/cfn-hybrid-routing/check-dependencies.sh +51 -51
- package/.claude/skills/cfn-loop-validation/orchestrate-cfn-loop.sh +252 -252
- package/.claude/skills/cfn-redis-coordination/agent-recovery.sh +74 -74
- package/.claude/skills/cfn-redis-coordination/get-context.sh +112 -112
- package/.claude/skills/cfn-transparency-middleware/middleware-config.sh +28 -28
- package/.claude/skills/cfn-transparency-middleware/performance-benchmark.sh +78 -78
- package/.claude/skills/cfn-transparency-middleware/test-integration.sh +161 -161
- package/.claude/skills/cfn-transparency-middleware/test-transparency-skill.sh +367 -367
- package/.claude/skills/cfn-transparency-middleware/tests/input-validation.sh +92 -92
- package/.claude/skills/cfn-transparency-middleware/wrap-agent.sh +131 -131
- package/claude-assets/hooks/cfn-BACKUP_USAGE.md +243 -243
- package/claude-assets/hooks/cfn-invoke-security-validation.sh +69 -69
- package/claude-assets/hooks/cfn-post-edit-cfn-retrospective.sh +78 -78
- package/claude-assets/hooks/cfn-post-edit.config.json +44 -44
- package/claude-assets/hooks/cfn-post-execution/memory-cleanup.sh +19 -19
- package/claude-assets/hooks/cfn-pre-execution/memory-check.sh +19 -19
- package/claude-assets/skills/agent-lifecycle/execute-lifecycle-hook.sh +572 -572
- package/claude-assets/skills/agent-lifecycle/simple-audit.sh +30 -30
- package/claude-assets/skills/cfn-automatic-memory-persistence/persist-agent-output.sh +48 -48
- package/claude-assets/skills/cfn-automatic-memory-persistence/query-agent-history.sh +34 -34
- package/claude-assets/skills/cfn-deliverable-validation/confidence-calculator.sh +261 -261
- package/claude-assets/skills/cfn-expert-update/update-expert.sh +345 -345
- package/claude-assets/skills/cfn-hybrid-routing/check-dependencies.sh +51 -51
- package/claude-assets/skills/cfn-intervention-detector/detect-intervention.sh +110 -110
- package/claude-assets/skills/cfn-intervention-orchestrator/execute-intervention.sh +58 -58
- package/claude-assets/skills/cfn-loop-validation/orchestrate-cfn-loop.sh +252 -252
- package/claude-assets/skills/cfn-loop2-output-processing/process-validator-output.sh +275 -275
- package/claude-assets/skills/cfn-memory-management/check-memory.sh +159 -159
- package/claude-assets/skills/cfn-memory-management/cleanup-memory.sh +196 -196
- package/claude-assets/skills/cfn-node-heap-sizer/task-mode-heap-limiter.sh +325 -325
- package/claude-assets/skills/cfn-playbook-auto-update/auto-update-playbook.sh +85 -85
- package/claude-assets/skills/cfn-redis-coordination/agent-recovery.sh +74 -74
- package/claude-assets/skills/cfn-redis-coordination/get-context.sh +112 -112
- package/claude-assets/skills/cfn-scope-simplifier/simplify-scope.sh +67 -67
- package/claude-assets/skills/cfn-specialist-injection/recommend-specialist.sh +56 -56
- package/claude-assets/skills/cfn-standardized-error-handling/capture-agent-error.sh +86 -86
- package/claude-assets/skills/cfn-standardized-error-handling/test-error-handling.sh +165 -165
- package/claude-assets/skills/cfn-task-config-init/initialize-config.sh +264 -264
- package/claude-assets/skills/cfn-task-decomposition/task-decomposer.sh +278 -278
- package/claude-assets/skills/cfn-transparency-middleware/middleware-config.sh +28 -28
- package/claude-assets/skills/cfn-transparency-middleware/performance-benchmark.sh +78 -78
- package/claude-assets/skills/cfn-transparency-middleware/test-integration.sh +161 -161
- package/claude-assets/skills/cfn-transparency-middleware/test-transparency-skill.sh +367 -367
- package/claude-assets/skills/cfn-transparency-middleware/tests/input-validation.sh +92 -92
- package/claude-assets/skills/cfn-transparency-middleware/wrap-agent.sh +131 -131
- package/claude-assets/skills/docker-build/SKILL.md +96 -203
- package/claude-assets/skills/docker-build/build.sh +73 -73
- package/claude-assets/skills/integration/agent-handoff.sh +494 -0
- package/claude-assets/skills/integration/file-operations.sh +414 -0
- package/claude-assets/skills/workflow-codification/APPROVAL_WORKFLOW.md +806 -0
- package/claude-assets/skills/workflow-codification/COST_TRACKING.md +637 -0
- package/claude-assets/skills/workflow-codification/EDGE_CASE_TRACKING.md +404 -0
- package/claude-assets/skills/workflow-codification/README_PHASE4.md +457 -0
- package/claude-assets/skills/workflow-codification/SKILL.md +110 -0
- package/claude-assets/skills/workflow-codification/analyze-patterns.sh +899 -0
- package/claude-assets/skills/workflow-codification/approval-workflow.sh +514 -0
- package/claude-assets/skills/workflow-codification/generate-skill-update.sh +525 -0
- package/claude-assets/skills/workflow-codification/review-skill.sh +643 -0
- package/claude-assets/skills/workflow-codification/templates/email-notification.txt +114 -0
- package/claude-assets/skills/workflow-codification/templates/slack-notification.md +85 -0
- package/claude-assets/skills/workflow-codification/test-integration.sh +281 -0
- package/claude-assets/skills/workflow-codification/track-cost-savings.sh +445 -0
- package/claude-assets/skills/workflow-codification/track-edge-case.sh +323 -0
- package/dist/cli/config-manager.js +91 -109
- package/dist/cli/config-manager.js.map +1 -1
- package/dist/integration/DatabaseHandoff.js +507 -0
- package/dist/integration/DatabaseHandoff.js.map +1 -0
- package/dist/integration/StandardAdapter.js +291 -0
- package/dist/integration/StandardAdapter.js.map +1 -0
- package/dist/lib/agent-output-parser.js +518 -0
- package/dist/lib/agent-output-parser.js.map +1 -0
- package/dist/lib/agent-output-validator.js +950 -0
- package/dist/lib/agent-output-validator.js.map +1 -0
- package/dist/lib/artifact-registry.js +443 -0
- package/dist/lib/artifact-registry.js.map +1 -0
- package/dist/lib/config-validator.js +687 -0
- package/dist/lib/config-validator.js.map +1 -0
- package/dist/types/agent-output.js +44 -0
- package/dist/types/agent-output.js.map +1 -0
- package/dist/types/config.js +28 -0
- package/dist/types/config.js.map +1 -0
- package/package.json +2 -1
- package/scripts/artifact-cleanup.sh +392 -0
- package/scripts/deploy-production.sh +355 -355
- package/scripts/docker-playwright-fix.sh +311 -311
- package/scripts/docker-rebuild-all-agents.sh +127 -127
- package/scripts/memory-leak-prevention.sh +305 -305
- package/scripts/migrate-artifacts.sh +563 -0
- package/scripts/migrate-yaml-to-json.sh +465 -0
- package/scripts/run-marketing-tests.sh +42 -42
- package/scripts/update_paths.sh +46 -46
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/config-validator.ts"],"sourcesContent":["/**\r\n * CFN Configuration Validator\r\n * Validates JSON configurations against the CFN schema with detailed error reporting\r\n *\r\n * @version 1.0.0\r\n * @description Type-safe validation library with 95%+ accuracy\r\n */\r\n\r\nimport {\r\n CFNConfig,\r\n ValidationError,\r\n ValidationResult,\r\n EnvVarExportMap,\r\n EnvironmentVariable,\r\n ConfigLoaderOptions,\r\n} from '../types/config';\r\n\r\n/**\r\n * Core validation result from our built-in validator\r\n */\r\ninterface ValidationCheckResult {\r\n valid: boolean;\r\n errors: ValidationError[];\r\n}\r\n\r\n/**\r\n * ConfigValidator: Main validation class\r\n * Provides schema validation, error reporting, and env var export functionality\r\n */\r\nexport class ConfigValidator {\r\n private schema: Record<string, unknown>;\r\n private initialized = true;\r\n\r\n constructor(schema?: Record<string, unknown>) {\r\n if (schema) {\r\n this.schema = schema;\r\n } else {\r\n // Use the default schema embedded below\r\n this.schema = this.getDefaultSchema();\r\n }\r\n }\r\n\r\n /**\r\n * Get default schema definition\r\n */\r\n private getDefaultSchema(): Record<string, unknown> {\r\n return {\r\n $schema: 'https://json-schema.org/draft/2020-12/schema',\r\n $id: 'https://claude-flow-novice.local/schemas/cfn-config-v1.json',\r\n title: 'CFN Configuration Schema v1.0',\r\n description: 'Canonical JSON schema for all Claude Flow Novice configuration files',\r\n version: '1.0.0',\r\n type: 'object',\r\n };\r\n }\r\n\r\n /**\r\n * Main validation method using built-in validators\r\n */\r\n public validate(config: unknown): ValidationResult {\r\n const errors: ValidationError[] = [];\r\n const warnings: string[] = [];\r\n\r\n if (typeof config !== 'object' || config === null) {\r\n return {\r\n valid: false,\r\n errors: [\r\n {\r\n field: 'root',\r\n message: 'Configuration must be a valid JSON object',\r\n path: '/',\r\n code: 'INVALID_TYPE',\r\n },\r\n ],\r\n warnings,\r\n configType: 'unknown',\r\n };\r\n }\r\n\r\n const configObj = config as Record<string, unknown>;\r\n const configType = this.detectConfigType(configObj);\r\n\r\n // Validate based on detected type\r\n switch (configType) {\r\n case 'agent-whitelist':\r\n return this.validateAgentWhitelist(configObj);\r\n case 'mcp-servers':\r\n return this.validateMCPServers(configObj);\r\n case 'skill-requirements':\r\n return this.validateSkillRequirements(configObj);\r\n case 'runtime-contract':\r\n return this.validateRuntimeContract(configObj);\r\n case 'team':\r\n return this.validateTeamConfig(configObj);\r\n default:\r\n return {\r\n valid: false,\r\n errors: [\r\n {\r\n field: 'root',\r\n message:\r\n 'Unknown configuration type. Must include agents, servers, tools, variables, or team',\r\n path: '/',\r\n code: 'UNKNOWN_CONFIG_TYPE',\r\n },\r\n ],\r\n warnings,\r\n configType: 'unknown',\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Validate JSON string\r\n */\r\n public validateJSON(jsonString: string): ValidationResult {\r\n try {\r\n const config = JSON.parse(jsonString);\r\n return this.validate(config);\r\n } catch (error) {\r\n return {\r\n valid: false,\r\n errors: [\r\n {\r\n field: 'json',\r\n message: `Failed to parse JSON: ${error instanceof Error ? error.message : String(error)}`,\r\n path: 'root',\r\n code: 'JSON_PARSE_ERROR',\r\n },\r\n ],\r\n warnings: [],\r\n configType: 'unknown',\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Validate Agent Whitelist Configuration\r\n */\r\n private validateAgentWhitelist(config: Record<string, unknown>): ValidationResult {\r\n const errors: ValidationError[] = [];\r\n const warnings: string[] = [];\r\n\r\n // Check version\r\n if (!config.version || typeof config.version !== 'string') {\r\n errors.push({\r\n field: 'version',\r\n message: 'Missing required field: version (string)',\r\n path: '/version',\r\n code: 'MISSING_REQUIRED',\r\n });\r\n } else if (!/^\\d+\\.\\d+\\.\\d+$/.test(config.version)) {\r\n errors.push({\r\n field: 'version',\r\n message: 'Invalid version format. Expected X.Y.Z format',\r\n path: '/version',\r\n value: config.version,\r\n code: 'INVALID_FORMAT',\r\n });\r\n }\r\n\r\n // Check agents array\r\n if (!Array.isArray(config.agents)) {\r\n errors.push({\r\n field: 'agents',\r\n message: 'Missing required field: agents (array)',\r\n path: '/agents',\r\n code: 'MISSING_REQUIRED',\r\n });\r\n } else {\r\n for (let i = 0; i < (config.agents as unknown[]).length; i++) {\r\n const agent = (config.agents as Record<string, unknown>[])[i];\r\n if (!agent.type || typeof agent.type !== 'string' || agent.type.length === 0) {\r\n errors.push({\r\n field: `agents[${i}].type`,\r\n message: 'Agent type is required and must be non-empty string',\r\n path: `/agents/${i}/type`,\r\n code: 'INVALID_AGENT',\r\n });\r\n }\r\n if (!agent.displayName || typeof agent.displayName !== 'string') {\r\n errors.push({\r\n field: `agents[${i}].displayName`,\r\n message: 'Agent displayName is required',\r\n path: `/agents/${i}/displayName`,\r\n code: 'INVALID_AGENT',\r\n });\r\n }\r\n if (!Array.isArray(agent.skills)) {\r\n errors.push({\r\n field: `agents[${i}].skills`,\r\n message: 'Agent skills must be an array',\r\n path: `/agents/${i}/skills`,\r\n code: 'INVALID_AGENT',\r\n });\r\n }\r\n }\r\n }\r\n\r\n if (!config.lastUpdated) {\r\n warnings.push('Agent configuration missing lastUpdated field (recommended)');\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n warnings,\r\n configType: 'agent-whitelist',\r\n };\r\n }\r\n\r\n /**\r\n * Validate MCP Servers Configuration\r\n */\r\n private validateMCPServers(config: Record<string, unknown>): ValidationResult {\r\n const errors: ValidationError[] = [];\r\n const warnings: string[] = [];\r\n\r\n // Check version\r\n if (!config.version || typeof config.version !== 'string') {\r\n errors.push({\r\n field: 'version',\r\n message: 'Missing required field: version',\r\n path: '/version',\r\n code: 'MISSING_REQUIRED',\r\n });\r\n }\r\n\r\n // Check servers object\r\n if (!config.servers || typeof config.servers !== 'object') {\r\n errors.push({\r\n field: 'servers',\r\n message: 'Missing required field: servers (object)',\r\n path: '/servers',\r\n code: 'MISSING_REQUIRED',\r\n });\r\n } else {\r\n const servers = config.servers as Record<string, Record<string, unknown>>;\r\n for (const serverName in servers) {\r\n if (Object.prototype.hasOwnProperty.call(servers, serverName)) {\r\n const serverConfig = servers[serverName];\r\n if (!serverConfig.endpoint || typeof serverConfig.endpoint !== 'string') {\r\n errors.push({\r\n field: `servers.${serverName}.endpoint`,\r\n message: 'Server endpoint is required',\r\n path: `/servers/${serverName}/endpoint`,\r\n code: 'INVALID_SERVER',\r\n });\r\n } else if (!this.isValidURL(serverConfig.endpoint)) {\r\n errors.push({\r\n field: `servers.${serverName}.endpoint`,\r\n message: 'Server endpoint must be a valid URL',\r\n path: `/servers/${serverName}/endpoint`,\r\n value: serverConfig.endpoint,\r\n code: 'INVALID_URL',\r\n });\r\n }\r\n\r\n if (!Array.isArray(serverConfig.requiredSkills)) {\r\n errors.push({\r\n field: `servers.${serverName}.requiredSkills`,\r\n message: 'Server requiredSkills must be an array',\r\n path: `/servers/${serverName}/requiredSkills`,\r\n code: 'INVALID_SERVER',\r\n });\r\n }\r\n\r\n if (!serverConfig.auth || typeof serverConfig.auth !== 'object') {\r\n errors.push({\r\n field: `servers.${serverName}.auth`,\r\n message: 'Server auth is required',\r\n path: `/servers/${serverName}/auth`,\r\n code: 'INVALID_SERVER',\r\n });\r\n }\r\n\r\n if (serverConfig.timeoutMs !== undefined && typeof serverConfig.timeoutMs !== 'number') {\r\n errors.push({\r\n field: `servers.${serverName}.timeoutMs`,\r\n message: 'timeoutMs must be a number',\r\n path: `/servers/${serverName}/timeoutMs`,\r\n code: 'INVALID_TYPE',\r\n });\r\n } else if (serverConfig.timeoutMs !== undefined && (serverConfig.timeoutMs as number) < 1000) {\r\n errors.push({\r\n field: `servers.${serverName}.timeoutMs`,\r\n message: 'timeoutMs must be at least 1000ms',\r\n path: `/servers/${serverName}/timeoutMs`,\r\n value: serverConfig.timeoutMs,\r\n code: 'CONSTRAINT_VIOLATION',\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n warnings,\r\n configType: 'mcp-servers',\r\n };\r\n }\r\n\r\n /**\r\n * Validate Skill Requirements Configuration\r\n */\r\n private validateSkillRequirements(config: Record<string, unknown>): ValidationResult {\r\n const errors: ValidationError[] = [];\r\n const warnings: string[] = [];\r\n\r\n if (!config.version || typeof config.version !== 'string') {\r\n errors.push({\r\n field: 'version',\r\n message: 'Missing required field: version',\r\n path: '/version',\r\n code: 'MISSING_REQUIRED',\r\n });\r\n }\r\n\r\n if (!config.tools || typeof config.tools !== 'object') {\r\n errors.push({\r\n field: 'tools',\r\n message: 'Missing required field: tools (object)',\r\n path: '/tools',\r\n code: 'MISSING_REQUIRED',\r\n });\r\n } else {\r\n const tools = config.tools as Record<string, Record<string, unknown>>;\r\n for (const toolName in tools) {\r\n if (Object.prototype.hasOwnProperty.call(tools, toolName)) {\r\n const toolConfig = tools[toolName];\r\n if (!toolConfig.displayName || typeof toolConfig.displayName !== 'string') {\r\n errors.push({\r\n field: `tools.${toolName}.displayName`,\r\n message: 'Tool displayName is required',\r\n path: `/tools/${toolName}/displayName`,\r\n code: 'INVALID_TOOL',\r\n });\r\n }\r\n\r\n if (!Array.isArray(toolConfig.requiredSkills) || (toolConfig.requiredSkills as unknown[]).length === 0) {\r\n errors.push({\r\n field: `tools.${toolName}.requiredSkills`,\r\n message: 'Tool requiredSkills must be a non-empty array',\r\n path: `/tools/${toolName}/requiredSkills`,\r\n code: 'INVALID_TOOL',\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n warnings,\r\n configType: 'skill-requirements',\r\n };\r\n }\r\n\r\n /**\r\n * Validate Runtime Contract Configuration\r\n */\r\n private validateRuntimeContract(config: Record<string, unknown>): ValidationResult {\r\n const errors: ValidationError[] = [];\r\n const warnings: string[] = [];\r\n\r\n if (!config.version || typeof config.version !== 'string') {\r\n errors.push({\r\n field: 'version',\r\n message: 'Missing required field: version',\r\n path: '/version',\r\n code: 'MISSING_REQUIRED',\r\n });\r\n }\r\n\r\n if (config.variables && typeof config.variables === 'object') {\r\n const variables = config.variables as Record<string, Record<string, unknown>>;\r\n for (const varName in variables) {\r\n if (Object.prototype.hasOwnProperty.call(variables, varName)) {\r\n const varConfig = variables[varName];\r\n if (!varConfig.description || typeof varConfig.description !== 'string') {\r\n errors.push({\r\n field: `variables.${varName}.description`,\r\n message: 'Variable description is required',\r\n path: `/variables/${varName}/description`,\r\n code: 'INVALID_VARIABLE',\r\n });\r\n }\r\n const varType = varConfig.type as string;\r\n const validTypes = ['string', 'integer', 'number', 'boolean'];\r\n if (!varConfig.type || validTypes.indexOf(varType) === -1) {\r\n errors.push({\r\n field: `variables.${varName}.type`,\r\n message: 'Variable type must be one of: string, integer, number, boolean',\r\n path: `/variables/${varName}/type`,\r\n code: 'INVALID_VARIABLE',\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n warnings,\r\n configType: 'runtime-contract',\r\n };\r\n }\r\n\r\n /**\r\n * Validate Team Configuration\r\n */\r\n private validateTeamConfig(config: Record<string, unknown>): ValidationResult {\r\n const errors: ValidationError[] = [];\r\n const warnings: string[] = [];\r\n\r\n if (!config.team || typeof config.team !== 'object') {\r\n errors.push({\r\n field: 'team',\r\n message: 'Missing required field: team (object)',\r\n path: '/team',\r\n code: 'MISSING_REQUIRED',\r\n });\r\n return { valid: false, errors, warnings, configType: 'team' };\r\n }\r\n\r\n const team = config.team as Record<string, unknown>;\r\n\r\n if (!team.id || typeof team.id !== 'string' || team.id.length === 0) {\r\n errors.push({\r\n field: 'team.id',\r\n message: 'Team id is required and must be non-empty',\r\n path: '/team/id',\r\n code: 'INVALID_TEAM',\r\n });\r\n } else if (!/^[a-z0-9-]+$/.test(team.id as string)) {\r\n errors.push({\r\n field: 'team.id',\r\n message: 'Team id must contain only lowercase letters, numbers, and hyphens',\r\n path: '/team/id',\r\n value: team.id,\r\n code: 'INVALID_FORMAT',\r\n });\r\n }\r\n\r\n if (!team.name || typeof team.name !== 'string') {\r\n errors.push({\r\n field: 'team.name',\r\n message: 'Team name is required',\r\n path: '/team/name',\r\n code: 'INVALID_TEAM',\r\n });\r\n }\r\n\r\n // Validate workspace if present (supports both diskQuota and disk_quota)\r\n if (team.workspace && typeof team.workspace === 'object') {\r\n const workspace = team.workspace as Record<string, unknown>;\r\n const diskQuota = this.getPropertyValue(workspace, 'diskQuota');\r\n if (diskQuota !== undefined && !this.isValidDiskQuota(diskQuota)) {\r\n errors.push({\r\n field: 'team.workspace.diskQuota',\r\n message: 'Invalid disk quota format. Expected format: <number><UNIT> (e.g., 100GB)',\r\n path: '/team/workspace/diskQuota',\r\n value: diskQuota,\r\n code: 'INVALID_FORMAT',\r\n });\r\n }\r\n }\r\n\r\n // Validate resources if present (supports both camelCase and snake_case naming)\r\n if (team.resources && typeof team.resources === 'object') {\r\n const resources = team.resources as Record<string, unknown>;\r\n const cpuCores = this.getPropertyValue(resources, 'cpuCores');\r\n const maxAgents = this.getPropertyValue(resources, 'maxAgents');\r\n\r\n // Validate cpuCores (supports cpuCores and cpu_cores)\r\n if (cpuCores !== undefined) {\r\n if (typeof cpuCores !== 'number' || cpuCores < 0) {\r\n errors.push({\r\n field: 'team.resources.cpuCores',\r\n message: 'cpuCores must be a non-negative number',\r\n path: '/team/resources/cpuCores',\r\n value: cpuCores,\r\n code: 'INVALID_TYPE',\r\n });\r\n }\r\n }\r\n\r\n // Validate maxAgents (supports maxAgents and max_agents)\r\n if (maxAgents !== undefined) {\r\n if (typeof maxAgents !== 'number' || maxAgents < 1 || !Number.isInteger(maxAgents)) {\r\n errors.push({\r\n field: 'team.resources.maxAgents',\r\n message: 'maxAgents must be a positive integer',\r\n path: '/team/resources/maxAgents',\r\n value: maxAgents,\r\n code: 'INVALID_TYPE',\r\n });\r\n }\r\n }\r\n }\r\n\r\n // Validate network if present\r\n if (team.network && typeof team.network === 'object') {\r\n const network = team.network as Record<string, unknown>;\r\n if (network.coordinatorIp && !this.isValidIPv4(network.coordinatorIp)) {\r\n errors.push({\r\n field: 'team.network.coordinatorIp',\r\n message: 'Invalid IPv4 format',\r\n path: '/team/network/coordinatorIp',\r\n value: network.coordinatorIp,\r\n code: 'INVALID_FORMAT',\r\n });\r\n }\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n warnings,\r\n configType: 'team',\r\n };\r\n }\r\n\r\n /**\r\n * Detect configuration type\r\n */\r\n private detectConfigType(config: Record<string, unknown>): string {\r\n // Check for agent whitelist (has 'agents' array)\r\n if ('agents' in config && Array.isArray(config.agents)) {\r\n return 'agent-whitelist';\r\n }\r\n\r\n // Check for MCP servers (has 'servers' object)\r\n if ('servers' in config && typeof config.servers === 'object') {\r\n return 'mcp-servers';\r\n }\r\n\r\n // Check for skill requirements (has 'tools' object)\r\n if ('tools' in config && typeof config.tools === 'object') {\r\n return 'skill-requirements';\r\n }\r\n\r\n // Check for runtime contract (has 'variables' object)\r\n if ('variables' in config && typeof config.variables === 'object') {\r\n return 'runtime-contract';\r\n }\r\n\r\n // Check for team config (has 'team' object)\r\n if ('team' in config && typeof config.team === 'object') {\r\n return 'team';\r\n }\r\n\r\n return 'unknown';\r\n }\r\n\r\n /**\r\n * Export configuration as environment variables\r\n * Handles type preservation and validation\r\n */\r\n public exportEnvVars(config: unknown): EnvVarExportMap {\r\n if (typeof config !== 'object' || config === null) {\r\n throw new Error('Configuration must be an object');\r\n }\r\n\r\n const configObj = config as Record<string, unknown>;\r\n if (!('variables' in configObj)) {\r\n throw new Error('Configuration is not a valid runtime contract');\r\n }\r\n\r\n const envMap: EnvVarExportMap = {};\r\n const variables = configObj.variables;\r\n\r\n if (typeof variables !== 'object' || variables === null) {\r\n throw new Error('Variables must be an object');\r\n }\r\n\r\n const varsObj = variables as Record<string, unknown>;\r\n for (const key in varsObj) {\r\n if (Object.prototype.hasOwnProperty.call(varsObj, key)) {\r\n const variable = varsObj[key];\r\n const varObj = variable as Record<string, unknown>;\r\n if (varObj.value !== null && varObj.value !== undefined) {\r\n const varType = varObj.type as string;\r\n envMap[key] = this.coerceToCorrectType(varObj.value, varType);\r\n }\r\n }\r\n }\r\n\r\n return envMap;\r\n }\r\n\r\n /**\r\n * Coerce value to correct type without loss\r\n */\r\n private coerceToCorrectType(\r\n value: unknown,\r\n type: string\r\n ): string | number | boolean {\r\n if (type === 'integer' && typeof value === 'string') {\r\n return parseInt(value, 10);\r\n }\r\n if (type === 'number' && typeof value === 'string') {\r\n return parseFloat(value);\r\n }\r\n if (type === 'boolean' && typeof value === 'string') {\r\n return value.toLowerCase() === 'true';\r\n }\r\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\r\n return value;\r\n }\r\n return String(value);\r\n }\r\n\r\n /**\r\n * Format validation errors for display\r\n */\r\n public formatErrors(result: ValidationResult): string {\r\n if (result.valid) {\r\n return 'Configuration is valid.';\r\n }\r\n\r\n let output = `Validation failed with ${result.errors.length} error(s):\\n\\n`;\r\n\r\n for (const error of result.errors) {\r\n output += `[${error.code}] ${error.field || 'root'}\\n`;\r\n output += ` ${error.message}\\n`;\r\n if (error.value !== undefined) {\r\n output += ` Current value: ${JSON.stringify(error.value)}\\n`;\r\n }\r\n output += '\\n';\r\n }\r\n\r\n if (result.warnings.length > 0) {\r\n output += `\\nWarnings (${result.warnings.length}):\\n`;\r\n for (const warning of result.warnings) {\r\n output += ` - ${warning}\\n`;\r\n }\r\n }\r\n\r\n return output;\r\n }\r\n\r\n /**\r\n * Helper: Validate URL format\r\n */\r\n private isValidURL(url: unknown): boolean {\r\n if (typeof url !== 'string') return false;\r\n try {\r\n new URL(url);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Helper: Validate disk quota format\r\n */\r\n private isValidDiskQuota(quota: unknown): boolean {\r\n if (typeof quota !== 'string') return false;\r\n return /^\\d+[KMGTPE]B$/.test(quota);\r\n }\r\n\r\n /**\r\n * Helper: Validate IPv4 format\r\n */\r\n private isValidIPv4(ip: unknown): boolean {\r\n if (typeof ip !== 'string') return false;\r\n const ipv4Pattern = /^(\\d{1,3}\\.){3}\\d{1,3}$/;\r\n if (!ipv4Pattern.test(ip)) return false;\r\n\r\n const parts = ip.split('.');\r\n return parts.every((part) => {\r\n const num = parseInt(part, 10);\r\n return num >= 0 && num <= 255;\r\n });\r\n }\r\n\r\n /**\r\n * Helper: Normalize field name (support both snake_case and camelCase)\r\n * Examples: disk_quota → diskQuota, cpu_cores → cpuCores, maxAgents → maxAgents\r\n */\r\n private normalizeFieldName(name: string): string {\r\n if (!name.includes('_')) return name;\r\n return name.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());\r\n }\r\n\r\n /**\r\n * Helper: Get property value supporting both naming conventions\r\n * @param obj Object to search\r\n * @param field Field name in any convention (camelCase or snake_case)\r\n * @returns Value if found, undefined otherwise\r\n */\r\n private getPropertyValue(obj: Record<string, unknown>, field: string): unknown {\r\n // Try camelCase version first\r\n if (field in obj) return obj[field];\r\n\r\n // Try snake_case version\r\n const snakeCase = field.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);\r\n if (snakeCase in obj) return obj[snakeCase];\r\n\r\n // Try normalizing if it's snake_case input\r\n const camelCase = this.normalizeFieldName(field);\r\n if (camelCase in obj) return obj[camelCase];\r\n\r\n return undefined;\r\n }\r\n}\r\n\r\n/**\r\n * Singleton instance for global usage\r\n */\r\nlet validatorInstance: ConfigValidator | null = null;\r\n\r\n/**\r\n * Get or create validator instance\r\n */\r\nexport function getValidator(schema?: Record<string, unknown>): ConfigValidator {\r\n if (!validatorInstance) {\r\n validatorInstance = new ConfigValidator(schema);\r\n }\r\n return validatorInstance;\r\n}\r\n\r\n/**\r\n * Validate configuration object\r\n */\r\nexport function validateConfig(config: unknown): ValidationResult {\r\n return getValidator().validate(config);\r\n}\r\n\r\n/**\r\n * Validate JSON string\r\n */\r\nexport function validateJSON(jsonString: string): ValidationResult {\r\n return getValidator().validateJSON(jsonString);\r\n}\r\n\r\n/**\r\n * Export environment variables from runtime contract\r\n */\r\nexport function exportEnvVars(config: unknown): EnvVarExportMap {\r\n return getValidator().exportEnvVars(config);\r\n}\r\n\r\n/**\r\n * Check if configuration is valid (boolean shortcut)\r\n */\r\nexport function isValidConfig(config: unknown): boolean {\r\n return getValidator().validate(config).valid;\r\n}\r\n\r\n/**\r\n * Reset validator instance (useful for testing)\r\n */\r\nexport function resetValidator(): void {\r\n validatorInstance = null;\r\n}\r\n\r\n/**\r\n * Validate multiple configuration files efficiently\r\n * @param filePaths Array of file paths to validate\r\n * @returns Map of file path to validation result\r\n * @throws Error if file cannot be read\r\n */\r\nexport function validateConfigFiles(\r\n filePaths: string[]\r\n): Record<string, ValidationResult> {\r\n const results: Record<string, ValidationResult> = {};\r\n const validator = getValidator();\r\n\r\n for (const filePath of filePaths) {\r\n try {\r\n // Dynamically import fs module to read file\r\n const fs = require('fs');\r\n const content = fs.readFileSync(filePath, 'utf-8');\r\n const config = JSON.parse(content);\r\n results[filePath] = validator.validate(config);\r\n } catch (error) {\r\n results[filePath] = {\r\n valid: false,\r\n errors: [\r\n {\r\n field: 'file',\r\n message: `Failed to read or parse file: ${error instanceof Error ? error.message : String(error)}`,\r\n path: filePath,\r\n code: 'FILE_READ_ERROR',\r\n },\r\n ],\r\n warnings: [],\r\n configType: 'unknown',\r\n };\r\n }\r\n }\r\n\r\n return results;\r\n}\r\n\r\nexport default ConfigValidator;\r\n"],"names":["ConfigValidator","schema","initialized","getDefaultSchema","$schema","$id","title","description","version","type","validate","config","errors","warnings","valid","field","message","path","code","configType","configObj","detectConfigType","validateAgentWhitelist","validateMCPServers","validateSkillRequirements","validateRuntimeContract","validateTeamConfig","validateJSON","jsonString","JSON","parse","error","Error","String","push","test","value","Array","isArray","agents","i","length","agent","displayName","skills","lastUpdated","servers","serverName","Object","prototype","hasOwnProperty","call","serverConfig","endpoint","isValidURL","requiredSkills","auth","timeoutMs","undefined","tools","toolName","toolConfig","variables","varName","varConfig","varType","validTypes","indexOf","team","id","name","workspace","diskQuota","getPropertyValue","isValidDiskQuota","resources","cpuCores","maxAgents","Number","isInteger","network","coordinatorIp","isValidIPv4","exportEnvVars","envMap","varsObj","key","variable","varObj","coerceToCorrectType","parseInt","parseFloat","toLowerCase","formatErrors","result","output","stringify","warning","url","URL","quota","ip","ipv4Pattern","parts","split","every","part","num","normalizeFieldName","includes","replace","_","letter","toUpperCase","obj","snakeCase","camelCase","validatorInstance","getValidator","validateConfig","isValidConfig","resetValidator","validateConfigFiles","filePaths","results","validator","filePath","fs","require","content","readFileSync"],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Output Type Definitions
|
|
3
|
+
* TypeScript interfaces matching agent-output-v1.json schema
|
|
4
|
+
*
|
|
5
|
+
* @version 1.0.0
|
|
6
|
+
* @description Strict type-safe agent output interfaces for CFN Loop
|
|
7
|
+
*/ // ============================================================================
|
|
8
|
+
// Enums and Type Aliases
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Type Guards
|
|
12
|
+
// ============================================================================
|
|
13
|
+
/**
|
|
14
|
+
* Type guard for Loop 3 output
|
|
15
|
+
*/ export function isLoop3Output(output) {
|
|
16
|
+
return output.output_type === 'loop3';
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Type guard for Loop 2 output
|
|
20
|
+
*/ export function isLoop2Output(output) {
|
|
21
|
+
return output.output_type === 'loop2';
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Type guard for Product Owner output
|
|
25
|
+
*/ export function isProductOwnerOutput(output) {
|
|
26
|
+
return output.output_type === 'product_owner';
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Type guard for base agent output
|
|
30
|
+
*/ export function isValidAgentOutput(value) {
|
|
31
|
+
if (typeof value !== 'object' || value === null) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
const obj = value;
|
|
35
|
+
// Check required base fields
|
|
36
|
+
if (typeof obj.success !== 'boolean' || typeof obj.confidence !== 'number' || typeof obj.iteration !== 'number' || !Array.isArray(obj.errors) || typeof obj.metadata !== 'object' || obj.metadata === null) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
// Check output_type discriminator
|
|
40
|
+
const outputType = obj.output_type;
|
|
41
|
+
return outputType === 'loop3' || outputType === 'loop2' || outputType === 'product_owner';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=agent-output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/types/agent-output.ts"],"sourcesContent":["/**\r\n * Agent Output Type Definitions\r\n * TypeScript interfaces matching agent-output-v1.json schema\r\n *\r\n * @version 1.0.0\r\n * @description Strict type-safe agent output interfaces for CFN Loop\r\n */\r\n\r\n// ============================================================================\r\n// Enums and Type Aliases\r\n// ============================================================================\r\n\r\nexport type DeliverableType =\r\n | 'implementation'\r\n | 'test'\r\n | 'documentation'\r\n | 'config'\r\n | 'schema'\r\n | 'script'\r\n | 'other';\r\n\r\nexport type DeliverableStatus =\r\n | 'created'\r\n | 'modified'\r\n | 'deleted'\r\n | 'validated'\r\n | 'pending';\r\n\r\nexport type IssueSeverity = 'critical' | 'high' | 'medium' | 'low' | 'info';\r\n\r\nexport type IssueCategory =\r\n | 'security'\r\n | 'performance'\r\n | 'quality'\r\n | 'style'\r\n | 'documentation'\r\n | 'testing'\r\n | 'architecture'\r\n | 'other';\r\n\r\nexport type ValidationType =\r\n | 'review'\r\n | 'test'\r\n | 'security'\r\n | 'architecture'\r\n | 'performance'\r\n | 'compliance';\r\n\r\nexport type ProductOwnerDecision = 'PROCEED' | 'ITERATE' | 'ABORT';\r\n\r\nexport type AgentOutputType = 'loop3' | 'loop2' | 'product_owner';\r\n\r\nexport type CFNLoopMode = 'mvp' | 'standard' | 'enterprise';\r\n\r\n// ============================================================================\r\n// Core Interfaces\r\n// ============================================================================\r\n\r\n/**\r\n * Artifact created or modified by agent\r\n */\r\nexport interface Deliverable {\r\n /** Absolute or relative file path */\r\n path: string;\r\n /** Deliverable type */\r\n type: DeliverableType;\r\n /** Deliverable status */\r\n status: DeliverableStatus;\r\n /** File size in bytes */\r\n size_bytes?: number;\r\n /** Number of lines (for text files) */\r\n lines?: number;\r\n /** SHA-256 checksum for integrity validation */\r\n checksum?: string;\r\n}\r\n\r\n/**\r\n * Issue found during validation\r\n */\r\nexport interface Issue {\r\n /** Issue severity level */\r\n severity: IssueSeverity;\r\n /** Issue category */\r\n category: IssueCategory;\r\n /** Human-readable issue description */\r\n message: string;\r\n /** File path and line number (e.g., 'src/file.ts:45') */\r\n location?: string;\r\n /** Suggested fix or improvement */\r\n recommendation?: string;\r\n /** Error code or rule identifier */\r\n code?: string;\r\n}\r\n\r\n/**\r\n * Quantitative metrics from implementation\r\n */\r\nexport interface Metrics {\r\n /** Number of files created */\r\n files_created?: number;\r\n /** Number of files modified */\r\n files_modified?: number;\r\n /** Number of files deleted */\r\n files_deleted?: number;\r\n /** Total lines of code written */\r\n lines_of_code?: number;\r\n /** Test coverage percentage (0.0-1.0) */\r\n test_coverage?: number;\r\n /** Number of tests passed */\r\n tests_passed?: number;\r\n /** Number of tests failed */\r\n tests_failed?: number;\r\n /** Execution time in milliseconds */\r\n execution_time_ms?: number;\r\n /** Memory usage in megabytes */\r\n memory_usage_mb?: number;\r\n /** Additional custom metrics (extensible numeric values) */\r\n custom_metrics?: Record<string, number>;\r\n}\r\n\r\n/**\r\n * Error encountered during execution\r\n */\r\nexport interface AgentError {\r\n /** Error code */\r\n code: string;\r\n /** Error message */\r\n message: string;\r\n /** Stack trace (optional) */\r\n stack?: string;\r\n /** Additional error context */\r\n context?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * Agent execution metadata\r\n */\r\nexport interface AgentMetadata {\r\n /** Type of agent that produced output */\r\n agent_type: string;\r\n /** Unique agent instance ID */\r\n agent_id?: string;\r\n /** Total execution time in milliseconds */\r\n execution_time_ms?: number;\r\n /** ISO 8601 timestamp */\r\n timestamp?: string;\r\n /** Swarm/task identifier */\r\n swarm_id?: string;\r\n /** CFN Loop iteration number */\r\n iteration?: number;\r\n /** CFN Loop execution mode */\r\n mode?: CFNLoopMode;\r\n /** Additional execution context */\r\n context?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * Base output common to all agent types\r\n */\r\nexport interface BaseAgentOutput {\r\n /** Whether execution was successful */\r\n success: boolean;\r\n /** Confidence score (0.0-1.0) */\r\n confidence: number;\r\n /** CFN Loop iteration number */\r\n iteration: number;\r\n /** Errors encountered during execution */\r\n errors: AgentError[];\r\n /** Agent execution metadata */\r\n metadata: AgentMetadata;\r\n}\r\n\r\n// ============================================================================\r\n// Discriminated Union Types\r\n// ============================================================================\r\n\r\n/**\r\n * Loop 3 (Implementer) Output\r\n */\r\nexport interface Loop3Output extends BaseAgentOutput {\r\n /** Discriminator for Loop 3 implementer output */\r\n output_type: 'loop3';\r\n /** Artifacts created or modified */\r\n deliverables: Deliverable[];\r\n /** Quantitative metrics */\r\n metrics?: Metrics;\r\n /** Brief summary of implementation work */\r\n summary?: string;\r\n}\r\n\r\n/**\r\n * Loop 2 (Validator) Output\r\n */\r\nexport interface Loop2Output extends BaseAgentOutput {\r\n /** Discriminator for Loop 2 validator output */\r\n output_type: 'loop2';\r\n /** Type of validation performed */\r\n validation_type: ValidationType;\r\n /** Issues found during validation */\r\n issues: Issue[];\r\n /** Recommendations for improvement */\r\n recommendations: string[];\r\n /** Whether work is approved (consensus vote) */\r\n approved: boolean;\r\n /** Brief summary of validation findings */\r\n summary?: string;\r\n}\r\n\r\n/**\r\n * Product Owner Output\r\n */\r\nexport interface ProductOwnerOutput extends BaseAgentOutput {\r\n /** Discriminator for Product Owner output */\r\n output_type: 'product_owner';\r\n /** Product Owner decision */\r\n decision: ProductOwnerDecision;\r\n /** Explanation for decision */\r\n rationale: string;\r\n /** Whether deliverables were validated */\r\n deliverables_validated: boolean;\r\n /** Next action to take */\r\n next_action: string;\r\n /** Consensus score from Loop 2 validators (0.0-1.0) */\r\n consensus_score?: number;\r\n /** Gate score from Loop 3 implementers (0.0-1.0) */\r\n gate_score?: number;\r\n}\r\n\r\n/**\r\n * Union type for all agent outputs\r\n */\r\nexport type AgentOutput = Loop3Output | Loop2Output | ProductOwnerOutput;\r\n\r\n// ============================================================================\r\n// Type Guards\r\n// ============================================================================\r\n\r\n/**\r\n * Type guard for Loop 3 output\r\n */\r\nexport function isLoop3Output(output: AgentOutput): output is Loop3Output {\r\n return output.output_type === 'loop3';\r\n}\r\n\r\n/**\r\n * Type guard for Loop 2 output\r\n */\r\nexport function isLoop2Output(output: AgentOutput): output is Loop2Output {\r\n return output.output_type === 'loop2';\r\n}\r\n\r\n/**\r\n * Type guard for Product Owner output\r\n */\r\nexport function isProductOwnerOutput(\r\n output: AgentOutput\r\n): output is ProductOwnerOutput {\r\n return output.output_type === 'product_owner';\r\n}\r\n\r\n/**\r\n * Type guard for base agent output\r\n */\r\nexport function isValidAgentOutput(value: unknown): value is AgentOutput {\r\n if (typeof value !== 'object' || value === null) {\r\n return false;\r\n }\r\n\r\n const obj = value as Record<string, unknown>;\r\n\r\n // Check required base fields\r\n if (\r\n typeof obj.success !== 'boolean' ||\r\n typeof obj.confidence !== 'number' ||\r\n typeof obj.iteration !== 'number' ||\r\n !Array.isArray(obj.errors) ||\r\n typeof obj.metadata !== 'object' ||\r\n obj.metadata === null\r\n ) {\r\n return false;\r\n }\r\n\r\n // Check output_type discriminator\r\n const outputType = obj.output_type;\r\n return (\r\n outputType === 'loop3' ||\r\n outputType === 'loop2' ||\r\n outputType === 'product_owner'\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// Validation Result Types\r\n// ============================================================================\r\n\r\n/**\r\n * Validation error details\r\n */\r\nexport interface ValidationError {\r\n /** Field that failed validation */\r\n field: string;\r\n /** Error message */\r\n message: string;\r\n /** JSON path to field */\r\n path: string;\r\n /** Error code */\r\n code: string;\r\n /** Current value (if applicable) */\r\n value?: unknown;\r\n}\r\n\r\n/**\r\n * Validation result\r\n */\r\nexport interface ValidationResult {\r\n /** Whether validation passed */\r\n valid: boolean;\r\n /** Validation errors (if any) */\r\n errors: ValidationError[];\r\n /** Warnings (non-fatal issues) */\r\n warnings: string[];\r\n /** Detected output type */\r\n output_type?: AgentOutputType;\r\n}\r\n\r\n// ============================================================================\r\n// Parser Result Types\r\n// ============================================================================\r\n\r\n/**\r\n * Legacy parser result\r\n */\r\nexport interface ParseResult {\r\n /** Whether parsing was successful */\r\n success: boolean;\r\n /** Parsed agent output (if successful) */\r\n output?: AgentOutput;\r\n /** Parse errors (if unsuccessful) */\r\n errors: string[];\r\n /** Parser confidence (0.0-1.0) */\r\n confidence: number;\r\n}\r\n\r\n// ============================================================================\r\n// Exports\r\n// ============================================================================\r\n\r\nexport default AgentOutput;\r\n"],"names":["isLoop3Output","output","output_type","isLoop2Output","isProductOwnerOutput","isValidAgentOutput","value","obj","success","confidence","iteration","Array","isArray","errors","metadata","outputType"],"mappings":"AAAA;;;;;;CAMC,GAED,+EAA+E;AAC/E,yBAAyB;AACzB,+EAA+E;AA+N/E,+EAA+E;AAC/E,cAAc;AACd,+EAA+E;AAE/E;;CAEC,GACD,OAAO,SAASA,cAAcC,MAAmB;IAC/C,OAAOA,OAAOC,WAAW,KAAK;AAChC;AAEA;;CAEC,GACD,OAAO,SAASC,cAAcF,MAAmB;IAC/C,OAAOA,OAAOC,WAAW,KAAK;AAChC;AAEA;;CAEC,GACD,OAAO,SAASE,qBACdH,MAAmB;IAEnB,OAAOA,OAAOC,WAAW,KAAK;AAChC;AAEA;;CAEC,GACD,OAAO,SAASG,mBAAmBC,KAAc;IAC/C,IAAI,OAAOA,UAAU,YAAYA,UAAU,MAAM;QAC/C,OAAO;IACT;IAEA,MAAMC,MAAMD;IAEZ,6BAA6B;IAC7B,IACE,OAAOC,IAAIC,OAAO,KAAK,aACvB,OAAOD,IAAIE,UAAU,KAAK,YAC1B,OAAOF,IAAIG,SAAS,KAAK,YACzB,CAACC,MAAMC,OAAO,CAACL,IAAIM,MAAM,KACzB,OAAON,IAAIO,QAAQ,KAAK,YACxBP,IAAIO,QAAQ,KAAK,MACjB;QACA,OAAO;IACT;IAEA,kCAAkC;IAClC,MAAMC,aAAaR,IAAIL,WAAW;IAClC,OACEa,eAAe,WACfA,eAAe,WACfA,eAAe;AAEnB"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript type definitions for CFN Configuration System
|
|
3
|
+
* Derived from schemas/cfn-config-v1.json
|
|
4
|
+
*
|
|
5
|
+
* @version 1.0.0
|
|
6
|
+
* @description Canonical types for all CFN configuration formats
|
|
7
|
+
*/ /**
|
|
8
|
+
* Resource allocation limits with explicit property definitions
|
|
9
|
+
* @description All properties are optional but type-safe when present
|
|
10
|
+
*/ /**
|
|
11
|
+
* Type guard helpers
|
|
12
|
+
*/ export function isAgentWhitelistConfig(config) {
|
|
13
|
+
return 'agents' in config && Array.isArray(config.agents);
|
|
14
|
+
}
|
|
15
|
+
export function isMCPServersConfig(config) {
|
|
16
|
+
return 'servers' in config && typeof config.servers === 'object';
|
|
17
|
+
}
|
|
18
|
+
export function isSkillRequirementsConfig(config) {
|
|
19
|
+
return 'tools' in config && typeof config.tools === 'object';
|
|
20
|
+
}
|
|
21
|
+
export function isRuntimeContractConfig(config) {
|
|
22
|
+
return 'variables' in config && config.variables !== undefined;
|
|
23
|
+
}
|
|
24
|
+
export function isTeamConfig(config) {
|
|
25
|
+
return 'team' in config && config.team !== undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/types/config.ts"],"sourcesContent":["/**\r\n * TypeScript type definitions for CFN Configuration System\r\n * Derived from schemas/cfn-config-v1.json\r\n *\r\n * @version 1.0.0\r\n * @description Canonical types for all CFN configuration formats\r\n */\r\n\r\n/**\r\n * Resource allocation limits with explicit property definitions\r\n * @description All properties are optional but type-safe when present\r\n */\r\nexport interface ResourceLimits {\r\n maxMemoryMB?: number;\r\n maxCpuCores?: number;\r\n maxRequestsPerMinute?: number;\r\n maxConcurrentRequests?: number;\r\n maxConnections?: number;\r\n maxCpuPercent?: number;\r\n maxWorkflows?: number;\r\n maxSessions?: number;\r\n}\r\n\r\n/**\r\n * Environment variable definition\r\n */\r\nexport interface EnvironmentVariable {\r\n value?: string | number | boolean | null;\r\n description: string;\r\n type: 'string' | 'integer' | 'number' | 'boolean';\r\n required?: boolean;\r\n default?: string | number | boolean | null;\r\n scope?: string[];\r\n legacyAliases?: string[];\r\n example?: string | number | boolean;\r\n}\r\n\r\n/**\r\n * Health check configuration\r\n */\r\nexport interface HealthCheckConfig {\r\n enabled?: boolean;\r\n path?: string;\r\n interval?: number;\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Authentication configuration\r\n */\r\nexport interface AuthConfig {\r\n type: 'token' | 'oauth2' | 'basic' | 'apikey';\r\n header?: string;\r\n secretName?: string;\r\n required?: boolean;\r\n}\r\n\r\n/**\r\n * Agent whitelist configuration\r\n */\r\nexport interface Agent {\r\n type: string;\r\n displayName: string;\r\n skills: string[];\r\n allowedMcpServers?: string[];\r\n resourceLimits?: ResourceLimits;\r\n description?: string;\r\n}\r\n\r\nexport interface AgentWhitelistConfig {\r\n version: string;\r\n description?: string;\r\n lastUpdated?: string;\r\n agents: Agent[];\r\n}\r\n\r\n/**\r\n * MCP Server configuration\r\n */\r\nexport interface MCPServer {\r\n endpoint: string;\r\n requiredSkills: string[];\r\n auth: AuthConfig;\r\n healthCheck?: string | HealthCheckConfig;\r\n timeoutMs?: number;\r\n retryAttempts?: number;\r\n resourceLimits?: ResourceLimits;\r\n capabilities?: string[];\r\n}\r\n\r\nexport interface MCPServersConfig {\r\n version: string;\r\n description?: string;\r\n lastUpdated?: string;\r\n servers: Record<string, MCPServer>;\r\n}\r\n\r\n/**\r\n * Skill requirements configuration\r\n */\r\nexport interface ResourceImpact {\r\n memoryMB?: number;\r\n cpuUnits?: number;\r\n durationSeconds?: number;\r\n}\r\n\r\nexport interface ToolRequirement {\r\n displayName: string;\r\n requiredSkills: string[];\r\n optionalSkills?: string[];\r\n allowedAgentTypes?: string[];\r\n resourceImpact?: ResourceImpact;\r\n description?: string;\r\n}\r\n\r\nexport interface SkillRequirementsConfig {\r\n version: string;\r\n description?: string;\r\n lastUpdated?: string;\r\n tools: Record<string, ToolRequirement>;\r\n}\r\n\r\n/**\r\n * Runtime contract configuration\r\n */\r\nexport interface RuntimeContractConfig {\r\n version: string;\r\n lastUpdated?: string;\r\n generated?: string;\r\n variables?: Record<string, EnvironmentVariable>;\r\n}\r\n\r\n/**\r\n * Team configuration\r\n */\r\nexport interface TeamWorkspace {\r\n path?: string;\r\n diskQuota?: string;\r\n}\r\n\r\nexport interface TeamResources {\r\n memory?: string;\r\n cpuCores?: number;\r\n maxAgents?: number;\r\n}\r\n\r\nexport interface TeamNetwork {\r\n subnetId?: number;\r\n coordinatorIp?: string;\r\n}\r\n\r\nexport interface Team {\r\n id: string;\r\n name: string;\r\n description?: string;\r\n workspace?: TeamWorkspace;\r\n resources?: TeamResources;\r\n allowedSkills?: string[];\r\n network?: TeamNetwork;\r\n}\r\n\r\nexport interface TeamConfig {\r\n team: Team;\r\n}\r\n\r\n/**\r\n * Union type for all possible CFN configuration types\r\n */\r\nexport type CFNConfig =\r\n | AgentWhitelistConfig\r\n | MCPServersConfig\r\n | SkillRequirementsConfig\r\n | RuntimeContractConfig\r\n | TeamConfig;\r\n\r\n/**\r\n * Validation result type\r\n */\r\nexport interface ValidationError {\r\n field: string;\r\n message: string;\r\n path: string;\r\n value?: unknown;\r\n code: string;\r\n}\r\n\r\nexport interface ValidationResult {\r\n valid: boolean;\r\n errors: ValidationError[];\r\n warnings: string[];\r\n configType?: string;\r\n}\r\n\r\n/**\r\n * Environment variable export map\r\n */\r\nexport interface EnvVarExportMap {\r\n [key: string]: string | number | boolean;\r\n}\r\n\r\n/**\r\n * Configuration loader options\r\n */\r\nexport interface ConfigLoaderOptions {\r\n validateSchema?: boolean;\r\n strictMode?: boolean;\r\n resolveEnvVars?: boolean;\r\n warnOnLegacyVars?: boolean;\r\n}\r\n\r\n/**\r\n * Type guard helpers\r\n */\r\nexport function isAgentWhitelistConfig(\r\n config: CFNConfig\r\n): config is AgentWhitelistConfig {\r\n return 'agents' in config && Array.isArray((config as AgentWhitelistConfig).agents);\r\n}\r\n\r\nexport function isMCPServersConfig(\r\n config: CFNConfig\r\n): config is MCPServersConfig {\r\n return (\r\n 'servers' in config &&\r\n typeof (config as MCPServersConfig).servers === 'object'\r\n );\r\n}\r\n\r\nexport function isSkillRequirementsConfig(\r\n config: CFNConfig\r\n): config is SkillRequirementsConfig {\r\n return (\r\n 'tools' in config &&\r\n typeof (config as SkillRequirementsConfig).tools === 'object'\r\n );\r\n}\r\n\r\nexport function isRuntimeContractConfig(\r\n config: CFNConfig\r\n): config is RuntimeContractConfig {\r\n return (\r\n 'variables' in config &&\r\n (config as RuntimeContractConfig).variables !== undefined\r\n );\r\n}\r\n\r\nexport function isTeamConfig(config: CFNConfig): config is TeamConfig {\r\n return 'team' in config && (config as TeamConfig).team !== undefined;\r\n}\r\n"],"names":["isAgentWhitelistConfig","config","Array","isArray","agents","isMCPServersConfig","servers","isSkillRequirementsConfig","tools","isRuntimeContractConfig","variables","undefined","isTeamConfig","team"],"mappings":"AAAA;;;;;;CAMC,GAED;;;CAGC,GAuMD;;CAEC,GACD,OAAO,SAASA,uBACdC,MAAiB;IAEjB,OAAO,YAAYA,UAAUC,MAAMC,OAAO,CAAC,AAACF,OAAgCG,MAAM;AACpF;AAEA,OAAO,SAASC,mBACdJ,MAAiB;IAEjB,OACE,aAAaA,UACb,OAAO,AAACA,OAA4BK,OAAO,KAAK;AAEpD;AAEA,OAAO,SAASC,0BACdN,MAAiB;IAEjB,OACE,WAAWA,UACX,OAAO,AAACA,OAAmCO,KAAK,KAAK;AAEzD;AAEA,OAAO,SAASC,wBACdR,MAAiB;IAEjB,OACE,eAAeA,UACf,AAACA,OAAiCS,SAAS,KAAKC;AAEpD;AAEA,OAAO,SAASC,aAAaX,MAAiB;IAC5C,OAAO,UAAUA,UAAU,AAACA,OAAsBY,IAAI,KAAKF;AAC7D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-flow-novice",
|
|
3
|
-
"version": "2.15.
|
|
3
|
+
"version": "2.15.3",
|
|
4
4
|
"description": "AI agent orchestration framework with namespace-isolated skills, agents, and CFN Loop validation. Safe installation with ~0.01% collision risk.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"files": [
|
|
19
19
|
"dist/",
|
|
20
20
|
"claude-assets/",
|
|
21
|
+
".claude/skills/agent-lifecycle/",
|
|
21
22
|
".claude/skills/cfn-ace-system/",
|
|
22
23
|
".claude/skills/cfn-agent-discovery/",
|
|
23
24
|
".claude/skills/cfn-agent-execution/",
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Artifact Registry TTL-based Cleanup Script
|
|
3
|
+
# Version: 1.0.0
|
|
4
|
+
# Purpose: Automatically archive/delete expired artifacts based on retention policy
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# ./artifact-cleanup.sh [OPTIONS]
|
|
8
|
+
#
|
|
9
|
+
# Options:
|
|
10
|
+
# --dry-run Show what would be cleaned up without making changes
|
|
11
|
+
# --policy <policy> Only clean specific retention policy (ephemeral, standard, custom)
|
|
12
|
+
# --archive-days <N> Days before archived artifacts are deleted (default: 90)
|
|
13
|
+
# --db-path <path> Path to SQLite database (default: ./artifacts/database/registry.db)
|
|
14
|
+
# --log-file <path> Path to log file (default: ./artifacts/logs/cleanup.log)
|
|
15
|
+
# --verbose Enable verbose logging
|
|
16
|
+
# --help Show this help message
|
|
17
|
+
#
|
|
18
|
+
# Exit Codes:
|
|
19
|
+
# 0 - Success
|
|
20
|
+
# 1 - General error
|
|
21
|
+
# 2 - Database error
|
|
22
|
+
# 3 - Validation error
|
|
23
|
+
|
|
24
|
+
set -euo pipefail
|
|
25
|
+
|
|
26
|
+
# ============================================================================
|
|
27
|
+
# Configuration and Defaults
|
|
28
|
+
# ============================================================================
|
|
29
|
+
|
|
30
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
31
|
+
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
32
|
+
|
|
33
|
+
# Default configuration
|
|
34
|
+
DRY_RUN=false
|
|
35
|
+
POLICY_FILTER=""
|
|
36
|
+
ARCHIVE_DAYS=90
|
|
37
|
+
DB_PATH="${PROJECT_ROOT}/artifacts/database/registry.db"
|
|
38
|
+
LOG_FILE="${PROJECT_ROOT}/artifacts/logs/cleanup.log"
|
|
39
|
+
VERBOSE=false
|
|
40
|
+
|
|
41
|
+
# Counters
|
|
42
|
+
ARTIFACTS_ARCHIVED=0
|
|
43
|
+
ARTIFACTS_DELETED=0
|
|
44
|
+
ERRORS=0
|
|
45
|
+
|
|
46
|
+
# ============================================================================
|
|
47
|
+
# Logging Functions
|
|
48
|
+
# ============================================================================
|
|
49
|
+
|
|
50
|
+
log() {
|
|
51
|
+
local level="$1"
|
|
52
|
+
shift
|
|
53
|
+
local message="$*"
|
|
54
|
+
local timestamp
|
|
55
|
+
timestamp="$(date '+%Y-%m-%d %H:%M:%S')"
|
|
56
|
+
|
|
57
|
+
echo "[${timestamp}] [${level}] ${message}" | tee -a "$LOG_FILE"
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
log_info() {
|
|
61
|
+
log "INFO" "$@"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
log_warn() {
|
|
65
|
+
log "WARN" "$@"
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
log_error() {
|
|
69
|
+
log "ERROR" "$@"
|
|
70
|
+
((ERRORS++)) || true
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
log_debug() {
|
|
74
|
+
if [[ "$VERBOSE" == "true" ]]; then
|
|
75
|
+
log "DEBUG" "$@"
|
|
76
|
+
fi
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# ============================================================================
|
|
80
|
+
# Utility Functions
|
|
81
|
+
# ============================================================================
|
|
82
|
+
|
|
83
|
+
show_help() {
|
|
84
|
+
grep '^#' "$0" | grep -v '#!/usr/bin/env' | sed 's/^# //; s/^#//'
|
|
85
|
+
exit 0
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
ensure_directory() {
|
|
89
|
+
local dir="$1"
|
|
90
|
+
if [[ ! -d "$dir" ]]; then
|
|
91
|
+
mkdir -p "$dir"
|
|
92
|
+
log_debug "Created directory: $dir"
|
|
93
|
+
fi
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
validate_database() {
|
|
97
|
+
if [[ ! -f "$DB_PATH" ]]; then
|
|
98
|
+
log_error "Database not found: $DB_PATH"
|
|
99
|
+
exit 2
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
# Test database connectivity
|
|
103
|
+
if ! sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM artifacts;" &>/dev/null; then
|
|
104
|
+
log_error "Failed to query database or artifacts table does not exist"
|
|
105
|
+
exit 2
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
log_debug "Database validated: $DB_PATH"
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# ============================================================================
|
|
112
|
+
# Cleanup Functions
|
|
113
|
+
# ============================================================================
|
|
114
|
+
|
|
115
|
+
find_expired_artifacts() {
|
|
116
|
+
local policy_clause=""
|
|
117
|
+
if [[ -n "$POLICY_FILTER" ]]; then
|
|
118
|
+
policy_clause="AND retention_policy = '$POLICY_FILTER'"
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
sqlite3 "$DB_PATH" <<EOF
|
|
122
|
+
SELECT id, name, type, storage_location, retention_policy,
|
|
123
|
+
created_at, expires_at, CAST((julianday('now') - julianday(expires_at)) AS INTEGER) as days_expired
|
|
124
|
+
FROM artifacts
|
|
125
|
+
WHERE status = 'active'
|
|
126
|
+
AND expires_at IS NOT NULL
|
|
127
|
+
AND datetime('now') >= expires_at
|
|
128
|
+
$policy_clause
|
|
129
|
+
ORDER BY created_at ASC;
|
|
130
|
+
EOF
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
archive_artifact() {
|
|
134
|
+
local artifact_id="$1"
|
|
135
|
+
local artifact_name="$2"
|
|
136
|
+
|
|
137
|
+
if [[ "$DRY_RUN" == "true" ]]; then
|
|
138
|
+
log_info "[DRY-RUN] Would archive: $artifact_name (ID: $artifact_id)"
|
|
139
|
+
((ARTIFACTS_ARCHIVED++)) || true
|
|
140
|
+
return 0
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
local result
|
|
144
|
+
result=$(sqlite3 "$DB_PATH" <<EOF
|
|
145
|
+
UPDATE artifacts
|
|
146
|
+
SET status = 'archived',
|
|
147
|
+
archived_at = CURRENT_TIMESTAMP,
|
|
148
|
+
updated_at = CURRENT_TIMESTAMP
|
|
149
|
+
WHERE id = '$artifact_id';
|
|
150
|
+
SELECT changes();
|
|
151
|
+
EOF
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
if [[ "$result" == "1" ]]; then
|
|
155
|
+
log_info "Archived: $artifact_name (ID: $artifact_id)"
|
|
156
|
+
((ARTIFACTS_ARCHIVED++)) || true
|
|
157
|
+
return 0
|
|
158
|
+
else
|
|
159
|
+
log_error "Failed to archive: $artifact_name (ID: $artifact_id)"
|
|
160
|
+
return 1
|
|
161
|
+
fi
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
find_archived_for_deletion() {
|
|
165
|
+
local policy_clause=""
|
|
166
|
+
if [[ -n "$POLICY_FILTER" ]]; then
|
|
167
|
+
policy_clause="AND retention_policy = '$POLICY_FILTER'"
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
sqlite3 "$DB_PATH" <<EOF
|
|
171
|
+
SELECT id, name, type, storage_location, retention_policy,
|
|
172
|
+
archived_at, CAST((julianday('now') - julianday(archived_at)) AS INTEGER) as days_archived
|
|
173
|
+
FROM artifacts
|
|
174
|
+
WHERE status = 'archived'
|
|
175
|
+
AND archived_at IS NOT NULL
|
|
176
|
+
AND datetime('now') >= datetime(archived_at, '+$ARCHIVE_DAYS days')
|
|
177
|
+
$policy_clause
|
|
178
|
+
ORDER BY archived_at ASC;
|
|
179
|
+
EOF
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
delete_artifact() {
|
|
183
|
+
local artifact_id="$1"
|
|
184
|
+
local artifact_name="$2"
|
|
185
|
+
|
|
186
|
+
if [[ "$DRY_RUN" == "true" ]]; then
|
|
187
|
+
log_info "[DRY-RUN] Would delete: $artifact_name (ID: $artifact_id)"
|
|
188
|
+
((ARTIFACTS_DELETED++)) || true
|
|
189
|
+
return 0
|
|
190
|
+
fi
|
|
191
|
+
|
|
192
|
+
local result
|
|
193
|
+
result=$(sqlite3 "$DB_PATH" <<EOF
|
|
194
|
+
UPDATE artifacts
|
|
195
|
+
SET status = 'deleted',
|
|
196
|
+
deleted_at = CURRENT_TIMESTAMP,
|
|
197
|
+
updated_at = CURRENT_TIMESTAMP
|
|
198
|
+
WHERE id = '$artifact_id';
|
|
199
|
+
SELECT changes();
|
|
200
|
+
EOF
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
if [[ "$result" == "1" ]]; then
|
|
204
|
+
log_info "Deleted: $artifact_name (ID: $artifact_id)"
|
|
205
|
+
((ARTIFACTS_DELETED++)) || true
|
|
206
|
+
return 0
|
|
207
|
+
else
|
|
208
|
+
log_error "Failed to delete: $artifact_name (ID: $artifact_id)"
|
|
209
|
+
return 1
|
|
210
|
+
fi
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
# ============================================================================
|
|
214
|
+
# Main Cleanup Logic
|
|
215
|
+
# ============================================================================
|
|
216
|
+
|
|
217
|
+
cleanup_expired_artifacts() {
|
|
218
|
+
log_info "=== Starting Artifact Cleanup ==="
|
|
219
|
+
log_info "Configuration:"
|
|
220
|
+
log_info " - Database: $DB_PATH"
|
|
221
|
+
log_info " - Dry Run: $DRY_RUN"
|
|
222
|
+
log_info " - Policy Filter: ${POLICY_FILTER:-all}"
|
|
223
|
+
log_info " - Archive Days: $ARCHIVE_DAYS"
|
|
224
|
+
|
|
225
|
+
# Step 1: Archive expired active artifacts
|
|
226
|
+
log_info "--- Step 1: Finding expired active artifacts ---"
|
|
227
|
+
local expired_artifacts
|
|
228
|
+
expired_artifacts=$(find_expired_artifacts)
|
|
229
|
+
|
|
230
|
+
if [[ -z "$expired_artifacts" ]]; then
|
|
231
|
+
log_info "No expired artifacts found for archival"
|
|
232
|
+
else
|
|
233
|
+
local count
|
|
234
|
+
count=$(echo "$expired_artifacts" | wc -l)
|
|
235
|
+
log_info "Found $count expired artifact(s) to archive"
|
|
236
|
+
|
|
237
|
+
while IFS='|' read -r id name type storage policy created expires days_expired; do
|
|
238
|
+
log_debug "Processing: $name (Type: $type, Policy: $policy, Expired: ${days_expired}d ago)"
|
|
239
|
+
archive_artifact "$id" "$name" || true
|
|
240
|
+
done <<< "$expired_artifacts"
|
|
241
|
+
fi
|
|
242
|
+
|
|
243
|
+
# Step 2: Delete old archived artifacts
|
|
244
|
+
log_info "--- Step 2: Finding old archived artifacts ---"
|
|
245
|
+
local archived_artifacts
|
|
246
|
+
archived_artifacts=$(find_archived_for_deletion)
|
|
247
|
+
|
|
248
|
+
if [[ -z "$archived_artifacts" ]]; then
|
|
249
|
+
log_info "No archived artifacts ready for deletion"
|
|
250
|
+
else
|
|
251
|
+
local count
|
|
252
|
+
count=$(echo "$archived_artifacts" | wc -l)
|
|
253
|
+
log_info "Found $count archived artifact(s) ready for deletion"
|
|
254
|
+
|
|
255
|
+
while IFS='|' read -r id name type storage policy archived days_archived; do
|
|
256
|
+
log_debug "Processing: $name (Type: $type, Policy: $policy, Archived: ${days_archived}d ago)"
|
|
257
|
+
delete_artifact "$id" "$name" || true
|
|
258
|
+
done <<< "$archived_artifacts"
|
|
259
|
+
fi
|
|
260
|
+
|
|
261
|
+
# Summary
|
|
262
|
+
log_info "=== Cleanup Summary ==="
|
|
263
|
+
log_info " - Artifacts Archived: $ARTIFACTS_ARCHIVED"
|
|
264
|
+
log_info " - Artifacts Deleted: $ARTIFACTS_DELETED"
|
|
265
|
+
log_info " - Errors: $ERRORS"
|
|
266
|
+
|
|
267
|
+
if [[ "$DRY_RUN" == "true" ]]; then
|
|
268
|
+
log_info " - Mode: DRY RUN (no changes made)"
|
|
269
|
+
fi
|
|
270
|
+
|
|
271
|
+
if [[ $ERRORS -gt 0 ]]; then
|
|
272
|
+
exit 1
|
|
273
|
+
fi
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
get_cleanup_statistics() {
|
|
277
|
+
log_info "=== Artifact Registry Statistics ==="
|
|
278
|
+
|
|
279
|
+
local stats
|
|
280
|
+
stats=$(sqlite3 -header -column "$DB_PATH" <<EOF
|
|
281
|
+
SELECT
|
|
282
|
+
retention_policy,
|
|
283
|
+
COUNT(*) as total,
|
|
284
|
+
SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) as active,
|
|
285
|
+
SUM(CASE WHEN status = 'archived' THEN 1 ELSE 0 END) as archived,
|
|
286
|
+
SUM(CASE WHEN status = 'deleted' THEN 1 ELSE 0 END) as deleted,
|
|
287
|
+
SUM(CASE WHEN cleanup_eligible = 1 THEN 1 ELSE 0 END) as cleanup_eligible,
|
|
288
|
+
ROUND(COALESCE(SUM(size_bytes), 0) / 1024.0 / 1024.0, 2) as size_mb
|
|
289
|
+
FROM artifacts
|
|
290
|
+
GROUP BY retention_policy
|
|
291
|
+
ORDER BY retention_policy;
|
|
292
|
+
EOF
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
echo "$stats" | tee -a "$LOG_FILE"
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
# ============================================================================
|
|
299
|
+
# Argument Parsing
|
|
300
|
+
# ============================================================================
|
|
301
|
+
|
|
302
|
+
parse_arguments() {
|
|
303
|
+
while [[ $# -gt 0 ]]; do
|
|
304
|
+
case "$1" in
|
|
305
|
+
--dry-run)
|
|
306
|
+
DRY_RUN=true
|
|
307
|
+
shift
|
|
308
|
+
;;
|
|
309
|
+
--policy)
|
|
310
|
+
POLICY_FILTER="$2"
|
|
311
|
+
shift 2
|
|
312
|
+
;;
|
|
313
|
+
--archive-days)
|
|
314
|
+
ARCHIVE_DAYS="$2"
|
|
315
|
+
shift 2
|
|
316
|
+
;;
|
|
317
|
+
--db-path)
|
|
318
|
+
DB_PATH="$2"
|
|
319
|
+
shift 2
|
|
320
|
+
;;
|
|
321
|
+
--log-file)
|
|
322
|
+
LOG_FILE="$2"
|
|
323
|
+
shift 2
|
|
324
|
+
;;
|
|
325
|
+
--verbose)
|
|
326
|
+
VERBOSE=true
|
|
327
|
+
shift
|
|
328
|
+
;;
|
|
329
|
+
--help)
|
|
330
|
+
show_help
|
|
331
|
+
;;
|
|
332
|
+
*)
|
|
333
|
+
log_error "Unknown option: $1"
|
|
334
|
+
show_help
|
|
335
|
+
exit 3
|
|
336
|
+
;;
|
|
337
|
+
esac
|
|
338
|
+
done
|
|
339
|
+
|
|
340
|
+
# Validate policy filter if provided
|
|
341
|
+
if [[ -n "$POLICY_FILTER" ]]; then
|
|
342
|
+
case "$POLICY_FILTER" in
|
|
343
|
+
ephemeral|standard|permanent|custom)
|
|
344
|
+
;;
|
|
345
|
+
*)
|
|
346
|
+
log_error "Invalid retention policy: $POLICY_FILTER"
|
|
347
|
+
log_error "Valid values: ephemeral, standard, permanent, custom"
|
|
348
|
+
exit 3
|
|
349
|
+
;;
|
|
350
|
+
esac
|
|
351
|
+
fi
|
|
352
|
+
|
|
353
|
+
# Validate archive days
|
|
354
|
+
if ! [[ "$ARCHIVE_DAYS" =~ ^[0-9]+$ ]] || [[ "$ARCHIVE_DAYS" -lt 0 ]]; then
|
|
355
|
+
log_error "Invalid archive days: $ARCHIVE_DAYS (must be non-negative integer)"
|
|
356
|
+
exit 3
|
|
357
|
+
fi
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
# ============================================================================
|
|
361
|
+
# Main Execution
|
|
362
|
+
# ============================================================================
|
|
363
|
+
|
|
364
|
+
main() {
|
|
365
|
+
parse_arguments "$@"
|
|
366
|
+
|
|
367
|
+
# Ensure log directory exists
|
|
368
|
+
ensure_directory "$(dirname "$LOG_FILE")"
|
|
369
|
+
|
|
370
|
+
log_info "Artifact Cleanup Script - Version 1.0.0"
|
|
371
|
+
log_info "Starting at $(date '+%Y-%m-%d %H:%M:%S')"
|
|
372
|
+
|
|
373
|
+
# Validate database
|
|
374
|
+
validate_database
|
|
375
|
+
|
|
376
|
+
# Show statistics before cleanup
|
|
377
|
+
get_cleanup_statistics
|
|
378
|
+
|
|
379
|
+
# Perform cleanup
|
|
380
|
+
cleanup_expired_artifacts
|
|
381
|
+
|
|
382
|
+
# Show statistics after cleanup
|
|
383
|
+
get_cleanup_statistics
|
|
384
|
+
|
|
385
|
+
log_info "Cleanup completed at $(date '+%Y-%m-%d %H:%M:%S')"
|
|
386
|
+
exit 0
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
# Run main if executed directly
|
|
390
|
+
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
391
|
+
main "$@"
|
|
392
|
+
fi
|