From a340eb6ddcf39d74370f14302bad4a5ab79a5a82 Mon Sep 17 00:00:00 2001 From: chitcommit <208086304+chitcommit@users.noreply.github.com> Date: Wed, 3 Jun 2026 18:52:57 +0000 Subject: [PATCH 1/2] chore: rm orphan notion-sync.ts copies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both copies were MD5-identical (45723e4b30dfd91864ec2d7cd6954abc) and outside tsconfig.json include (client/src, shared, server) — never built, never imported. Refs: chittycanon://gov/killlist/2026-06-02-notion Co-Authored-By: Claude Opus 4.7 (1M context) --- .../notion-integration/notion-sync.ts | 553 ------------------ .../notion-integration/notion-sync.ts | 553 ------------------ 2 files changed, 1106 deletions(-) delete mode 100644 cross-session-sync/notion-integration/notion-sync.ts delete mode 100644 src/cross-session-sync/notion-integration/notion-sync.ts diff --git a/cross-session-sync/notion-integration/notion-sync.ts b/cross-session-sync/notion-integration/notion-sync.ts deleted file mode 100644 index f847ee1..0000000 --- a/cross-session-sync/notion-integration/notion-sync.ts +++ /dev/null @@ -1,553 +0,0 @@ -import { Client } from '@notionhq/client'; -import { PageObjectResponse, DatabaseObjectResponse } from '@notionhq/client/build/src/api-endpoints'; - -interface SessionData { - id: string; - name: string; - status: string; - githubBranch?: string; - githubPR?: number; - tasks: string[]; - lastHeartbeat: number; -} - -interface TaskData { - id: string; - name: string; - status: string; - sessionId?: string; - priority: number; - dependencies: string[]; - githubIssue?: number; -} - -export class NotionSyncManager { - private notion: Client; - private databaseId: string; - private sessionsDatabase: string; - private tasksDatabase: string; - - constructor(config: { - notionToken: string; - mainDatabaseId: string; - sessionsDatabaseId: string; - tasksDatabaseId: string; - }) { - this.notion = new Client({ auth: config.notionToken }); - this.databaseId = config.mainDatabaseId; - this.sessionsDatabase = config.sessionsDatabaseId; - this.tasksDatabase = config.tasksDatabaseId; - } - - async createSessionDashboard(session: SessionData): Promise { - const page = await this.notion.pages.create({ - parent: { database_id: this.sessionsDatabase }, - icon: { - type: 'emoji', - emoji: session.status === 'active' ? '🟢' : '🔴' - }, - properties: { - 'Name': { - title: [{ - text: { content: session.name } - }] - }, - 'Session ID': { - rich_text: [{ - text: { content: session.id } - }] - }, - 'Status': { - select: { - name: session.status - } - }, - 'GitHub Branch': { - rich_text: session.githubBranch ? [{ - text: { content: session.githubBranch } - }] : [] - }, - 'GitHub PR': { - number: session.githubPR || null - }, - 'Last Heartbeat': { - date: { - start: new Date(session.lastHeartbeat).toISOString() - } - }, - 'Active Tasks': { - number: session.tasks.length - } - }, - children: [ - { - object: 'block', - type: 'heading_1', - heading_1: { - rich_text: [{ - text: { content: `Session: ${session.name}` } - }] - } - }, - { - object: 'block', - type: 'divider', - divider: {} - }, - { - object: 'block', - type: 'heading_2', - heading_2: { - rich_text: [{ - text: { content: '📊 Real-Time Metrics' } - }] - } - }, - { - object: 'block', - type: 'synced_block', - synced_block: { - synced_from: null, - children: [ - { - object: 'block', - type: 'callout', - callout: { - rich_text: [{ - text: { content: 'Session metrics will be updated in real-time' } - }], - icon: { emoji: '📈' } - } - } - ] - } - }, - { - object: 'block', - type: 'heading_2', - heading_2: { - rich_text: [{ - text: { content: '🔄 GitHub Integration' } - }] - } - }, - { - object: 'block', - type: 'embed', - embed: { - url: session.githubBranch - ? `https://github.com/${process.env.GITHUB_REPO}/tree/${session.githubBranch}` - : 'https://github.com' - } - }, - { - object: 'block', - type: 'heading_2', - heading_2: { - rich_text: [{ - text: { content: '📝 Active Tasks' } - }] - } - }, - { - object: 'block', - type: 'child_database', - child_database: { - title: 'Session Tasks' - } - } - ] - }); - - return page.id; - } - - async updateSessionStatus( - pageId: string, - session: Partial - ): Promise { - const updates: any = {}; - - if (session.status !== undefined) { - updates['Status'] = { - select: { name: session.status } - }; - } - - if (session.lastHeartbeat !== undefined) { - updates['Last Heartbeat'] = { - date: { - start: new Date(session.lastHeartbeat).toISOString() - } - }; - } - - if (session.tasks !== undefined) { - updates['Active Tasks'] = { - number: session.tasks.length - }; - } - - await this.notion.pages.update({ - page_id: pageId, - properties: updates, - icon: { - type: 'emoji', - emoji: session.status === 'active' ? '🟢' : '🔴' - } - }); - } - - async createTaskCard(task: TaskData): Promise { - const page = await this.notion.pages.create({ - parent: { database_id: this.tasksDatabase }, - icon: { - type: 'emoji', - emoji: this.getTaskEmoji(task.status) - }, - properties: { - 'Title': { - title: [{ - text: { content: task.name } - }] - }, - 'Task ID': { - rich_text: [{ - text: { content: task.id } - }] - }, - 'Status': { - select: { - name: task.status - } - }, - 'Priority': { - select: { - name: this.getPriorityLabel(task.priority) - } - }, - 'Assigned Session': { - rich_text: task.sessionId ? [{ - text: { content: task.sessionId } - }] : [] - }, - 'GitHub Issue': { - number: task.githubIssue || null - }, - 'Dependencies': { - multi_select: task.dependencies.map(dep => ({ name: dep })) - } - } - }); - - return page.id; - } - - async createCoordinationDashboard(): Promise { - const page = await this.notion.pages.create({ - parent: { database_id: this.databaseId }, - icon: { type: 'emoji', emoji: '🎯' }, - cover: { - type: 'external', - external: { - url: 'https://images.unsplash.com/photo-1542744173-8e7e53415bb0' - } - }, - properties: { - 'Title': { - title: [{ - text: { content: 'Cross-Session Coordination Dashboard' } - }] - }, - 'Type': { - select: { name: 'Dashboard' } - }, - 'Created': { - date: { - start: new Date().toISOString() - } - } - }, - children: [ - { - object: 'block', - type: 'heading_1', - heading_1: { - rich_text: [{ - text: { - content: '🚀 Cross-Session Coordination Center', - annotations: { bold: true } - } - }] - } - }, - { - object: 'block', - type: 'callout', - callout: { - rich_text: [{ - text: { - content: 'Real-time coordination between multiple Claude sessions with GitHub, Neon, and Cloudflare integration' - } - }], - icon: { emoji: '💡' }, - color: 'blue_background' - } - }, - { - object: 'block', - type: 'divider', - divider: {} - }, - { - object: 'block', - type: 'heading_2', - heading_2: { - rich_text: [{ - text: { content: '📊 Active Sessions' } - }] - } - }, - { - object: 'block', - type: 'child_database', - child_database: { - title: 'Active Sessions' - } - }, - { - object: 'block', - type: 'heading_2', - heading_2: { - rich_text: [{ - text: { content: '📋 Task Queue' } - }] - } - }, - { - object: 'block', - type: 'child_database', - child_database: { - title: 'Global Task Queue' - } - }, - { - object: 'block', - type: 'heading_2', - heading_2: { - rich_text: [{ - text: { content: '🔄 GitHub Activity' } - }] - } - }, - { - object: 'block', - type: 'synced_block', - synced_block: { - synced_from: null, - children: [ - { - object: 'block', - type: 'embed', - embed: { - url: `https://github.com/${process.env.GITHUB_REPO}/pulse` - } - } - ] - } - }, - { - object: 'block', - type: 'heading_2', - heading_2: { - rich_text: [{ - text: { content: '🗄️ Neon Database Status' } - }] - } - }, - { - object: 'block', - type: 'code', - code: { - rich_text: [{ - text: { content: 'SELECT * FROM sessions WHERE status = \'active\';' } - }], - language: 'sql' - } - }, - { - object: 'block', - type: 'heading_2', - heading_2: { - rich_text: [{ - text: { content: '⚡ Cloudflare Workers Status' } - }] - } - }, - { - object: 'block', - type: 'table', - table: { - table_width: 3, - has_column_header: true, - has_row_header: false, - children: [ - { - object: 'block', - type: 'table_row', - table_row: { - cells: [ - [{ text: { content: 'Worker' } }], - [{ text: { content: 'Status' } }], - [{ text: { content: 'Last Update' } }] - ] - } - }, - { - object: 'block', - type: 'table_row', - table_row: { - cells: [ - [{ text: { content: 'cross-session-sync' } }], - [{ text: { content: '✅ Active' } }], - [{ text: { content: new Date().toISOString() } }] - ] - } - } - ] - } - } - ] - }); - - return page.id; - } - - async syncWithNeonDatabase(neonClient: any): Promise { - const sessions = await neonClient.query('SELECT * FROM sessions WHERE status = $1', ['active']); - - for (const session of sessions.rows) { - const notionSession = await this.findSessionByID(session.id); - - if (notionSession) { - await this.updateSessionStatus(notionSession.id, { - status: session.status, - lastHeartbeat: session.last_heartbeat, - tasks: session.tasks - }); - } else { - const pageId = await this.createSessionDashboard({ - id: session.id, - name: session.session_name, - status: session.status, - githubBranch: session.github_branch, - githubPR: session.github_pr_number, - tasks: session.tasks, - lastHeartbeat: session.last_heartbeat - }); - - await neonClient.query( - 'UPDATE sessions SET notion_page_id = $1 WHERE id = $2', - [pageId, session.id] - ); - } - } - } - - async syncGitHubActions(githubOctokit: any): Promise { - const { data: runs } = await githubOctokit.actions.listWorkflowRunsForRepo({ - owner: process.env.GITHUB_OWNER, - repo: process.env.GITHUB_REPO, - per_page: 10 - }); - - for (const run of runs.workflow_runs) { - await this.updateGitHubActionStatus(run); - } - } - - private async findSessionByID(sessionId: string): Promise { - const response = await this.notion.databases.query({ - database_id: this.sessionsDatabase, - filter: { - property: 'Session ID', - rich_text: { - equals: sessionId - } - } - }); - - return response.results[0] as PageObjectResponse || null; - } - - private async updateGitHubActionStatus(run: any): Promise { - const block = { - object: 'block' as const, - type: 'callout' as const, - callout: { - rich_text: [{ - text: { - content: `${run.name}: ${run.status} (${run.conclusion || 'in progress'})` - } - }], - icon: { emoji: this.getGitHubActionEmoji(run.status, run.conclusion) }, - color: this.getGitHubActionColor(run.conclusion) as any - } - }; - } - - private getTaskEmoji(status: string): string { - const emojis: Record = { - 'pending': '⏳', - 'in_progress': '🔄', - 'completed': '✅', - 'failed': '❌', - 'blocked': '🚫' - }; - return emojis[status] || '📝'; - } - - private getPriorityLabel(priority: number): string { - if (priority >= 9) return 'Critical'; - if (priority >= 7) return 'High'; - if (priority >= 4) return 'Medium'; - return 'Low'; - } - - private getGitHubActionEmoji(status: string, conclusion?: string): string { - if (status === 'completed') { - const emojis: Record = { - 'success': '✅', - 'failure': '❌', - 'cancelled': '🚫', - 'skipped': '⏭️' - }; - return emojis[conclusion || ''] || '❓'; - } - return status === 'in_progress' ? '🔄' : '⏳'; - } - - private getGitHubActionColor(conclusion?: string): string { - const colors: Record = { - 'success': 'green_background', - 'failure': 'red_background', - 'cancelled': 'gray_background', - 'skipped': 'yellow_background' - }; - return colors[conclusion || ''] || 'default'; - } -} - -export async function setupNotionIntegration(): Promise { - const manager = new NotionSyncManager({ - notionToken: process.env.NOTION_TOKEN!, - mainDatabaseId: process.env.NOTION_MAIN_DB!, - sessionsDatabaseId: process.env.NOTION_SESSIONS_DB!, - tasksDatabaseId: process.env.NOTION_TASKS_DB! - }); - - const dashboardId = await manager.createCoordinationDashboard(); - console.log(`Notion dashboard created: https://notion.so/${dashboardId.replace(/-/g, '')}`); - - return manager; -} \ No newline at end of file diff --git a/src/cross-session-sync/notion-integration/notion-sync.ts b/src/cross-session-sync/notion-integration/notion-sync.ts deleted file mode 100644 index f847ee1..0000000 --- a/src/cross-session-sync/notion-integration/notion-sync.ts +++ /dev/null @@ -1,553 +0,0 @@ -import { Client } from '@notionhq/client'; -import { PageObjectResponse, DatabaseObjectResponse } from '@notionhq/client/build/src/api-endpoints'; - -interface SessionData { - id: string; - name: string; - status: string; - githubBranch?: string; - githubPR?: number; - tasks: string[]; - lastHeartbeat: number; -} - -interface TaskData { - id: string; - name: string; - status: string; - sessionId?: string; - priority: number; - dependencies: string[]; - githubIssue?: number; -} - -export class NotionSyncManager { - private notion: Client; - private databaseId: string; - private sessionsDatabase: string; - private tasksDatabase: string; - - constructor(config: { - notionToken: string; - mainDatabaseId: string; - sessionsDatabaseId: string; - tasksDatabaseId: string; - }) { - this.notion = new Client({ auth: config.notionToken }); - this.databaseId = config.mainDatabaseId; - this.sessionsDatabase = config.sessionsDatabaseId; - this.tasksDatabase = config.tasksDatabaseId; - } - - async createSessionDashboard(session: SessionData): Promise { - const page = await this.notion.pages.create({ - parent: { database_id: this.sessionsDatabase }, - icon: { - type: 'emoji', - emoji: session.status === 'active' ? '🟢' : '🔴' - }, - properties: { - 'Name': { - title: [{ - text: { content: session.name } - }] - }, - 'Session ID': { - rich_text: [{ - text: { content: session.id } - }] - }, - 'Status': { - select: { - name: session.status - } - }, - 'GitHub Branch': { - rich_text: session.githubBranch ? [{ - text: { content: session.githubBranch } - }] : [] - }, - 'GitHub PR': { - number: session.githubPR || null - }, - 'Last Heartbeat': { - date: { - start: new Date(session.lastHeartbeat).toISOString() - } - }, - 'Active Tasks': { - number: session.tasks.length - } - }, - children: [ - { - object: 'block', - type: 'heading_1', - heading_1: { - rich_text: [{ - text: { content: `Session: ${session.name}` } - }] - } - }, - { - object: 'block', - type: 'divider', - divider: {} - }, - { - object: 'block', - type: 'heading_2', - heading_2: { - rich_text: [{ - text: { content: '📊 Real-Time Metrics' } - }] - } - }, - { - object: 'block', - type: 'synced_block', - synced_block: { - synced_from: null, - children: [ - { - object: 'block', - type: 'callout', - callout: { - rich_text: [{ - text: { content: 'Session metrics will be updated in real-time' } - }], - icon: { emoji: '📈' } - } - } - ] - } - }, - { - object: 'block', - type: 'heading_2', - heading_2: { - rich_text: [{ - text: { content: '🔄 GitHub Integration' } - }] - } - }, - { - object: 'block', - type: 'embed', - embed: { - url: session.githubBranch - ? `https://github.com/${process.env.GITHUB_REPO}/tree/${session.githubBranch}` - : 'https://github.com' - } - }, - { - object: 'block', - type: 'heading_2', - heading_2: { - rich_text: [{ - text: { content: '📝 Active Tasks' } - }] - } - }, - { - object: 'block', - type: 'child_database', - child_database: { - title: 'Session Tasks' - } - } - ] - }); - - return page.id; - } - - async updateSessionStatus( - pageId: string, - session: Partial - ): Promise { - const updates: any = {}; - - if (session.status !== undefined) { - updates['Status'] = { - select: { name: session.status } - }; - } - - if (session.lastHeartbeat !== undefined) { - updates['Last Heartbeat'] = { - date: { - start: new Date(session.lastHeartbeat).toISOString() - } - }; - } - - if (session.tasks !== undefined) { - updates['Active Tasks'] = { - number: session.tasks.length - }; - } - - await this.notion.pages.update({ - page_id: pageId, - properties: updates, - icon: { - type: 'emoji', - emoji: session.status === 'active' ? '🟢' : '🔴' - } - }); - } - - async createTaskCard(task: TaskData): Promise { - const page = await this.notion.pages.create({ - parent: { database_id: this.tasksDatabase }, - icon: { - type: 'emoji', - emoji: this.getTaskEmoji(task.status) - }, - properties: { - 'Title': { - title: [{ - text: { content: task.name } - }] - }, - 'Task ID': { - rich_text: [{ - text: { content: task.id } - }] - }, - 'Status': { - select: { - name: task.status - } - }, - 'Priority': { - select: { - name: this.getPriorityLabel(task.priority) - } - }, - 'Assigned Session': { - rich_text: task.sessionId ? [{ - text: { content: task.sessionId } - }] : [] - }, - 'GitHub Issue': { - number: task.githubIssue || null - }, - 'Dependencies': { - multi_select: task.dependencies.map(dep => ({ name: dep })) - } - } - }); - - return page.id; - } - - async createCoordinationDashboard(): Promise { - const page = await this.notion.pages.create({ - parent: { database_id: this.databaseId }, - icon: { type: 'emoji', emoji: '🎯' }, - cover: { - type: 'external', - external: { - url: 'https://images.unsplash.com/photo-1542744173-8e7e53415bb0' - } - }, - properties: { - 'Title': { - title: [{ - text: { content: 'Cross-Session Coordination Dashboard' } - }] - }, - 'Type': { - select: { name: 'Dashboard' } - }, - 'Created': { - date: { - start: new Date().toISOString() - } - } - }, - children: [ - { - object: 'block', - type: 'heading_1', - heading_1: { - rich_text: [{ - text: { - content: '🚀 Cross-Session Coordination Center', - annotations: { bold: true } - } - }] - } - }, - { - object: 'block', - type: 'callout', - callout: { - rich_text: [{ - text: { - content: 'Real-time coordination between multiple Claude sessions with GitHub, Neon, and Cloudflare integration' - } - }], - icon: { emoji: '💡' }, - color: 'blue_background' - } - }, - { - object: 'block', - type: 'divider', - divider: {} - }, - { - object: 'block', - type: 'heading_2', - heading_2: { - rich_text: [{ - text: { content: '📊 Active Sessions' } - }] - } - }, - { - object: 'block', - type: 'child_database', - child_database: { - title: 'Active Sessions' - } - }, - { - object: 'block', - type: 'heading_2', - heading_2: { - rich_text: [{ - text: { content: '📋 Task Queue' } - }] - } - }, - { - object: 'block', - type: 'child_database', - child_database: { - title: 'Global Task Queue' - } - }, - { - object: 'block', - type: 'heading_2', - heading_2: { - rich_text: [{ - text: { content: '🔄 GitHub Activity' } - }] - } - }, - { - object: 'block', - type: 'synced_block', - synced_block: { - synced_from: null, - children: [ - { - object: 'block', - type: 'embed', - embed: { - url: `https://github.com/${process.env.GITHUB_REPO}/pulse` - } - } - ] - } - }, - { - object: 'block', - type: 'heading_2', - heading_2: { - rich_text: [{ - text: { content: '🗄️ Neon Database Status' } - }] - } - }, - { - object: 'block', - type: 'code', - code: { - rich_text: [{ - text: { content: 'SELECT * FROM sessions WHERE status = \'active\';' } - }], - language: 'sql' - } - }, - { - object: 'block', - type: 'heading_2', - heading_2: { - rich_text: [{ - text: { content: '⚡ Cloudflare Workers Status' } - }] - } - }, - { - object: 'block', - type: 'table', - table: { - table_width: 3, - has_column_header: true, - has_row_header: false, - children: [ - { - object: 'block', - type: 'table_row', - table_row: { - cells: [ - [{ text: { content: 'Worker' } }], - [{ text: { content: 'Status' } }], - [{ text: { content: 'Last Update' } }] - ] - } - }, - { - object: 'block', - type: 'table_row', - table_row: { - cells: [ - [{ text: { content: 'cross-session-sync' } }], - [{ text: { content: '✅ Active' } }], - [{ text: { content: new Date().toISOString() } }] - ] - } - } - ] - } - } - ] - }); - - return page.id; - } - - async syncWithNeonDatabase(neonClient: any): Promise { - const sessions = await neonClient.query('SELECT * FROM sessions WHERE status = $1', ['active']); - - for (const session of sessions.rows) { - const notionSession = await this.findSessionByID(session.id); - - if (notionSession) { - await this.updateSessionStatus(notionSession.id, { - status: session.status, - lastHeartbeat: session.last_heartbeat, - tasks: session.tasks - }); - } else { - const pageId = await this.createSessionDashboard({ - id: session.id, - name: session.session_name, - status: session.status, - githubBranch: session.github_branch, - githubPR: session.github_pr_number, - tasks: session.tasks, - lastHeartbeat: session.last_heartbeat - }); - - await neonClient.query( - 'UPDATE sessions SET notion_page_id = $1 WHERE id = $2', - [pageId, session.id] - ); - } - } - } - - async syncGitHubActions(githubOctokit: any): Promise { - const { data: runs } = await githubOctokit.actions.listWorkflowRunsForRepo({ - owner: process.env.GITHUB_OWNER, - repo: process.env.GITHUB_REPO, - per_page: 10 - }); - - for (const run of runs.workflow_runs) { - await this.updateGitHubActionStatus(run); - } - } - - private async findSessionByID(sessionId: string): Promise { - const response = await this.notion.databases.query({ - database_id: this.sessionsDatabase, - filter: { - property: 'Session ID', - rich_text: { - equals: sessionId - } - } - }); - - return response.results[0] as PageObjectResponse || null; - } - - private async updateGitHubActionStatus(run: any): Promise { - const block = { - object: 'block' as const, - type: 'callout' as const, - callout: { - rich_text: [{ - text: { - content: `${run.name}: ${run.status} (${run.conclusion || 'in progress'})` - } - }], - icon: { emoji: this.getGitHubActionEmoji(run.status, run.conclusion) }, - color: this.getGitHubActionColor(run.conclusion) as any - } - }; - } - - private getTaskEmoji(status: string): string { - const emojis: Record = { - 'pending': '⏳', - 'in_progress': '🔄', - 'completed': '✅', - 'failed': '❌', - 'blocked': '🚫' - }; - return emojis[status] || '📝'; - } - - private getPriorityLabel(priority: number): string { - if (priority >= 9) return 'Critical'; - if (priority >= 7) return 'High'; - if (priority >= 4) return 'Medium'; - return 'Low'; - } - - private getGitHubActionEmoji(status: string, conclusion?: string): string { - if (status === 'completed') { - const emojis: Record = { - 'success': '✅', - 'failure': '❌', - 'cancelled': '🚫', - 'skipped': '⏭️' - }; - return emojis[conclusion || ''] || '❓'; - } - return status === 'in_progress' ? '🔄' : '⏳'; - } - - private getGitHubActionColor(conclusion?: string): string { - const colors: Record = { - 'success': 'green_background', - 'failure': 'red_background', - 'cancelled': 'gray_background', - 'skipped': 'yellow_background' - }; - return colors[conclusion || ''] || 'default'; - } -} - -export async function setupNotionIntegration(): Promise { - const manager = new NotionSyncManager({ - notionToken: process.env.NOTION_TOKEN!, - mainDatabaseId: process.env.NOTION_MAIN_DB!, - sessionsDatabaseId: process.env.NOTION_SESSIONS_DB!, - tasksDatabaseId: process.env.NOTION_TASKS_DB! - }); - - const dashboardId = await manager.createCoordinationDashboard(); - console.log(`Notion dashboard created: https://notion.so/${dashboardId.replace(/-/g, '')}`); - - return manager; -} \ No newline at end of file From 9acf41beb257179ec95865f5eb4f650cfb29335c Mon Sep 17 00:00:00 2001 From: Migration Agent Date: Wed, 29 Jul 2026 22:31:11 +0000 Subject: [PATCH 2/2] ci: replace broken ecosystem-cicd with working lint + deploy pipeline Remove 285-line fantasy workflow that: - referenced /Users/nb/ local Mac paths (never runs on GitHub runners) - used non-existent 'codex mcp --init' / 'codex review' CLI - tried to deploy 5 separate services from this repo's CI Replace with minimal working pipeline: - lint on all PRs and pushes - deploy:production (wrangler.optimized.toml) on push to main --- .github/workflows/ecosystem-cicd.yml | 282 ++------------------------- 1 file changed, 18 insertions(+), 264 deletions(-) diff --git a/.github/workflows/ecosystem-cicd.yml b/.github/workflows/ecosystem-cicd.yml index 538fb7a..bcbbd80 100644 --- a/.github/workflows/ecosystem-cicd.yml +++ b/.github/workflows/ecosystem-cicd.yml @@ -1,4 +1,4 @@ -name: ChittyOS Ecosystem CI/CD with Codex Review +name: CI/CD on: push: @@ -8,278 +8,32 @@ on: workflow_dispatch: env: - CHITTY_API_KEY: ${{ secrets.CHITTY_API_KEY }} CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} jobs: - # Phase 1: Codex Code Review - codex-review: + lint: + name: Lint runs-on: ubuntu-latest - name: Codex Code Review & Analysis - outputs: - review-status: ${{ steps.codex.outputs.status }} - security-score: ${{ steps.codex.outputs.security }} - steps: - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: - fetch-depth: 0 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '18' - cache: 'npm' - - - name: Install Dependencies & Lint - run: | - npm install - npm run lint || echo "Linting completed with warnings" - npm install -g @modelcontextprotocol/cli - - - name: Run Codex Security Analysis - id: codex - run: | - echo "Starting Codex security analysis..." - - # Initialize Codex MCP server - codex mcp --init - - # Run comprehensive code review - codex review \ - --security \ - --performance \ - --architecture \ - --chittyid-compliance \ - --output-format json > codex-review.json - - # Extract security score - SECURITY_SCORE=$(jq -r '.security.score' codex-review.json) - echo "security=$SECURITY_SCORE" >> $GITHUB_OUTPUT - - # Check if review passes - if [ "$SECURITY_SCORE" -ge 85 ]; then - echo "status=passed" >> $GITHUB_OUTPUT - echo "✅ Codex review passed with score: $SECURITY_SCORE" - else - echo "status=failed" >> $GITHUB_OUTPUT - echo "❌ Codex review failed with score: $SECURITY_SCORE" - exit 1 - fi - - - name: Upload Codex Report - uses: actions/upload-artifact@v4 - with: - name: codex-review-report - path: codex-review.json - - - name: Comment PR with Codex Results - if: github.event_name == 'pull_request' - uses: actions/github-script@v7 - with: - script: | - const fs = require('fs'); - const review = JSON.parse(fs.readFileSync('codex-review.json', 'utf8')); - - const comment = `## 🤖 Codex Review Results - - **Security Score**: ${review.security.score}/100 - **Performance Score**: ${review.performance.score}/100 - **Architecture Score**: ${review.architecture.score}/100 - **ChittyID Compliance**: ${review.chittyid.compliant ? '✅ Compliant' : '❌ Non-compliant'} - - ### Key Findings: - ${review.findings.map(f => `- ${f.severity}: ${f.message}`).join('\n')} - - ### Recommendations: - ${review.recommendations.map(r => `- ${r}`).join('\n')} - `; - - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: comment - }); - - # Phase 2: ChittyOS Ecosystem Validation - ecosystem-validation: - runs-on: ubuntu-latest - name: ChittyOS Ecosystem Validation - needs: codex-review - if: needs.codex-review.outputs.review-status == 'passed' - - steps: - - uses: actions/checkout@v4 - - - name: ChittyID Compliance Check - run: | - echo "Running ChittyID compliance validation..." - ./chittycheck-enhanced.sh --ci-mode - - # Ensure no local ID generation (exclude submodules and build artifacts) - if grep -r "CHITTY-.*-.*-.*" . \ - --exclude-dir=node_modules \ - --exclude-dir=.git \ - --exclude-dir=chittychronicle \ - --exclude-dir=chittychain \ - --exclude-dir=chittyforce \ - --exclude-dir=nevershitty-github \ - --exclude-dir=dist \ - --exclude-dir=build \ - --exclude="*.json" \ - --exclude="*.md"; then - echo "❌ Found hardcoded ChittyIDs in source code - all IDs must come from id.chitty.cc" - exit 1 - fi - - - name: Cross-Service Integration Test - run: | - echo "Testing cross-service integration..." - - # Test ChittyMCP connectivity - curl -f https://mcp.chitty.cc/health || echo "ChittyMCP not yet deployed" - - # Test service registry - curl -f https://registry.chitty.cc/health || echo "Registry not yet deployed" - - # Test gateway - curl -f https://gateway.chitty.cc/health || echo "Gateway not yet deployed" - - - name: Evidence Chain Validation - run: | - echo "Validating evidence chain integrity..." - node -e " - const fs = require('fs'); - const crypto = require('crypto'); - - // Validate evidence files have proper ChittyID linking - const evidenceFiles = fs.readdirSync('.', {recursive: true}) - .filter(f => f.includes('evidence') && f.endsWith('.json')); - - for (const file of evidenceFiles) { - const evidence = JSON.parse(fs.readFileSync(file)); - if (!evidence.chittyId || !evidence.chittyId.startsWith('CHITTY-')) { - console.error('Invalid evidence file:', file); - process.exit(1); - } - } - console.log('✅ Evidence chain validated'); - " - - # Phase 3: Multi-Service Deployment - deploy-ecosystem: + node-version: '20' + cache: npm + - run: npm ci + - run: npm run lint + + deploy: + name: Deploy to Cloudflare + needs: lint + if: github.ref == 'refs/heads/main' && github.event_name == 'push' runs-on: ubuntu-latest - name: Deploy ChittyOS Ecosystem - needs: [codex-review, ecosystem-validation] - if: needs.codex-review.outputs.review-status == 'passed' - strategy: - matrix: - service: - - chittychat - - chittymcp - - chittyrouter - - chittyschema - - chittyregistry - steps: - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 + - uses: actions/setup-node@v4 with: - node-version: '18' - - - name: Deploy ${{ matrix.service }} - run: | - SERVICE_DIR="/Users/nb/.claude/projects/-/${{ matrix.service }}" - - if [ -d "$SERVICE_DIR" ]; then - echo "Deploying ${{ matrix.service }}..." - cd "$SERVICE_DIR" - - # Install dependencies if package.json exists - if [ -f "package.json" ]; then - npm ci - fi - - # Run service-specific deployment - if [ -f "wrangler.toml" ]; then - npx wrangler deploy --env production - elif [ -f "deploy.sh" ]; then - chmod +x deploy.sh && ./deploy.sh - else - echo "No deployment configuration found for ${{ matrix.service }}" - fi - else - echo "Service directory not found: ${{ matrix.service }}" - fi - - # Phase 4: Integration Smoke Tests - smoke-tests: - runs-on: ubuntu-latest - name: Ecosystem Smoke Tests - needs: deploy-ecosystem - - steps: - - name: Test ChittyOS Services - run: | - echo "Running ecosystem smoke tests..." - - # Test core services - SERVICES=( - "https://gateway.chitty.cc/health" - "https://mcp.chitty.cc/health" - "https://id.chitty.cc/health" - "https://registry.chitty.cc/health" - "https://schema.chitty.cc/health" - ) - - for service in "${SERVICES[@]}"; do - echo "Testing $service..." - if curl -f "$service" --max-time 30; then - echo "✅ $service is healthy" - else - echo "❌ $service failed health check" - # Don't fail immediately - collect all results - fi - done - - - name: Test ChittyID Integration - run: | - echo "Testing ChittyID service integration..." - - # Test ID minting - CHITTY_ID=$(curl -X POST https://id.chitty.cc/v1/mint \ - -H "Authorization: Bearer $CHITTY_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"entity_type": "EVNT"}' \ - --max-time 30 | jq -r '.chittyId') - - if [[ "$CHITTY_ID" =~ ^CHITTY-EVNT-.* ]]; then - echo "✅ ChittyID minting successful: $CHITTY_ID" - else - echo "❌ ChittyID minting failed" - exit 1 - fi - - - name: Final Status Report - run: | - echo "🎯 ChittyOS Ecosystem Deployment Complete!" - echo "✅ Codex Review: Passed (Score: ${{ needs.codex-review.outputs.security-score }})" - echo "✅ Ecosystem Validation: Passed" - echo "✅ Multi-Service Deployment: Completed" - echo "✅ Smoke Tests: All services operational" - - # Update deployment status - curl -X POST https://registry.chitty.cc/api/deployments \ - -H "Authorization: Bearer $CHITTY_API_KEY" \ - -H "Content-Type: application/json" \ - -d "{ - \"deployment_id\": \"$GITHUB_RUN_ID\", - \"status\": \"completed\", - \"services\": [\"chittychat\", \"chittymcp\", \"chittyrouter\", \"chittyschema\", \"chittyregistry\"], - \"codex_score\": ${{ needs.codex-review.outputs.security-score }}, - \"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\" - }" || echo "Registry update failed (non-critical)" \ No newline at end of file + node-version: '20' + cache: npm + - run: npm ci + - run: npm run deploy:production \ No newline at end of file