import { ref, computed, shallowRef } from 'vue' export interface ProjectInfo { name: string path: string isGit: boolean language?: string } export interface FileEntry { name: string path: string isDirectory: boolean children?: FileEntry[] } // Module-level singleton state const codeMode = ref(false) const activeProject = ref(null) const projectList = shallowRef([]) const fileTree = shallowRef([]) const activeFile = ref(null) const activeFileContent = ref('') const activeFileLanguage = ref('plaintext') // Demo projects path const PROJECTS_ROOT = '/Users/dorian/Projects' function detectLanguage(filename: string): string { const ext = filename.split('.').pop()?.toLowerCase() ?? '' const map: Record = { ts: 'typescript', tsx: 'typescript', js: 'javascript', jsx: 'javascript', vue: 'vue', svelte: 'svelte', py: 'python', rs: 'rust', go: 'go', java: 'java', kt: 'kotlin', swift: 'swift', rb: 'ruby', php: 'php', css: 'css', scss: 'scss', html: 'html', json: 'json', yaml: 'yaml', yml: 'yaml', md: 'markdown', toml: 'toml', sh: 'shell', bash: 'shell', sql: 'sql', graphql: 'graphql', dockerfile: 'dockerfile', c: 'c', cpp: 'cpp', h: 'c', hpp: 'cpp', cs: 'csharp', } return map[ext] ?? 'plaintext' } function detectProjectLanguage(files: string[]): string { if (files.includes('package.json')) return 'TypeScript/JavaScript' if (files.includes('Cargo.toml')) return 'Rust' if (files.includes('go.mod')) return 'Go' if (files.includes('requirements.txt') || files.includes('setup.py') || files.includes('pyproject.toml')) return 'Python' if (files.includes('pom.xml') || files.includes('build.gradle')) return 'Java' if (files.includes('Package.swift')) return 'Swift' if (files.includes('Gemfile')) return 'Ruby' if (files.includes('composer.json')) return 'PHP' if (files.some(f => f.endsWith('.csproj') || f.endsWith('.sln'))) return 'C#' return 'Unknown' } export function useCodeContext() { const isCodeMode = computed(() => codeMode.value) const hasActiveProject = computed(() => activeProject.value !== null) async function loadProjects(): Promise { // In dev/demo mode, scan the Projects folder // This would be replaced by Archy integration later try { const response = await fetch(`/api/fs/list?path=${encodeURIComponent(PROJECTS_ROOT)}`) if (response.ok) { const data = await response.json() projectList.value = data.projects ?? [] } } catch { // Fallback: use hardcoded list from build time // In real app, this would come from local filesystem or Archy nodes projectList.value = getDemoProjects() } } function getDemoProjects(): ProjectInfo[] { // Hardcoded demo list matching actual ~/Projects folder return [ { name: 'AIUI', path: `${PROJECTS_ROOT}/AIUI`, isGit: true, language: 'TypeScript/JavaScript' }, { name: 'archy', path: `${PROJECTS_ROOT}/archy`, isGit: true, language: 'TypeScript/JavaScript' }, { name: 'angor', path: `${PROJECTS_ROOT}/angor`, isGit: true, language: 'C#' }, { name: 'angor-prototype', path: `${PROJECTS_ROOT}/angor-prototype`, isGit: true, language: 'TypeScript/JavaScript' }, { name: 'archipelago', path: `${PROJECTS_ROOT}/archipelago`, isGit: true, language: 'Unknown' }, { name: 'archipelago-foundation', path: `${PROJECTS_ROOT}/archipelago-foundation`, isGit: true, language: 'Unknown' }, { name: 'blossom', path: `${PROJECTS_ROOT}/blossom`, isGit: true, language: 'TypeScript/JavaScript' }, { name: 'fedimint', path: `${PROJECTS_ROOT}/fedimint`, isGit: true, language: 'Rust' }, { name: 'Syntopy', path: `${PROJECTS_ROOT}/Syntopy`, isGit: true, language: 'Unknown' }, { name: 'Syntropy-Institute', path: `${PROJECTS_ROOT}/Syntropy-Institute`, isGit: true, language: 'Unknown' }, { name: 'LoRaBell', path: `${PROJECTS_ROOT}/LoRaBell`, isGit: true, language: 'Unknown' }, { name: 'satoshi-services', path: `${PROJECTS_ROOT}/satoshi-services`, isGit: true, language: 'Unknown' }, { name: 'Proux', path: `${PROJECTS_ROOT}/Proux`, isGit: true, language: 'Unknown' }, { name: 'KYC', path: `${PROJECTS_ROOT}/KYC`, isGit: true, language: 'Unknown' }, { name: 'k484', path: `${PROJECTS_ROOT}/k484`, isGit: true, language: 'Unknown' }, { name: 'tbf', path: `${PROJECTS_ROOT}/tbf`, isGit: true, language: 'Unknown' }, { name: 'Icon', path: `${PROJECTS_ROOT}/Icon`, isGit: false, language: 'Unknown' }, { name: 'indeehub-frontend', path: `${PROJECTS_ROOT}/indeehub-frontend`, isGit: true, language: 'TypeScript/JavaScript' }, { name: 'Indeedhub Prototype', path: `${PROJECTS_ROOT}/Indeedhub Prototype`, isGit: true, language: 'Unknown' }, { name: '21', path: `${PROJECTS_ROOT}/21`, isGit: true, language: 'Unknown' }, ] } function enterCodeMode(): void { codeMode.value = true loadProjects() } function exitCodeMode(): void { codeMode.value = false activeProject.value = null activeFile.value = null activeFileContent.value = '' fileTree.value = [] } function selectProject(project: ProjectInfo): void { activeProject.value = project loadFileTree(project.path) } async function loadFileTree(projectPath: string): Promise { try { const response = await fetch(`/api/fs/tree?path=${encodeURIComponent(projectPath)}`) if (response.ok) { const data = await response.json() fileTree.value = data.files ?? [] } } catch { // Demo fallback: generate a simple tree fileTree.value = getDemoFileTree() } } function getDemoFileTree(): FileEntry[] { // Generic project structure for demo return [ { name: 'src', path: 'src', isDirectory: true, children: [ { name: 'index.ts', path: 'src/index.ts', isDirectory: false }, { name: 'app.ts', path: 'src/app.ts', isDirectory: false }, { name: 'utils.ts', path: 'src/utils.ts', isDirectory: false }, ]}, { name: 'package.json', path: 'package.json', isDirectory: false }, { name: 'tsconfig.json', path: 'tsconfig.json', isDirectory: false }, { name: 'README.md', path: 'README.md', isDirectory: false }, ] } async function openFile(filePath: string): Promise { activeFile.value = filePath activeFileLanguage.value = detectLanguage(filePath) try { const fullPath = activeProject.value ? `${activeProject.value.path}/${filePath}` : filePath const response = await fetch(`/api/fs/read?path=${encodeURIComponent(fullPath)}`) if (response.ok) { const data = await response.json() activeFileContent.value = data.content ?? '' } } catch { // Demo fallback activeFileContent.value = getDemoFileContent(filePath) } } function getDemoFileContent(filePath: string): string { const name = filePath.split('/').pop() ?? filePath if (name === 'package.json') { return JSON.stringify({ name: activeProject.value?.name?.toLowerCase() ?? 'project', version: '1.0.0', type: 'module', scripts: { dev: 'vite', build: 'vite build', test: 'vitest' }, dependencies: {}, }, null, 2) } if (name === 'README.md') { return `# ${activeProject.value?.name ?? 'Project'}\n\nA project in the AIUI ecosystem.\n` } if (name.endsWith('.ts') || name.endsWith('.js')) { return `// ${name}\n// ${activeProject.value?.name ?? 'Project'}\n\nexport function main() {\n console.log('Hello from ${name}')\n}\n` } return `// ${name}\n` } return { // State codeMode, isCodeMode, activeProject, hasActiveProject, projectList, fileTree, activeFile, activeFileContent, activeFileLanguage, // Actions enterCodeMode, exitCodeMode, selectProject, openFile, loadProjects, detectLanguage, } }