├── pkg └── .gitkeep ├── internal ├── db │ ├── .gitkeep │ ├── models.go │ ├── queries.sql │ ├── db.go │ ├── init.go │ └── queries.sql.go ├── ai │ ├── context │ │ └── .gitkeep │ ├── llm │ │ └── .gitkeep │ └── vector │ │ └── .gitkeep ├── editor │ ├── git │ │ └── .gitkeep │ └── parser │ │ └── .gitkeep ├── server │ └── .gitkeep ├── terminal │ ├── types.go │ ├── events.go │ └── terminal.go ├── command │ ├── root.go │ └── db.go └── service │ ├── projects.go │ ├── config.go │ └── terminal.go ├── frontend ├── .gitignore ├── src │ ├── lib │ │ ├── terminal │ │ │ └── types.ts │ │ ├── components │ │ │ ├── KeyboardManager.svelte │ │ │ ├── palletes │ │ │ │ ├── components │ │ │ │ │ ├── ResultsList.svelte │ │ │ │ │ ├── CommandItem.svelte │ │ │ │ │ ├── FileItem.svelte │ │ │ │ │ └── BasePalette.svelte │ │ │ │ ├── CommandPalette.svelte │ │ │ │ └── BranchPalette.svelte │ │ │ ├── DropdownMenu.svelte │ │ │ ├── Select.svelte │ │ │ ├── Button.svelte │ │ │ ├── Snow.svelte │ │ │ ├── Tooltip.svelte │ │ │ ├── Modal.svelte │ │ │ ├── ContextMenu.svelte │ │ │ ├── Input.svelte │ │ │ ├── ResizeHandle.svelte │ │ │ └── RecentProjects.svelte │ │ ├── editor │ │ │ ├── git │ │ │ │ ├── changes │ │ │ │ │ ├── GitDiffViewer.svelte │ │ │ │ │ ├── GitDiffHeader.svelte │ │ │ │ │ ├── GitChangesView.svelte │ │ │ │ │ └── DiffHeader.svelte │ │ │ │ ├── GitRepositoryStatus.svelte │ │ │ │ ├── GitStagedChanges.svelte │ │ │ │ ├── GitCommitItem.svelte │ │ │ │ ├── GitCommitSection.svelte │ │ │ │ ├── GitUnstagedChanges.svelte │ │ │ │ └── GitStatusItem.svelte │ │ │ ├── LeftSidebar.svelte │ │ │ ├── Breadcrumbs.svelte │ │ │ ├── panes │ │ │ │ ├── ExplorerPane.svelte │ │ │ │ ├── BottomPane.svelte │ │ │ │ └── GitPane.svelte │ │ │ ├── BottomBar.svelte │ │ │ ├── Topbar.svelte │ │ │ ├── RightSidebar.svelte │ │ │ └── explorer │ │ │ │ └── FileTree.svelte │ │ ├── wailsjs │ │ │ ├── runtime │ │ │ │ ├── package.json │ │ │ │ └── runtime.js │ │ │ └── go │ │ │ │ └── main │ │ │ │ ├── App.d.ts │ │ │ │ └── App.js │ │ ├── utils │ │ │ ├── time.ts │ │ │ ├── languageMap.ts │ │ │ ├── fuzzySearch.ts │ │ │ └── gitSort.ts │ │ └── actions │ │ │ └── tooltip.ts │ ├── routes │ │ ├── Configs.svelte │ │ └── Welcome.svelte │ ├── app.css │ ├── vite-env.d.ts │ ├── assets │ │ ├── images │ │ │ └── logo-universal.png │ │ └── fonts │ │ │ ├── nunito-v16-latin-regular.woff2 │ │ │ └── OFL.txt │ ├── main.js │ ├── types │ │ ├── index.ts │ │ ├── git.ts │ │ ├── ui.ts │ │ ├── keyboard.ts │ │ └── files.ts │ ├── stores │ │ ├── bottomPaneStore.ts │ │ ├── editorSessionStore.ts │ │ ├── editorInstanceStore.ts │ │ ├── commandStore.ts │ │ ├── editorConfigStore.ts │ │ ├── focusStore.ts │ │ ├── terminalStore.ts │ │ ├── editorStateStore.ts │ │ └── project.ts │ └── App.svelte ├── package.json.md5 ├── .vscode │ └── extensions.json ├── postcss.config.js ├── svelte.config.js ├── tailwind.config.js ├── tsconfig.node.json ├── index.html ├── tsconfig.json ├── vite.config.js ├── package.json └── README.md ├── .github ├── FUNDING.yml └── workflows │ └── editai-release.yaml ├── db └── migrations │ ├── embed.go │ └── 0001_initial_schema.sql ├── sqlc.yaml ├── cmd ├── edit4i │ └── main.go └── server │ └── main.go ├── example.env ├── docker-compose.yaml ├── .gitignore ├── wails.json ├── main.go ├── Makefile ├── examples ├── tools │ └── web_scraper.yaml └── .editai │ ├── knowledge │ └── codestyle │ │ └── javascript.yaml │ ├── workflows │ └── code-review.yaml │ └── config.yaml ├── .docker └── wails │ └── Dockerfile ├── go.mod └── README.md /pkg/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /internal/db/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | tmp/* -------------------------------------------------------------------------------- /internal/ai/context/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /internal/ai/llm/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /internal/ai/vector/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /internal/editor/git/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /internal/server/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /internal/editor/parser/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/lib/terminal/types.ts: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [nathabonfim59] 2 | -------------------------------------------------------------------------------- /frontend/src/routes/Configs.svelte: -------------------------------------------------------------------------------- 1 |

Configs

-------------------------------------------------------------------------------- /frontend/package.json.md5: -------------------------------------------------------------------------------- 1 | 2be276b66fa69ca283f64ddc7d9337aa -------------------------------------------------------------------------------- /frontend/src/app.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | html { 6 | } -------------------------------------------------------------------------------- /frontend/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /frontend/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "svelte.svelte-vscode" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /db/migrations/embed.go: -------------------------------------------------------------------------------- 1 | package migrations 2 | 3 | import "embed" 4 | 5 | //go:embed *.sql 6 | var FS embed.FS 7 | -------------------------------------------------------------------------------- /frontend/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/assets/images/logo-universal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edit4i/editor/HEAD/frontend/src/assets/images/logo-universal.png -------------------------------------------------------------------------------- /frontend/src/assets/fonts/nunito-v16-latin-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edit4i/editor/HEAD/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 -------------------------------------------------------------------------------- /frontend/svelte.config.js: -------------------------------------------------------------------------------- 1 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; 2 | 3 | export default { 4 | preprocess: vitePreprocess() 5 | }; 6 | -------------------------------------------------------------------------------- /frontend/src/main.js: -------------------------------------------------------------------------------- 1 | import App from './App.svelte' 2 | 3 | const app = new App({ 4 | target: document.getElementById('app') 5 | }) 6 | 7 | export default app 8 | -------------------------------------------------------------------------------- /frontend/src/types/index.ts: -------------------------------------------------------------------------------- 1 | // Editor Types 2 | export * from './files'; 3 | export * from './git'; 4 | export * from './keyboard'; 5 | 6 | // UI Types 7 | export * from './ui'; -------------------------------------------------------------------------------- /frontend/src/types/git.ts: -------------------------------------------------------------------------------- 1 | export interface GitStatusItem { 2 | status: 'modified' | 'new' | 'deleted' | 'renamed'; 3 | file: string; 4 | oldFile?: string; 5 | staged: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /sqlc.yaml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | sql: 3 | - engine: sqlite 4 | queries: internal/db/queries.sql 5 | schema: db/migrations 6 | gen: 7 | go: 8 | package: db 9 | out: internal/db 10 | -------------------------------------------------------------------------------- /frontend/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: ['./src/**/*.{html,js,svelte,ts}'], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | } 9 | 10 | -------------------------------------------------------------------------------- /frontend/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/stores/bottomPaneStore.ts: -------------------------------------------------------------------------------- 1 | import { writable } from 'svelte/store'; 2 | 3 | // Store for bottom pane state 4 | export const bottomPaneStore = writable({ 5 | collapsed: false, 6 | activeSection: 'terminal', 7 | isAllCollapsed: false 8 | }); 9 | -------------------------------------------------------------------------------- /cmd/edit4i/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "os" 6 | 7 | "github.com/edit4i/editor/internal/command" 8 | ) 9 | 10 | func main() { 11 | if err := command.Execute(); err != nil { 12 | log.Printf("Error: %v\n", err) 13 | os.Exit(1) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /internal/terminal/types.go: -------------------------------------------------------------------------------- 1 | package terminal 2 | 3 | // TerminalOptions contains options for creating a new terminal 4 | type TerminalOptions struct { 5 | Shell string 6 | Cols int 7 | Rows int 8 | Cwd string // Working directory for the terminal 9 | } 10 | -------------------------------------------------------------------------------- /example.env: -------------------------------------------------------------------------------- 1 | # Server Configuration 2 | SERVER_PORT=8080 3 | SERVER_HOST=localhost 4 | 5 | # OpenAI Configuration 6 | OPENAI_API_KEY=your_api_key_here 7 | OPENAI_MODEL=gpt-4-1106-preview 8 | 9 | # Database Configuration 10 | LIBSQL_URL=file:local.db 11 | 12 | # Development Settings 13 | DEBUG=true 14 | -------------------------------------------------------------------------------- /frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | editai 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /internal/db/models.go: -------------------------------------------------------------------------------- 1 | // Code generated by sqlc. DO NOT EDIT. 2 | // versions: 3 | // sqlc v1.27.0 4 | 5 | package db 6 | 7 | import ( 8 | "database/sql" 9 | ) 10 | 11 | type Project struct { 12 | ID int64 13 | Name string 14 | Path string 15 | LastOpened sql.NullTime 16 | CreatedAt sql.NullTime 17 | UpdatedAt sql.NullTime 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/lib/components/KeyboardManager.svelte: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /internal/terminal/events.go: -------------------------------------------------------------------------------- 1 | package terminal 2 | 3 | // EventType represents the type of terminal event 4 | type EventType int 5 | 6 | const ( 7 | EventData EventType = iota 8 | EventResize 9 | EventCursor 10 | EventExit 11 | ) 12 | 13 | // Event represents a terminal event 14 | type Event struct { 15 | Type EventType 16 | Data []byte 17 | Cols int 18 | Rows int 19 | CursorX int 20 | CursorY int 21 | } 22 | -------------------------------------------------------------------------------- /internal/db/queries.sql: -------------------------------------------------------------------------------- 1 | -- name: GetProject :one 2 | SELECT * FROM projects 3 | WHERE path = ? LIMIT 1; 4 | 5 | -- name: CreateProject :one 6 | INSERT INTO projects (name, path) 7 | VALUES (?, ?) 8 | RETURNING *; 9 | 10 | -- name: UpdateProjectLastOpened :exec 11 | UPDATE projects 12 | SET last_opened = CURRENT_TIMESTAMP 13 | WHERE id = ?; 14 | 15 | -- name: ListRecentProjects :many 16 | SELECT * FROM projects 17 | ORDER BY last_opened DESC 18 | LIMIT ?; -------------------------------------------------------------------------------- /internal/command/root.go: -------------------------------------------------------------------------------- 1 | package command 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | ) 6 | 7 | var rootCmd = &cobra.Command{ 8 | Use: "edit4i", 9 | Short: "Edit4I - An AI-powered editor", 10 | Long: `Edit4I is an AI-powered editor that enhances your coding experience.`, 11 | } 12 | 13 | // Execute runs the root command 14 | func Execute() error { 15 | return rootCmd.Execute() 16 | } 17 | 18 | func init() { 19 | rootCmd.AddCommand(dbCmd) 20 | } 21 | -------------------------------------------------------------------------------- /db/migrations/0001_initial_schema.sql: -------------------------------------------------------------------------------- 1 | -- migrate:up 2 | 3 | CREATE TABLE projects ( 4 | id INTEGER PRIMARY KEY AUTOINCREMENT, 5 | name TEXT NOT NULL, 6 | path TEXT NOT NULL UNIQUE, 7 | last_opened DATETIME DEFAULT CURRENT_TIMESTAMP, 8 | created_at DATETIME DEFAULT CURRENT_TIMESTAMP, 9 | updated_at DATETIME DEFAULT CURRENT_TIMESTAMP 10 | ); 11 | 12 | CREATE INDEX idx_projects_path ON projects(path); 13 | 14 | -- migrate:down 15 | 16 | DROP TABLE projects; -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | editai-dev: 3 | build: 4 | context: . 5 | dockerfile: .docker/wails/Dockerfile 6 | container_name: editai-dev 7 | volumes: 8 | - .:/app 9 | - go-cache:/go 10 | - node-modules:/app/frontend/node_modules 11 | ports: 12 | - "3000:3000" 13 | environment: 14 | - GOOS=linux 15 | - GOARCH=amd64 16 | - CGO_ENABLED=1 17 | tty: true 18 | stdin_open: true 19 | 20 | volumes: 21 | go-cache: 22 | node-modules: 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | node_modules/ 3 | /frontend/node_modules/ 4 | 5 | # Build 6 | /build/ 7 | /frontend/dist/ 8 | /frontend/.svelte-kit/ 9 | 10 | # Environment 11 | .env 12 | .env.* 13 | !.env.example 14 | 15 | # Editor 16 | .vscode/ 17 | .idea/ 18 | *.swp 19 | *.swo 20 | 21 | # OS 22 | .DS_Store 23 | Thumbs.db 24 | 25 | # Debug 26 | npm-debug.log* 27 | yarn-debug.log* 28 | yarn-error.log* 29 | 30 | # Database 31 | *.db 32 | *.db-journal 33 | 34 | # Go 35 | /bin/ 36 | *.exe 37 | *.exe~ 38 | *.dll 39 | *.so 40 | *.dylib 41 | *.test 42 | *.out 43 | go.work 44 | imepl.example 45 | -------------------------------------------------------------------------------- /frontend/src/lib/editor/git/changes/GitDiffViewer.svelte: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /frontend/src/stores/editorSessionStore.ts: -------------------------------------------------------------------------------- 1 | import { writable } from 'svelte/store'; 2 | 3 | interface EditorSession { 4 | // Add any non-vim related session state here if needed 5 | } 6 | 7 | const defaultSession: EditorSession = { 8 | // Add default values for any session state 9 | }; 10 | 11 | function createEditorSessionStore() { 12 | const { subscribe, update, set } = writable(defaultSession); 13 | 14 | return { 15 | subscribe, 16 | reset: () => set(defaultSession) 17 | }; 18 | } 19 | 20 | export const editorSessionStore = createEditorSessionStore(); 21 | -------------------------------------------------------------------------------- /frontend/src/lib/editor/LeftSidebar.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 |
11 |
12 | {#if state.activeSection === 'files'} 13 | 14 | {/if} 15 | 16 | {#if state.activeSection === 'git'} 17 | 18 | {/if} 19 |
20 |
-------------------------------------------------------------------------------- /wails.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://wails.io/schemas/config.v2.json", 3 | "name": "editai", 4 | "outputfilename": "editai", 5 | "frontend:install": "npm install", 6 | "frontend:build": "npm run build", 7 | "frontend:dev:watcher": "npm run dev", 8 | "frontend:dev:serverUrl": "auto", 9 | "wailsjsdir": "frontend/src/lib", 10 | "author": { 11 | "name": "nathabonfim59", 12 | "email": "dev@nathabonfim59.com" 13 | }, 14 | "info": { 15 | "companyName": "EditAI", 16 | "productName": "EditAI", 17 | "productVersion": "0.1.8", 18 | "copyright": "Copyright 2024 © - EditAI", 19 | "comments": "An AI-powered code editor" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /frontend/src/lib/wailsjs/runtime/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wailsapp/runtime", 3 | "version": "2.0.0", 4 | "description": "Wails Javascript runtime library", 5 | "main": "runtime.js", 6 | "types": "runtime.d.ts", 7 | "scripts": { 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/wailsapp/wails.git" 12 | }, 13 | "keywords": [ 14 | "Wails", 15 | "Javascript", 16 | "Go" 17 | ], 18 | "author": "Lea Anthony ", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/wailsapp/wails/issues" 22 | }, 23 | "homepage": "https://github.com/wailsapp/wails#readme" 24 | } 25 | -------------------------------------------------------------------------------- /cmd/server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "os" 6 | 7 | "github.com/joho/godotenv" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | var rootCmd = &cobra.Command{ 12 | Use: "editai", 13 | Short: "EditAI - An AI-first powered agentic editor", 14 | Run: func(cmd *cobra.Command, args []string) { 15 | // TODO: Initialize and start the server 16 | log.Println("Starting EditAI server...") 17 | }, 18 | } 19 | 20 | func init() { 21 | // Load environment variables 22 | if err := godotenv.Load(); err != nil { 23 | log.Println("No .env file found") 24 | } 25 | } 26 | 27 | func main() { 28 | if err := rootCmd.Execute(); err != nil { 29 | os.Exit(1) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /frontend/src/types/ui.ts: -------------------------------------------------------------------------------- 1 | import type { service } from '@/lib/wailsjs/go/models' 2 | 3 | export interface Position { 4 | x: number; 5 | y: number; 6 | } 7 | 8 | export interface ContextMenuItem { 9 | label: string; 10 | icon?: any; 11 | action: () => void; 12 | shortcut?: string; 13 | divider?: boolean; 14 | disabled?: boolean; 15 | } 16 | 17 | export interface SidebarState { 18 | collapsed: boolean; 19 | activeSection: 'files' | 'git'; 20 | isAllCollapsed: boolean; 21 | } 22 | 23 | export interface BottomPaneState { 24 | collapsed: boolean; 25 | activeSection: 'terminal' | 'problems' | 'output'; 26 | isAllCollapsed: boolean; 27 | } 28 | -------------------------------------------------------------------------------- /frontend/src/types/keyboard.ts: -------------------------------------------------------------------------------- 1 | export type ModifierKey = 'ctrl' | 'alt' | 'shift' | 'meta'; 2 | 3 | export type KeyboardContext = 4 | | 'global' 5 | | 'commandPalette' 6 | | 'fileFinder' 7 | | 'editor' 8 | | 'aiAssistant' 9 | | 'git' 10 | | 'fileManager' 11 | | 'bottomPane'; 12 | 13 | export type KeyBinding = { 14 | key: string; 15 | modifiers?: ModifierKey[]; 16 | description: string; 17 | category?: string; 18 | context: KeyboardContext[]; 19 | action: () => void; 20 | }; 21 | 22 | export type KeyBindingConfig = { 23 | [command: string]: { 24 | defaultBinding: Omit; 25 | action: () => void; 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /internal/db/db.go: -------------------------------------------------------------------------------- 1 | // Code generated by sqlc. DO NOT EDIT. 2 | // versions: 3 | // sqlc v1.27.0 4 | 5 | package db 6 | 7 | import ( 8 | "context" 9 | "database/sql" 10 | ) 11 | 12 | type DBTX interface { 13 | ExecContext(context.Context, string, ...interface{}) (sql.Result, error) 14 | PrepareContext(context.Context, string) (*sql.Stmt, error) 15 | QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) 16 | QueryRowContext(context.Context, string, ...interface{}) *sql.Row 17 | } 18 | 19 | func New(db DBTX) *Queries { 20 | return &Queries{db: db} 21 | } 22 | 23 | type Queries struct { 24 | db DBTX 25 | } 26 | 27 | func (q *Queries) WithTx(tx *sql.Tx) *Queries { 28 | return &Queries{ 29 | db: tx, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /frontend/src/lib/utils/time.ts: -------------------------------------------------------------------------------- 1 | // Format date to relative time (e.g., "2 hours ago", "3 days ago") 2 | export function formatRelativeTime(date: string) { 3 | const now = new Date(); 4 | const commitDate = new Date(date); 5 | const diffInSeconds = Math.floor((now.getTime() - commitDate.getTime()) / 1000); 6 | 7 | if (diffInSeconds < 60) return 'just now'; 8 | if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`; 9 | if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`; 10 | if (diffInSeconds < 604800) return `${Math.floor(diffInSeconds / 86400)}d ago`; 11 | if (diffInSeconds < 2592000) return `${Math.floor(diffInSeconds / 604800)}w ago`; 12 | return commitDate.toLocaleDateString(); 13 | } -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/svelte/tsconfig.json", 3 | "compilerOptions": { 4 | "target": "ESNext", 5 | "useDefineForClassFields": true, 6 | "module": "ESNext", 7 | "moduleResolution": "bundler", 8 | "resolveJsonModule": true, 9 | "allowJs": true, 10 | "checkJs": true, 11 | "isolatedModules": true, 12 | "strict": true, 13 | "noImplicitAny": true, 14 | "noUnusedLocals": true, 15 | "noUnusedParameters": true, 16 | "noImplicitReturns": true, 17 | "skipLibCheck": true, 18 | "baseUrl": ".", 19 | "paths": { 20 | "@/*": ["src/*"], 21 | } 22 | }, 23 | "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte", "src/**/*.d.ts"], 24 | "references": [{ "path": "./tsconfig.node.json" }] 25 | } 26 | -------------------------------------------------------------------------------- /frontend/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import { svelte } from '@sveltejs/vite-plugin-svelte' 3 | import { resolve } from 'path' 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [svelte()], 8 | resolve: { 9 | alias: { 10 | '@': resolve(__dirname, './src'), 11 | } 12 | }, 13 | build: { 14 | rollupOptions: { 15 | output: { 16 | manualChunks: { 17 | 'monaco': ['monaco-editor'] 18 | } 19 | } 20 | }, 21 | worker: { 22 | format: 'es' 23 | } 24 | }, 25 | optimizeDeps: { 26 | exclude: ['@wailsjs/runtime'] 27 | }, 28 | server: { 29 | fs: { 30 | strict: false 31 | } 32 | }, 33 | publicDir: 'public', 34 | base: './' 35 | }) 36 | -------------------------------------------------------------------------------- /frontend/src/lib/components/palletes/components/ResultsList.svelte: -------------------------------------------------------------------------------- 1 | 16 | 17 |
18 |
19 | 20 |
21 |
22 | 23 | {#if isEmpty} 24 | 25 |
26 | {emptyMessage} 27 |
28 |
29 | {/if} 30 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "embed" 5 | "os" 6 | 7 | "github.com/edit4i/editor/internal/command" 8 | "github.com/wailsapp/wails/v2" 9 | "github.com/wailsapp/wails/v2/pkg/options" 10 | "github.com/wailsapp/wails/v2/pkg/options/assetserver" 11 | ) 12 | 13 | //go:embed all:frontend/dist 14 | var assets embed.FS 15 | 16 | func main() { 17 | // Check if running in CLI mode 18 | if len(os.Args) > 1 { 19 | if err := command.Execute(); err != nil { 20 | os.Exit(1) 21 | } 22 | return 23 | } 24 | 25 | // Create an instance of the app structure 26 | app := NewApp() 27 | 28 | // Create application with options 29 | err := wails.Run(&options.App{ 30 | Title: "edit4i", 31 | Width: 1024, 32 | Height: 768, 33 | AssetServer: &assetserver.Options{ 34 | Assets: assets, 35 | }, 36 | OnStartup: app.startup, 37 | Bind: []interface{}{ 38 | app, 39 | }, 40 | }) 41 | 42 | if err != nil { 43 | println("Error:", err.Error()) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /frontend/src/stores/editorInstanceStore.ts: -------------------------------------------------------------------------------- 1 | import { writable } from 'svelte/store'; 2 | import type TabEditor from '@/lib/editor/core/TabEditor.svelte'; 3 | 4 | function createEditorStore() { 5 | const { subscribe, update, set } = writable(new Map()); 6 | 7 | return { 8 | subscribe, 9 | setEditor: (id: string, editor: TabEditor) => update(editors => { 10 | editors.set(id, editor); 11 | return editors; 12 | }), 13 | removeEditor: (id: string) => update(editors => { 14 | editors.delete(id); 15 | return editors; 16 | }), 17 | getEditor: (id: string) => { 18 | let editor: TabEditor | undefined; 19 | update(editors => { 20 | editor = editors.get(id); 21 | return editors; 22 | }); 23 | return editor; 24 | } 25 | }; 26 | } 27 | 28 | export const editorInstanceStore = createEditorStore(); 29 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "editai-frontend", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview", 10 | "check": "svelte-check --tsconfig ./tsconfig.json" 11 | }, 12 | "devDependencies": { 13 | "@sveltejs/vite-plugin-svelte": "^6.1.0", 14 | "@tsconfig/svelte": "^5.0.2", 15 | "autoprefixer": "^10.4.20", 16 | "postcss": "^8.4.49", 17 | "svelte": "^4.0.0", 18 | "svelte-check": "^3.6.2", 19 | "tailwindcss": "^3.4.15", 20 | "typescript": "^5.3.3", 21 | "vite": "^7.0.6" 22 | }, 23 | "dependencies": { 24 | "@xterm/addon-fit": "^0.10.0", 25 | "@xterm/addon-search": "^0.15.0", 26 | "@xterm/addon-webgl": "^0.18.0", 27 | "@xterm/xterm": "^5.5.0", 28 | "lucide-svelte": "^0.294.0", 29 | "monaco-editor": "^0.52.0", 30 | "monaco-vim": "^0.4.1", 31 | "svelte-spa-router": "^4.0.1", 32 | "tailwind-merge": "^2.5.5" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /frontend/src/stores/commandStore.ts: -------------------------------------------------------------------------------- 1 | import { writable, derived } from 'svelte/store'; 2 | import { keyBindings, formatKeybinding } from './keyboardStore'; 3 | 4 | export interface Command { 5 | id: string; 6 | label: string; 7 | category?: string; 8 | context?: string[]; 9 | shortcut?: string; 10 | action: () => void; 11 | } 12 | 13 | // Create a derived store that combines keyboard shortcuts with commands 14 | export const commandStore = derived( 15 | keyBindings, 16 | ($keyBindings) => { 17 | const commands: Command[] = []; 18 | 19 | // Convert keyboard bindings to commands 20 | for (const [id, binding] of Object.entries($keyBindings)) { 21 | commands.push({ 22 | id, 23 | label: binding.description, 24 | category: binding.category, 25 | shortcut: formatKeybinding(binding), 26 | action: binding.action 27 | }); 28 | } 29 | 30 | return commands; 31 | } 32 | ); 33 | -------------------------------------------------------------------------------- /frontend/src/lib/editor/Breadcrumbs.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 |
12 |
13 | {#each parts as part, i} 14 | {#if i > 0} 15 | 16 | {/if} 17 | 18 | {part} 19 | 20 | {/each} 21 |
22 |
23 | 24 | 33 | -------------------------------------------------------------------------------- /frontend/src/lib/editor/git/GitRepositoryStatus.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | {#if $gitStore.isLoading} 8 |
9 | 10 | Loading Git Repository... 11 |
12 | {:else if !$gitStore.isRepository} 13 |
14 |
This directory is not a Git repository
15 | 18 |
19 | {:else if $gitStore.error} 20 |
21 |
{$gitStore.error}
22 | 25 |
26 | {/if} 27 | -------------------------------------------------------------------------------- /frontend/src/lib/utils/languageMap.ts: -------------------------------------------------------------------------------- 1 | // Map file extensions to Monaco editor language identifiers 2 | export const languageMap: Record = { 3 | // Web 4 | 'html': 'html', 5 | 'htm': 'html', 6 | 'css': 'css', 7 | 'scss': 'scss', 8 | 'less': 'less', 9 | 'js': 'javascript', 10 | 'jsx': 'javascript', 11 | 'ts': 'typescript', 12 | 'tsx': 'typescript', 13 | 'json': 'json', 14 | 'svelte': 'svelte', 15 | 'vue': 'vue', 16 | 17 | // Programming Languages 18 | 'py': 'python', 19 | 'java': 'java', 20 | 'c': 'c', 21 | 'cpp': 'cpp', 22 | 'h': 'cpp', 23 | 'hpp': 'cpp', 24 | 'cs': 'csharp', 25 | 'go': 'go', 26 | 'rs': 'rust', 27 | 'rb': 'ruby', 28 | 'php': 'php', 29 | 'pl': 'perl', 30 | 'sh': 'shell', 31 | 'bash': 'shell', 32 | 'zsh': 'shell', 33 | 34 | // Markup/Config 35 | 'md': 'markdown', 36 | 'markdown': 'markdown', 37 | 'yaml': 'yaml', 38 | 'yml': 'yaml', 39 | 'toml': 'toml', 40 | 'xml': 'xml', 41 | 'svg': 'xml', 42 | 43 | // Default 44 | 'txt': 'plaintext' 45 | }; 46 | 47 | export function getLanguageFromPath(path: string): string { 48 | const ext = path.split('.').pop()?.toLowerCase() || ''; 49 | return languageMap[ext] || 'plaintext'; 50 | } 51 | -------------------------------------------------------------------------------- /frontend/src/stores/editorConfigStore.ts: -------------------------------------------------------------------------------- 1 | import { writable } from 'svelte/store'; 2 | import type { service } from '@/lib/wailsjs/go/models'; 3 | import { GetEditorConfig } from '@/lib/wailsjs/go/main/App'; 4 | 5 | type EditorConfig = service.EditorConfig; 6 | 7 | const defaultConfig: EditorConfig = { 8 | editor: { 9 | theme: 'vs-dark', 10 | fontSize: 14, 11 | tabSize: 4, 12 | wordWrap: true, 13 | lineNumbers: true, 14 | relativeLines: false, 15 | minimap: false, 16 | stickyScroll: false, 17 | vim: { 18 | enabled: false, 19 | mode: 'normal' 20 | } 21 | }, 22 | keyboard: { 23 | customBindings: {} 24 | } 25 | }; 26 | 27 | function createEditorConfigStore() { 28 | const { subscribe, set } = writable(defaultConfig); 29 | 30 | return { 31 | subscribe, 32 | 33 | // Load config from backend 34 | loadConfig: async () => { 35 | try { 36 | const config = await GetEditorConfig(); 37 | set(config || defaultConfig); 38 | } catch (error) { 39 | console.error('Error loading editor config:', error); 40 | set(defaultConfig); 41 | } 42 | } 43 | }; 44 | } 45 | 46 | export const editorConfigStore = createEditorConfigStore(); 47 | -------------------------------------------------------------------------------- /frontend/src/lib/components/palletes/components/CommandItem.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | 37 | -------------------------------------------------------------------------------- /internal/service/projects.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | 7 | "github.com/edit4i/editor/internal/db" 8 | ) 9 | 10 | // ProjectsService handles project-related operations 11 | type ProjectsService struct { 12 | queries *db.Queries 13 | } 14 | 15 | // NewProjectsService creates a new projects service 16 | func NewProjectsService(dbConn *sql.DB) *ProjectsService { 17 | return &ProjectsService{ 18 | queries: db.New(dbConn), 19 | } 20 | } 21 | 22 | // GetRecentProjects returns a list of recently opened projects 23 | func (s *ProjectsService) GetRecentProjects(limit int64) ([]db.Project, error) { 24 | return s.queries.ListRecentProjects(context.Background(), limit) 25 | } 26 | 27 | // AddProject adds a new project or updates its last opened time if it exists 28 | func (s *ProjectsService) AddProject(name, path string) (*db.Project, error) { 29 | ctx := context.Background() 30 | 31 | // Try to create new project 32 | proj, err := s.queries.CreateProject(ctx, db.CreateProjectParams{ 33 | Name: name, 34 | Path: path, 35 | }) 36 | if err != nil { 37 | // If project exists, update last opened time 38 | existing, err := s.queries.GetProject(ctx, path) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | err = s.queries.UpdateProjectLastOpened(ctx, existing.ID) 44 | if err != nil { 45 | return nil, err 46 | } 47 | 48 | return &existing, nil 49 | } 50 | 51 | return &proj, nil 52 | } 53 | -------------------------------------------------------------------------------- /frontend/src/lib/components/DropdownMenu.svelte: -------------------------------------------------------------------------------- 1 | 15 | 16 | {#if show} 17 |
show = false} 20 | class="absolute py-1 bg-gray-800 rounded shadow-lg z-50 border border-gray-700" 21 | class:right-0={align === 'right'} 22 | class:left-0={align === 'left'} 23 | class:mt-1={position === 'bottom'} 24 | class:mb-1={position === 'top'} 25 | class:bottom-full={position === 'top'} 26 | style="width: {width}" 27 | > 28 | {#each items as item} 29 | 39 | {/each} 40 |
41 | {/if} 42 | -------------------------------------------------------------------------------- /frontend/src/lib/editor/git/GitStagedChanges.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | {#if stagedChanges.length > 0} 13 |
14 | 27 | {#if $gitStore.stagedExpanded} 28 |
29 | {#each stagedChanges as item} 30 | 31 | {/each} 32 |
33 | {/if} 34 |
35 | {/if} 36 | -------------------------------------------------------------------------------- /frontend/src/lib/editor/git/changes/GitDiffHeader.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 |
11 |
12 | {diff?.path} 13 |
14 | {#if stats.added > 0} 15 |
16 | 17 | {stats.added} 18 |
19 | {/if} 20 | {#if stats.deleted > 0} 21 |
22 | 23 | {stats.deleted} 24 |
25 | {/if} 26 |
27 |
28 |
29 |
37 |
38 | -------------------------------------------------------------------------------- /internal/db/init.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | "os" 7 | "path/filepath" 8 | 9 | _ "github.com/mattn/go-sqlite3" 10 | ) 11 | 12 | const ( 13 | defaultDBName = "metadata.db" 14 | ) 15 | 16 | // Config holds database configuration 17 | type Config struct { 18 | Directory string 19 | Filename string 20 | } 21 | 22 | // DefaultConfig returns the default configuration for Edit4I database 23 | func DefaultConfig() *Config { 24 | homeDir, err := os.UserHomeDir() 25 | if err != nil { 26 | homeDir = "." 27 | } 28 | 29 | return &Config{ 30 | Directory: filepath.Join(homeDir, ".edit4i"), 31 | Filename: defaultDBName, 32 | } 33 | } 34 | 35 | // InitDB initializes the database connection using the provided configuration 36 | func InitDB(cfg *Config) (*sql.DB, error) { 37 | if cfg == nil { 38 | cfg = DefaultConfig() 39 | } 40 | 41 | // Create directory if it doesn't exist 42 | if err := os.MkdirAll(cfg.Directory, 0755); err != nil { 43 | return nil, fmt.Errorf("error creating database directory: %v", err) 44 | } 45 | 46 | // Full database path 47 | dbPath := filepath.Join(cfg.Directory, cfg.Filename) 48 | 49 | // Open database connection 50 | db, err := sql.Open("sqlite3", dbPath) 51 | if err != nil { 52 | return nil, fmt.Errorf("error opening database: %v", err) 53 | } 54 | 55 | // Test the connection 56 | if err := db.Ping(); err != nil { 57 | db.Close() 58 | return nil, fmt.Errorf("error connecting to database: %v", err) 59 | } 60 | 61 | return db, nil 62 | } 63 | -------------------------------------------------------------------------------- /frontend/src/lib/components/Select.svelte: -------------------------------------------------------------------------------- 1 | 33 | 34 |
35 | 45 |
46 | ▼ 47 |
48 |
49 | 50 | 56 | -------------------------------------------------------------------------------- /frontend/src/lib/editor/git/changes/GitChangesView.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | {#if $gitStore.isDiffLoading} 10 |
11 | 12 |
13 | {:else if $gitStore.diffError} 14 |
15 |
16 | Error 17 |
18 |
26 |
27 |
28 |
{$gitStore.diffError}
29 |
30 |
31 | {:else if $gitStore.fileDiff} 32 |
33 | 34 |
35 | 36 |
37 |
38 | {/if} 39 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | APP_NAME = editai 2 | DOCKER_IMAGE = editai:latest 3 | VERSION = 0.1.0 4 | BUILD_TIME = $(shell date -u '+%Y-%m-%d_%H:%M:%S') 5 | BUILD_OPTIONS := -clean -upx 6 | BUILD_TAGS := 7 | GO_ENV := GOFLAGS="-buildvcs=false" 8 | 9 | WAILS_PATH := $(shell command -v wails 2>/dev/null) 10 | 11 | # If Wails is not installed, exit the make process 12 | ifeq ($(WAILS_PATH),) 13 | $(error Wails is not installed. Please install Wails to proceed.) 14 | endif 15 | 16 | # Setup development environment 17 | configure: 18 | docker compose up -d 19 | 20 | dev: 21 | wails dev 22 | 23 | WEBKIT_TAG := $(shell \ 24 | if ! pkg-config --exists webkit2gtk-4.0; then \ 25 | echo "-tags webkit2_41"; \ 26 | else \ 27 | echo ""; \ 28 | fi \ 29 | ) 30 | 31 | # Build development version 32 | build-dev: 33 | $(GO_ENV) wails build ${WEBKIT_TAG} 34 | 35 | 36 | # Build for different platforms 37 | build-windows: 38 | $(GO_ENV) wails build -platform windows/amd64 -nsis ${BUILD_OPTIONS} 39 | 40 | build-mac: 41 | $(GO_ENV) wails build -platform darwin/universal ${BUILD_OPTIONS} 42 | 43 | build-linux: 44 | $(GO_ENV) wails build ${WEBKIT_TAG} -platform linux/amd64 ${BUILD_OPTIONS} && \ 45 | cd build/debian && \ 46 | nfpm pkg --packager deb --target ../bin/ && \ 47 | nfpm pkg --packager rpm --target ../bin/ 48 | 49 | # Clean up 50 | clean: 51 | rm -rf build/bin/* 52 | docker compose down --rmi all 53 | 54 | # Update dependencies 55 | tidy: 56 | docker exec -e $(GO_ENV) editai-dev sh -c "go mod tidy && cd frontend && npm install" 57 | 58 | .PHONY: configure build-dev build-windows build-mac build-linux build-linux-static clean tidy 59 | -------------------------------------------------------------------------------- /frontend/src/lib/utils/fuzzySearch.ts: -------------------------------------------------------------------------------- 1 | export function fuzzySearch( 2 | items: T[], 3 | query: string, 4 | getter: (item: T) => string 5 | ): T[] { 6 | const searchQuery = query.toLowerCase(); 7 | return items 8 | .map(item => { 9 | const str = getter(item).toLowerCase(); 10 | let score = 0; 11 | let lastMatchIndex = -1; 12 | let matches = 0; 13 | 14 | for (let i = 0; i < searchQuery.length; i++) { 15 | const searchChar = searchQuery[i]; 16 | const found = str.indexOf(searchChar, lastMatchIndex + 1); 17 | 18 | if (found === -1) { 19 | return { item, score: -1 }; 20 | } 21 | 22 | // Consecutive matches score higher 23 | if (found === lastMatchIndex + 1) { 24 | score += 2; 25 | } 26 | 27 | // Characters closer to the start score higher 28 | score += 1 / (found + 1); 29 | 30 | lastMatchIndex = found; 31 | matches++; 32 | } 33 | 34 | // Complete matches score higher 35 | if (matches === searchQuery.length) { 36 | score += 1; 37 | } 38 | 39 | // Exact matches score highest 40 | if (str === searchQuery) { 41 | score += 2; 42 | } 43 | 44 | return { item, score }; 45 | }) 46 | .filter(({ score }) => score > -1) 47 | .sort((a, b) => b.score - a.score) 48 | .map(({ item }) => item); 49 | } 50 | -------------------------------------------------------------------------------- /frontend/src/App.svelte: -------------------------------------------------------------------------------- 1 | 36 | 37 | 38 | 39 |
40 | 41 | 42 | (showCommandPalette = false)} 45 | /> 46 | 47 | (showBranchPalette = false)} 50 | /> 51 |
52 | -------------------------------------------------------------------------------- /frontend/src/lib/editor/git/changes/DiffHeader.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
15 |
16 | Changes 17 | 18 | {filepath.replace('[diff] ', '')} 19 |
20 |
21 | 22 | {stats.added} 23 |
24 |
25 | 26 | {stats.deleted} 27 |
28 |
29 |
30 |
31 | 32 | 41 | -------------------------------------------------------------------------------- /frontend/src/types/files.ts: -------------------------------------------------------------------------------- 1 | export interface FileNode { 2 | id: string; 3 | name: string; 4 | path: string; 5 | type: 'file' | 'folder'; 6 | expanded?: boolean; 7 | isRenaming?: boolean; 8 | children?: FileNode[]; 9 | metadata?: { 10 | size?: number; 11 | modified?: Date; 12 | type?: string; 13 | }; 14 | } 15 | 16 | export interface OpenFile { 17 | path: string; 18 | content: string; 19 | isDirty: boolean; 20 | language?: string; 21 | cursor?: { 22 | line: number; 23 | column: number; 24 | }; 25 | selections?: Array<{ 26 | start: { line: number; column: number }; 27 | end: { line: number; column: number }; 28 | }>; 29 | } 30 | 31 | export interface Tab extends OpenFile { 32 | id: number; 33 | name: string; 34 | active: boolean; 35 | } 36 | 37 | export type FileAction = 38 | | { type: 'CREATE_FILE'; path: string; } 39 | | { type: 'CREATE_FOLDER'; path: string; } 40 | | { type: 'RENAME'; oldPath: string; newPath: string; } 41 | | { type: 'DELETE'; path: string; } 42 | | { type: 'MOVE'; sourcePath: string; targetPath: string; }; 43 | 44 | export interface FileOperation { 45 | type: 'success' | 'error'; 46 | message: string; 47 | action: FileAction; 48 | timestamp: number; 49 | } 50 | 51 | export interface FileState { 52 | fileTree: FileNode | null; 53 | activeFilePath: string | null; 54 | openFiles: Map; 55 | loading: boolean; 56 | error: string | null; 57 | } 58 | 59 | export interface SidebarState { 60 | collapsed: boolean; 61 | activeSection: 'files' | 'git'; 62 | fileTree: FileNode[]; 63 | isAllCollapsed: boolean; 64 | } -------------------------------------------------------------------------------- /frontend/src/lib/editor/git/GitCommitItem.svelte: -------------------------------------------------------------------------------- 1 | 28 | 29 | 30 | 31 |
35 | 36 |
37 |
38 | {commit.hash.substring(0, 7)} 39 | {formatRelativeTime(commit.date)} 40 |
41 |

42 | {commit.message} 43 |

44 |

45 | {commit.author} 46 |

47 |
48 |
49 | -------------------------------------------------------------------------------- /examples/tools/web_scraper.yaml: -------------------------------------------------------------------------------- 1 | name: WebScraper 2 | version: 1.0.0 3 | description: A tool to scrape web content and process it 4 | 5 | capabilities: 6 | - browser 7 | - http 8 | - vision 9 | - terminal 10 | 11 | parameters: 12 | - name: url 13 | type: string 14 | description: URL to scrape 15 | required: true 16 | - name: selector 17 | type: string 18 | description: CSS selector to extract 19 | required: true 20 | - name: process_type 21 | type: enum 22 | values: [text, image, table] 23 | default: text 24 | 25 | steps: 26 | - name: Fetch Page 27 | type: browser 28 | action: navigate 29 | params: 30 | url: ${url} 31 | waitFor: ${selector} 32 | 33 | - name: Extract Content 34 | type: browser 35 | action: extract 36 | params: 37 | selector: ${selector} 38 | store_as: raw_content 39 | 40 | - name: Process Content 41 | type: lua 42 | code: | 43 | function process(content, type) 44 | if type == "text" then 45 | return content:gsub("%s+", " "):trim() 46 | elseif type == "table" then 47 | return json.encode(parse_table(content)) 48 | end 49 | return content 50 | end 51 | 52 | return process(raw_content, process_type) 53 | 54 | - name: Save Result 55 | type: terminal 56 | command: | 57 | echo "${result}" > output.json 58 | 59 | error_handling: 60 | retry: 61 | max_attempts: 3 62 | delay: 1000 63 | fallback: 64 | type: http 65 | action: fetch 66 | params: 67 | url: ${url} 68 | 69 | validation: 70 | - type: lua 71 | code: | 72 | return #result > 0 73 | 74 | version_control: 75 | repository: tools/web_scraper 76 | branch: main 77 | tags: 78 | - web 79 | - scraping 80 | - automation 81 | -------------------------------------------------------------------------------- /frontend/src/lib/editor/panes/ExplorerPane.svelte: -------------------------------------------------------------------------------- 1 | 22 | 23 |
24 |
25 |
26 | 27 | Explorer 28 |
29 |
30 | 37 | 44 |
45 |
46 |
47 | 48 |
49 |
50 | -------------------------------------------------------------------------------- /frontend/src/lib/components/palletes/components/FileItem.svelte: -------------------------------------------------------------------------------- 1 | 15 | 16 | 46 | -------------------------------------------------------------------------------- /frontend/src/lib/components/Button.svelte: -------------------------------------------------------------------------------- 1 | 44 | 45 | 61 | -------------------------------------------------------------------------------- /frontend/src/lib/editor/panes/BottomPane.svelte: -------------------------------------------------------------------------------- 1 | 30 | 31 |
32 |
33 | {#if state.activeSection === 'terminal'} 34 | 35 | {:else if state.activeSection === 'problems'} 36 |
37 | 38 |

No problems found.

39 |
40 | {:else if state.activeSection === 'output'} 41 |
42 | 43 |

No output to display.

44 |
45 | {/if} 46 |
47 |
48 | -------------------------------------------------------------------------------- /frontend/src/lib/utils/gitSort.ts: -------------------------------------------------------------------------------- 1 | import type { service } from "@/lib/wailsjs/go/models"; 2 | 3 | export function compareFiles(a: string, b: string) { 4 | const aName = a.split('/').pop() || ''; 5 | const bName = b.split('/').pop() || ''; 6 | 7 | // Helper to check if string starts with dot or number 8 | const startsWithDotOrNumber = (str: string) => /^[.0-9]/.test(str); 9 | 10 | const aHasDotOrNumber = startsWithDotOrNumber(aName); 11 | const bHasDotOrNumber = startsWithDotOrNumber(bName); 12 | 13 | // If one has dot/number and other doesn't, prioritize dot/number 14 | if (aHasDotOrNumber && !bHasDotOrNumber) return -1; 15 | if (!aHasDotOrNumber && bHasDotOrNumber) return 1; 16 | 17 | // Otherwise, normal alphabetical sort 18 | return a.localeCompare(b); 19 | } 20 | 21 | export function sortGitFiles(files: service.FileStatus[], hierarchical: boolean): service.FileStatus[] { 22 | if (!hierarchical) { 23 | // Simple sort by filename 24 | return [...files].sort((a, b) => compareFiles(a.file, b.file)); 25 | } 26 | 27 | // Group files by directory 28 | const filesByDir = files.reduce((acc, file) => { 29 | const parts = file.file.split('/'); 30 | const dir = parts.length > 1 ? parts.slice(0, -1).join('/') : ''; 31 | if (!acc[dir]) { 32 | acc[dir] = []; 33 | } 34 | acc[dir].push(file); 35 | return acc; 36 | }, {} as Record); 37 | 38 | // Sort files within each directory and concatenate 39 | return Object.entries(filesByDir) 40 | // Sort directories 41 | .sort(([dirA], [dirB]) => dirA.localeCompare(dirB)) 42 | // Sort files within each directory and flatten 43 | .flatMap(([_, dirFiles]) => 44 | dirFiles.sort((a, b) => compareFiles(a.file.split('/').pop() || '', b.file.split('/').pop() || '')) 45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /examples/.editai/knowledge/codestyle/javascript.yaml: -------------------------------------------------------------------------------- 1 | name: JavaScript Style Guide 2 | version: 1.0.0 3 | last_updated: 2024-03-14 4 | 5 | rules: 6 | naming: 7 | variables: 8 | style: camelCase 9 | examples: 10 | - good: userName 11 | bad: user_name 12 | components: 13 | style: PascalCase 14 | examples: 15 | - good: UserProfile 16 | bad: userProfile 17 | 18 | formatting: 19 | indent: 2 20 | max_line_length: 80 21 | quotes: single 22 | 23 | patterns: 24 | preferred: 25 | - name: Array Methods 26 | use: array.map(), array.filter() 27 | avoid: for loops 28 | example: | 29 | // Good 30 | const newArray = items.map(item => transform(item)); 31 | 32 | // Avoid 33 | const newArray = []; 34 | for (let i = 0; i < items.length; i++) { 35 | newArray.push(transform(items[i])); 36 | } 37 | 38 | - name: Async/Await 39 | use: async/await 40 | avoid: raw promises 41 | example: | 42 | // Good 43 | async function getData() { 44 | const result = await api.fetch(); 45 | return result; 46 | } 47 | 48 | // Avoid 49 | function getData() { 50 | return api.fetch().then(result => result); 51 | } 52 | 53 | ai_prompts: 54 | style_check: | 55 | Review this code following our JavaScript style guide: 56 | - Use camelCase for variables 57 | - Use PascalCase for components 58 | - Prefer array methods over loops 59 | - Use async/await for async operations 60 | - Keep lines under 80 characters 61 | - Use single quotes for strings 62 | 63 | refactor_suggestions: | 64 | Suggest refactoring while considering: 65 | - Our naming conventions 66 | - Preferred patterns 67 | - Modern JavaScript features 68 | - Code organization guidelines 69 | -------------------------------------------------------------------------------- /.docker/wails/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | 3 | # Prevent tzdata questions 4 | ENV DEBIAN_FRONTEND=noninteractive 5 | 6 | # Install system dependencies 7 | RUN apt-get update && apt-get install -y \ 8 | wget \ 9 | git \ 10 | build-essential \ 11 | libgtk-3-0 \ 12 | libwebkit2gtk-4.0-dev \ 13 | gcc-aarch64-linux-gnu \ 14 | musl \ 15 | musl-dev \ 16 | musl-tools \ 17 | upx \ 18 | curl \ 19 | pkg-config \ 20 | software-properties-common \ 21 | linux-headers-generic \ 22 | npm 23 | 24 | # Install Go 1.22 25 | RUN wget https://go.dev/dl/go1.22.7.linux-amd64.tar.gz && \ 26 | tar -C /usr/local -xzf go1.22.7.linux-amd64.tar.gz && \ 27 | rm go1.22.7.linux-amd64.tar.gz 28 | 29 | # Add Go to PATH 30 | ENV PATH=$PATH:/usr/local/go/bin 31 | ENV GOPATH=/go 32 | ENV PATH=$PATH:$GOPATH/bin 33 | 34 | # Set musl as the C compiler 35 | ENV CC=/usr/bin/musl-gcc 36 | 37 | # Install Node.js 22 38 | RUN apt-get install -y curl && \ 39 | apt-get remove -y nodejs nodejs-doc libnode-dev && \ 40 | apt-get autoremove -y && \ 41 | curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh && \ 42 | bash nodesource_setup.sh && \ 43 | apt-get update && \ 44 | apt-get install -y nodejs && \ 45 | rm nodesource_setup.sh 46 | 47 | # Install Wails 48 | RUN go install github.com/wailsapp/wails/v2/cmd/wails@v2.9.2 49 | 50 | # Install sqlc 51 | RUN go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest 52 | 53 | WORKDIR /app 54 | 55 | # Copy go.mod and go.sum files 56 | COPY go.mod go.sum ./ 57 | 58 | # Download Go modules 59 | RUN go mod download 60 | 61 | # Copy the rest of the application 62 | COPY . . 63 | 64 | # Build frontend dependencies 65 | RUN cd frontend && npm install 66 | 67 | # Install additional Linux headers and development files 68 | RUN apt-get update && apt-get install -y \ 69 | linux-libc-dev \ 70 | linux-headers-$(uname -r) \ 71 | musl-dev \ 72 | build-essential \ 73 | gcc-multilib \ 74 | libc6-dev 75 | 76 | # Expose any necessary ports 77 | EXPOSE 3000 78 | -------------------------------------------------------------------------------- /frontend/src/lib/editor/git/GitCommitSection.svelte: -------------------------------------------------------------------------------- 1 | 39 | 40 |
41 |
42 | 48 | 62 |
63 | 64 |
65 | -------------------------------------------------------------------------------- /frontend/src/lib/editor/panes/GitPane.svelte: -------------------------------------------------------------------------------- 1 | 15 | 16 |
17 |
18 |
19 | {#if $gitStore.isLoading || $gitStore.isQuickRefreshing} 20 | 21 | {:else} 22 | 23 | {/if} 24 | Source Control 25 |
26 |
27 |
43 |
44 | 45 |
46 | 47 | 48 | {#if $gitStore.isRepository && !$gitStore.isLoading && !$gitStore.error} 49 |
50 | 51 | 52 |
53 | 54 | {/if} 55 |
56 |
-------------------------------------------------------------------------------- /examples/.editai/workflows/code-review.yaml: -------------------------------------------------------------------------------- 1 | name: Code Review Workflow 2 | version: 1.0.0 3 | description: Automated code review process 4 | 5 | triggers: 6 | - pull_request.created 7 | - pull_request.synchronized 8 | - manual 9 | 10 | environment: 11 | knowledge_base: 12 | - codestyle/* 13 | - guidelines/* 14 | - api/current 15 | external_docs: 16 | - react 17 | - typescript 18 | 19 | steps: 20 | - name: Initialize Review 21 | tool: context/builder 22 | params: 23 | include: 24 | - changed_files 25 | - pr_description 26 | - related_issues 27 | store_as: review_context 28 | 29 | - name: Style Check 30 | tool: quality/style-checker 31 | params: 32 | rules: ${knowledge_base}/codestyle 33 | context: ${review_context} 34 | report_format: markdown 35 | 36 | - name: Security Scan 37 | tool: security/scanner 38 | params: 39 | level: high 40 | include_deps: true 41 | context: ${review_context} 42 | 43 | - name: Documentation Check 44 | tool: docs/validator 45 | params: 46 | standards: ${knowledge_base}/guidelines/docs 47 | api_docs: ${knowledge_base}/api/current 48 | context: ${review_context} 49 | 50 | - name: AI Review 51 | tool: ai/reviewer 52 | params: 53 | context: ${review_context} 54 | style_guide: ${knowledge_base}/codestyle 55 | guidelines: ${knowledge_base}/guidelines 56 | focus: 57 | - patterns 58 | - best_practices 59 | - potential_issues 60 | - performance 61 | output: 62 | format: markdown 63 | sections: 64 | - summary 65 | - issues 66 | - suggestions 67 | - examples 68 | 69 | - name: Generate Report 70 | tool: report/generator 71 | params: 72 | inputs: 73 | - ${style_check.output} 74 | - ${security_scan.output} 75 | - ${docs_check.output} 76 | - ${ai_review.output} 77 | template: templates/review-report 78 | format: markdown 79 | 80 | notifications: 81 | on_complete: 82 | - type: github_comment 83 | template: templates/review-comment 84 | - type: slack 85 | channel: code-reviews 86 | template: templates/slack-notification 87 | 88 | error_handling: 89 | retry: 90 | max_attempts: 3 91 | delay: 1000 92 | notify_on_failure: 93 | - tech-leads 94 | - pr_author 95 | -------------------------------------------------------------------------------- /frontend/src/lib/actions/tooltip.ts: -------------------------------------------------------------------------------- 1 | import { keyBindings, formatKeybinding } from '../../stores/keyboardStore'; 2 | import type { KeyBinding } from '../../types/keyboard'; 3 | 4 | let tooltipElement: HTMLElement | null = null; 5 | 6 | function createTooltip() { 7 | const tooltip = document.createElement('div'); 8 | tooltip.className = 'fixed px-2 py-1 text-xs text-gray-300 bg-gray-800 rounded shadow-lg border border-gray-700 z-50 pointer-events-none opacity-0 transition-opacity duration-150 ease-in-out'; 9 | document.body.appendChild(tooltip); 10 | return tooltip; 11 | } 12 | 13 | function getShortcutForCommand(command: string): string | null { 14 | let shortcut: string | null = null; 15 | keyBindings.subscribe(bindings => { 16 | if (bindings[command]) { 17 | shortcut = formatKeybinding(bindings[command]); 18 | } 19 | })(); 20 | return shortcut; 21 | } 22 | 23 | export function tooltip(node: HTMLElement, params: { text: string; command?: string }) { 24 | let text = params.text; 25 | const shortcut = params.command ? getShortcutForCommand(params.command) : null; 26 | 27 | function showTooltip(event: MouseEvent) { 28 | if (!tooltipElement) { 29 | tooltipElement = createTooltip(); 30 | } 31 | 32 | const content = shortcut ? `${text} (${shortcut})` : text; 33 | tooltipElement.textContent = content; 34 | 35 | const rect = node.getBoundingClientRect(); 36 | const tooltipRect = tooltipElement.getBoundingClientRect(); 37 | 38 | tooltipElement.style.left = `${rect.left + (rect.width - tooltipRect.width) / 2}px`; 39 | tooltipElement.style.top = `${rect.bottom + 8}px`; 40 | tooltipElement.classList.add('opacity-100'); 41 | } 42 | 43 | function hideTooltip() { 44 | if (tooltipElement) { 45 | tooltipElement.classList.remove('opacity-100'); 46 | } 47 | } 48 | 49 | node.addEventListener('mouseenter', showTooltip); 50 | node.addEventListener('mouseleave', hideTooltip); 51 | 52 | return { 53 | update(newParams: { text: string; command?: string }) { 54 | text = newParams.text; 55 | }, 56 | destroy() { 57 | node.removeEventListener('mouseenter', showTooltip); 58 | node.removeEventListener('mouseleave', hideTooltip); 59 | tooltipElement?.remove(); 60 | tooltipElement = null; 61 | } 62 | }; 63 | } 64 | -------------------------------------------------------------------------------- /examples/.editai/config.yaml: -------------------------------------------------------------------------------- 1 | organization: 2 | name: ExampleOrg 3 | id: org_example123 4 | settings: 5 | default_language: en 6 | timezone: UTC 7 | security_level: high 8 | 9 | knowledge_base: 10 | sources: 11 | internal: 12 | - path: knowledge/codestyle 13 | update_interval: weekly 14 | - path: knowledge/guidelines 15 | update_interval: daily 16 | - path: knowledge/api 17 | auto_sync: true 18 | external: 19 | - name: React Documentation 20 | url: https://react.dev/docs 21 | sync_schedule: daily 22 | sections: 23 | - reference 24 | - api 25 | - name: Company Backend API 26 | url: https://api.company.com/docs 27 | auth: 28 | type: bearer 29 | token_env: API_TOKEN 30 | - name: Design System 31 | github: company/design-system 32 | branch: main 33 | path: docs 34 | 35 | workflows: 36 | ci: 37 | security_check: 38 | runs_on: [push, pull_request] 39 | steps: 40 | - name: Dependency Scan 41 | tool: security/dependency-scanner 42 | severity: high 43 | - name: Code Analysis 44 | tool: security/code-analyzer 45 | config: strict 46 | - name: Secret Detection 47 | tool: security/secret-detector 48 | 49 | code_quality: 50 | runs_on: [pull_request] 51 | steps: 52 | - name: Style Check 53 | tool: quality/style-checker 54 | rules: knowledge/codestyle/rules.yaml 55 | - name: Test Coverage 56 | tool: quality/coverage-checker 57 | minimum: 80% 58 | 59 | review: 60 | auto_review: 61 | trigger: [pull_request] 62 | steps: 63 | - name: Code Review 64 | tool: ai/code-reviewer 65 | context: 66 | - knowledge/guidelines 67 | - knowledge/codestyle 68 | - name: Documentation Check 69 | tool: quality/docs-checker 70 | standards: knowledge/guidelines/docs.yaml 71 | 72 | tools: 73 | allowed_sources: 74 | - org/internal 75 | - marketplace/verified 76 | default_permissions: 77 | terminal: restricted 78 | http: allowed 79 | browser: prompt 80 | vision: allowed 81 | lua: sandboxed 82 | 83 | security: 84 | allowed_domains: 85 | - company.com 86 | - github.com 87 | - npmjs.com 88 | secret_scanning: enabled 89 | dependency_checking: enabled 90 | code_signing: required 91 | -------------------------------------------------------------------------------- /frontend/src/lib/editor/BottomBar.svelte: -------------------------------------------------------------------------------- 1 | 44 | 45 |
46 |
47 | 92 |
93 | 94 | 95 |
96 | 106 |
107 |
108 | -------------------------------------------------------------------------------- /frontend/src/lib/components/Input.svelte: -------------------------------------------------------------------------------- 1 | 88 | 89 | {#if variant === 'textarea'} 90 |