UNPKG

aios-core

Version:

Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework

176 lines (154 loc) 4.78 kB
/** * @fileoverview Local PM Adapter (Standalone Mode) * * No-op adapter for standalone AIOS operation without external PM tool. * All story management happens via local YAML files and git. * * This adapter enables 100% AIOS functionality without requiring * ClickUp, Jira, GitHub Projects, or any other PM tool. * * @see Story 3.20 - PM Tool-Agnostic Integration (TR-3.20.5) */ const fs = require('fs'); const path = require('path'); const yaml = require('js-yaml'); const { PMAdapter } = require('../../scripts/pm-adapter'); /** * Local adapter - standalone mode with no external PM tool * * All operations return success without making external API calls. * Story management happens entirely via local YAML files and git versioning. */ class LocalAdapter extends PMAdapter { /** * Create Local adapter instance * @param {object} [config={}] - Config (not required for local adapter) */ constructor(config = {}) { super(config); } /** * Sync local story (no-op - story already local) * * In local mode, the YAML file IS the source of truth. * No external sync needed. * * @param {string} storyPath - Path to story YAML file * @returns {Promise<{success: boolean, url?: string, error?: string}>} */ async syncStory(storyPath) { try { // Verify file exists if (!fs.existsSync(storyPath)) { return { success: false, error: `Story file not found: ${storyPath}`, }; } // Read story and extract frontmatter (YAML between first --- and second ---) const storyContent = fs.readFileSync(storyPath, 'utf8'); const frontmatterMatch = storyContent.match(/^---\r?\n([\s\S]*?)\r?\n---/); if (!frontmatterMatch) { return { success: false, error: 'Invalid story file: missing YAML frontmatter', }; } const story = yaml.load(frontmatterMatch[1]); if (!story || !story.id) { return { success: false, error: 'Invalid story file: missing id field in frontmatter', }; } console.log(`✅ Story ${story.id} managed locally (no PM tool configured)`); // Return success - file path is the "URL" return { success: true, url: `file://${path.resolve(storyPath)}`, }; } catch (error) { console.error('❌ Error validating local story:', error); return { success: false, error: error.message, }; } } /** * Pull story updates (no-op - local file is source of truth) * * In local mode, there's no external source to pull from. * The local YAML file is always the most current version. * * @param {string} storyId - Story ID (e.g., "3.20") * @returns {Promise<{success: boolean, updates?: object, error?: string}>} */ async pullStory(storyId) { console.log(`ℹ️ Local-only mode: Story ${storyId} file is source of truth`); return { success: true, updates: null, // No updates from external source }; } /** * Create new story (local YAML file creation) * * In local mode, "creating" a story means the YAML file was created. * This method just validates that the file exists. * * @param {object} storyData - Story metadata * @returns {Promise<{success: boolean, url?: string, error?: string}>} */ async createStory(storyData) { if (!storyData || !storyData.id) { return { success: false, error: 'Story data missing required field: id', }; } console.log(`✅ Story ${storyData.id} created locally`); return { success: true, url: null, // No external URL in local mode }; } /** * Update story status (local YAML update) * * In local mode, status is updated directly in the YAML file. * This method just acknowledges the update. * * @param {string} storyId - Story ID * @param {string} status - New status * @returns {Promise<{success: boolean, error?: string}>} */ async updateStatus(storyId, status) { console.log(`✅ Story ${storyId} status updated to ${status} (local)`); return { success: true, }; } /** * Test connection (always succeeds - no connection needed) * * Local adapter doesn't require any external connections. * Always returns success. * * @returns {Promise<{success: boolean, error?: string}>} */ async testConnection() { console.log('✅ Local-only mode: No PM tool connection needed'); return { success: true, }; } /** * Get adapter name * @returns {string} "Local" (overrides base class to return cleaner name) */ getName() { return 'Local'; } } module.exports = { LocalAdapter };