├── next_app
├── public
│ ├── CNAME
│ ├── favicon.ico
│ ├── apple-icon.png
│ ├── icon-black.svg
│ ├── icon.svg
│ └── images
│ │ └── chat.svg
├── .eslintrc.json
├── image.png
├── src
│ ├── assets
│ │ ├── icons
│ │ │ ├── wAR.png
│ │ │ ├── run.svg
│ │ │ ├── loading.svg
│ │ │ └── bazar.svg
│ │ └── din-bhar-code.png
│ ├── components
│ │ ├── sidebar
│ │ │ ├── components
│ │ │ │ ├── packages.tsx
│ │ │ │ ├── projects.tsx
│ │ │ │ ├── sqlite-explorer.tsx
│ │ │ │ ├── files.tsx
│ │ │ │ ├── marketplace.tsx
│ │ │ │ ├── sam.tsx
│ │ │ │ ├── interact.tsx
│ │ │ │ ├── ai-chat.tsx
│ │ │ │ └── index.ts
│ │ │ └── index.tsx
│ │ ├── ui
│ │ │ ├── icons
│ │ │ │ ├── war.tsx
│ │ │ │ └── bazar.tsx
│ │ │ ├── skeleton.tsx
│ │ │ ├── label.tsx
│ │ │ ├── textarea.tsx
│ │ │ ├── separator.tsx
│ │ │ ├── toaster.tsx
│ │ │ ├── input.tsx
│ │ │ ├── sonner.tsx
│ │ │ ├── checkbox.tsx
│ │ │ ├── switch.tsx
│ │ │ ├── tooltip.tsx
│ │ │ ├── popover.tsx
│ │ │ ├── custom
│ │ │ │ ├── switch.tsx
│ │ │ │ ├── error-boundary.tsx
│ │ │ │ └── loading.tsx
│ │ │ ├── avatar.tsx
│ │ │ ├── toggle.tsx
│ │ │ ├── radio-group.tsx
│ │ │ ├── alert.tsx
│ │ │ ├── scroll-area.tsx
│ │ │ ├── resizable.tsx
│ │ │ ├── toggle-group.tsx
│ │ │ ├── button.tsx
│ │ │ ├── tabs.tsx
│ │ │ ├── card.tsx
│ │ │ ├── combo-box.tsx
│ │ │ ├── dialog.tsx
│ │ │ ├── toast.tsx
│ │ │ ├── use-toast.ts
│ │ │ └── alert-dialog.tsx
│ │ ├── mobile
│ │ │ └── index.tsx
│ │ ├── theme-provider.tsx
│ │ ├── views
│ │ │ ├── components
│ │ │ │ ├── _template.tsx
│ │ │ │ ├── index.ts
│ │ │ │ └── editor
│ │ │ │ │ └── components
│ │ │ │ │ ├── output.tsx
│ │ │ │ │ └── history.tsx
│ │ │ └── index.tsx
│ │ ├── menubar
│ │ │ └── components
│ │ │ │ ├── all-projects.tsx
│ │ │ │ ├── duplicate-project.tsx
│ │ │ │ ├── duplicate-file.tsx
│ │ │ │ ├── download-file.tsx
│ │ │ │ ├── download.tsx
│ │ │ │ ├── delete-file.tsx
│ │ │ │ ├── delete-project.tsx
│ │ │ │ ├── rename-project.tsx
│ │ │ │ ├── rename-file.tsx
│ │ │ │ └── blueprint.tsx
│ │ ├── drawer
│ │ │ ├── index.tsx
│ │ │ └── components
│ │ │ │ ├── index.ts
│ │ │ │ ├── marketplace.tsx
│ │ │ │ ├── project-list.tsx
│ │ │ │ ├── sqlite-explorer.tsx
│ │ │ │ └── file-list.tsx
│ │ └── layout.tsx
│ ├── hooks
│ │ ├── index.ts
│ │ ├── useUIState.ts
│ │ ├── useAIState.ts
│ │ ├── profile.ts
│ │ ├── useEditorState.ts
│ │ └── useGlobalState.ts
│ ├── modules
│ │ └── ao
│ │ │ ├── index.ts
│ │ │ ├── test.ts
│ │ │ ├── db-admin.ts
│ │ │ └── graph.ts
│ ├── pages
│ │ ├── bounties.tsx
│ │ ├── index.tsx
│ │ ├── dev.tsx
│ │ ├── _document.tsx
│ │ ├── _app.tsx
│ │ └── import.tsx
│ ├── templates
│ │ ├── index.ts
│ │ └── ao
│ │ │ ├── fantasy-llama.ts
│ │ │ ├── llama-complainer.ts
│ │ │ └── ao-bot.ts
│ ├── utils
│ │ └── keybinds.ts
│ ├── lib
│ │ ├── api.ts
│ │ ├── ai.ts
│ │ └── monaco-completions.ts
│ └── styles
│ │ └── globals.css
├── backend
│ ├── cron.sh
│ ├── routes
│ │ ├── health
│ │ │ └── index.ts
│ │ ├── analytics
│ │ │ ├── referrers.ts
│ │ │ └── post.ts
│ │ ├── system
│ │ │ └── index.ts
│ │ └── chat
│ │ │ └── index.ts
│ ├── utils
│ │ ├── helpers.ts
│ │ └── modelConfig.ts
│ ├── types.ts
│ ├── index.ts
│ ├── db
│ │ └── database.ts
│ ├── inlineSystemPrompt.ts
│ └── extract.sh
├── postcss.config.mjs
├── components.json
├── .gitignore
├── tsconfig.json
├── next.config.mjs
├── README.md
├── tailwind.config.ts
└── package.json
├── images
├── 1.png
├── 2.png
├── 3.png
└── 4.png
├── .gitignore
├── lua
└── sharecode.lua
├── .github
├── FUNDING.yml
└── workflows
│ ├── sync-to-protocol-land.yml
│ └── nextjs.yml
├── LICENSE
└── README.md
/next_app/public/CNAME:
--------------------------------------------------------------------------------
1 | ide.betteridea.dev
2 |
--------------------------------------------------------------------------------
/images/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betteridea-dev/ide/HEAD/images/1.png
--------------------------------------------------------------------------------
/images/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betteridea-dev/ide/HEAD/images/2.png
--------------------------------------------------------------------------------
/images/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betteridea-dev/ide/HEAD/images/3.png
--------------------------------------------------------------------------------
/images/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betteridea-dev/ide/HEAD/images/4.png
--------------------------------------------------------------------------------
/next_app/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/next_app/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betteridea-dev/ide/HEAD/next_app/image.png
--------------------------------------------------------------------------------
/next_app/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betteridea-dev/ide/HEAD/next_app/public/favicon.ico
--------------------------------------------------------------------------------
/next_app/public/apple-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betteridea-dev/ide/HEAD/next_app/public/apple-icon.png
--------------------------------------------------------------------------------
/next_app/src/assets/icons/wAR.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betteridea-dev/ide/HEAD/next_app/src/assets/icons/wAR.png
--------------------------------------------------------------------------------
/next_app/src/assets/din-bhar-code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/betteridea-dev/ide/HEAD/next_app/src/assets/din-bhar-code.png
--------------------------------------------------------------------------------
/next_app/backend/cron.sh:
--------------------------------------------------------------------------------
1 |
2 | # move the analytics.db file to an archive folder every month and rename it to the date span it covers
3 | # TODO
--------------------------------------------------------------------------------
/next_app/postcss.config.mjs:
--------------------------------------------------------------------------------
1 | /** @type {import('postcss-load-config').Config} */
2 | const config = {
3 | plugins: {
4 | tailwindcss: {},
5 | },
6 | };
7 |
8 | export default config;
9 |
--------------------------------------------------------------------------------
/next_app/backend/routes/health/index.ts:
--------------------------------------------------------------------------------
1 | import { Router } from 'express';
2 |
3 | const router = Router();
4 |
5 | // Health check route
6 | router.get('/', (req, res) => {
7 | res.status(304).redirect("https://ide.betteridea.dev");
8 | });
9 |
10 | export default router;
--------------------------------------------------------------------------------
/next_app/src/components/sidebar/components/packages.tsx:
--------------------------------------------------------------------------------
1 | import { TSidebarItem } from ".";
2 | import { Blocks } from "lucide-react"
3 |
4 | const item:TSidebarItem = {
5 | icon: Blocks,
6 | label: "Packages",
7 | value: "PACKAGES"
8 | }
9 |
10 | export default item;
--------------------------------------------------------------------------------
/next_app/src/components/sidebar/components/projects.tsx:
--------------------------------------------------------------------------------
1 | import { TSidebarItem } from ".";
2 | import { FolderIcon } from "lucide-react"
3 |
4 | const item:TSidebarItem = {
5 | icon: FolderIcon,
6 | label: "Projects",
7 | value: "ALL_PROJECTS"
8 | }
9 |
10 | export default item;
--------------------------------------------------------------------------------
/next_app/src/components/sidebar/components/sqlite-explorer.tsx:
--------------------------------------------------------------------------------
1 | import { TSidebarItem } from ".";
2 | import { Database } from "lucide-react"
3 |
4 | const item:TSidebarItem = {
5 | icon: Database,
6 | label: "SQLite Explorer",
7 | value: "SQLITE_EXPLORER"
8 | }
9 |
10 | export default item;
--------------------------------------------------------------------------------
/next_app/src/components/sidebar/components/files.tsx:
--------------------------------------------------------------------------------
1 | import { TSidebarItem } from ".";
2 | import { Files } from "lucide-react"
3 | import { useGlobalState } from "@/hooks";
4 |
5 | const item:TSidebarItem = {
6 | icon: Files,
7 | label: "Files",
8 | value: "FILES"
9 | }
10 |
11 | export default item;
--------------------------------------------------------------------------------
/next_app/src/components/sidebar/components/marketplace.tsx:
--------------------------------------------------------------------------------
1 | import { TSidebarItem } from ".";
2 | import { Library, LibraryBig, Warehouse } from "lucide-react"
3 |
4 | const item: TSidebarItem = {
5 | icon: LibraryBig,
6 | label: "Template Marketplace",
7 | value: "MARKETPLACE"
8 | }
9 |
10 | export default item;
--------------------------------------------------------------------------------
/next_app/src/components/sidebar/components/sam.tsx:
--------------------------------------------------------------------------------
1 | import { TSidebarItem } from ".";
2 | import { SearchCode } from "lucide-react"
3 | import { useGlobalState } from "@/hooks";
4 |
5 | const item: TSidebarItem = {
6 | icon: SearchCode,
7 | label: "Auditing (beta)",
8 | value: "SAM"
9 | }
10 |
11 | export default item;
--------------------------------------------------------------------------------
/next_app/src/components/sidebar/components/interact.tsx:
--------------------------------------------------------------------------------
1 | import { TSidebarItem } from ".";
2 | import { Files, FlaskConical } from "lucide-react"
3 | import { useGlobalState } from "@/hooks";
4 |
5 | const item:TSidebarItem = {
6 | icon: FlaskConical,
7 | label: "Interact",
8 | value: "INTERACT"
9 | }
10 |
11 | export default item;
--------------------------------------------------------------------------------
/next_app/src/hooks/index.ts:
--------------------------------------------------------------------------------
1 | export { useGlobalState } from './useGlobalState';
2 | export { default as useProjectManager } from './useProjectManager';
3 | export { default as useProfile } from './profile';
4 | export { useUIState } from './useUIState';
5 | export { useEditorState } from './useEditorState';
6 | export { useAIState } from './useAIState';
7 |
--------------------------------------------------------------------------------
/next_app/src/components/ui/icons/war.tsx:
--------------------------------------------------------------------------------
1 | import Image from "next/image"
2 | import wARpng from "@/assets/icons/wAR.png"
3 |
4 | export default function WarpedAR({ width = 20, height = 20 }: { width?: number, height?: number }) {
5 | return
6 |
7 |
8 | }
--------------------------------------------------------------------------------
/next_app/src/assets/icons/run.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/next_app/src/components/ui/skeleton.tsx:
--------------------------------------------------------------------------------
1 | import { cn } from "@/lib/utils"
2 |
3 | function Skeleton({
4 | className,
5 | ...props
6 | }: React.HTMLAttributes) {
7 | return (
8 |
12 | )
13 | }
14 |
15 | export { Skeleton }
16 |
--------------------------------------------------------------------------------
/next_app/src/components/ui/icons/bazar.tsx:
--------------------------------------------------------------------------------
1 | import Image from "next/image"
2 | import bazarpng from "@/assets/icons/bazar.svg"
3 |
4 | export default function BazarIcon({ width = 20, height = 20 }: { width?: number, height?: number }) {
5 | return
6 |
7 |
8 | }
--------------------------------------------------------------------------------
/next_app/src/components/mobile/index.tsx:
--------------------------------------------------------------------------------
1 | export default function Mobile() {
2 | return
3 | Hi There!
Looks like you are using a mobile device.
Please use a desktop device to access the IDE.
4 |
Thank you!
~The developer
5 |
6 | }
--------------------------------------------------------------------------------
/next_app/src/components/theme-provider.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import { ThemeProvider as NextThemesProvider } from "next-themes"
5 | import { type ThemeProviderProps } from "next-themes/dist/types"
6 |
7 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
8 | return {children}
9 | }
10 |
--------------------------------------------------------------------------------
/next_app/src/components/views/components/_template.tsx:
--------------------------------------------------------------------------------
1 | import { TView } from "."
2 |
3 |
4 | function ViewComponent() {
5 | return
6 | Name
7 |
8 | }
9 |
10 | const viewItem: TView = {
11 | component: ViewComponent,
12 | label: "ViewName",
13 | value: null // udpate this and add to the list in ./index.ts
14 | }
15 |
16 | export default viewItem;
--------------------------------------------------------------------------------
/next_app/src/modules/ao/index.ts:
--------------------------------------------------------------------------------
1 | import {name as graphName,src as graphSrc} from "./graph"
2 | import { name as testName, src as testSrc } from "./test"
3 | import { name as dbAdminname, src as dbAdminSrc } from "./db-admin"
4 |
5 | const modules: {
6 | [foo:string]:string
7 | } = {
8 | [graphName]: graphSrc,
9 | [testName]: testSrc,
10 | [dbAdminname]: dbAdminSrc
11 | }
12 |
13 | export default modules
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | dist
3 | dist-*
4 |
5 | # Logs
6 | logs
7 | *.log
8 | npm-debug.log*
9 | yarn-debug.log*
10 | yarn-error.log*
11 | pnpm-debug.log*
12 | lerna-debug.log*
13 |
14 | node_modules
15 | dist
16 | dist-ssr
17 | *.local
18 |
19 | # Editor directories and files
20 | .vscode/*
21 | !.vscode/extensions.json
22 | .idea
23 | .DS_Store
24 | *.suo
25 | *.ntvs*
26 | *.njsproj
27 | *.sln
28 | *.sw?
29 |
30 | #
31 |
--------------------------------------------------------------------------------
/next_app/components.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ui.shadcn.com/schema.json",
3 | "style": "new-york",
4 | "rsc": false,
5 | "tsx": true,
6 | "tailwind": {
7 | "config": "tailwind.config.ts",
8 | "css": "src/styles/globals.css",
9 | "baseColor": "zinc",
10 | "cssVariables": true,
11 | "prefix": ""
12 | },
13 | "aliases": {
14 | "components": "@/components",
15 | "utils": "@/lib/utils"
16 | }
17 | }
--------------------------------------------------------------------------------
/next_app/src/pages/bounties.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 |
3 | export default function Bounties() {
4 | useEffect(() => {
5 | window.location.href = "https://betteridea.dev/bounties";
6 |
7 | }, [])
8 |
9 | return
10 | Loading Bounties... ⌛️
11 |
12 | }
--------------------------------------------------------------------------------
/next_app/src/components/views/index.tsx:
--------------------------------------------------------------------------------
1 | import { useGlobalState } from "@/hooks"
2 | import viewItems from "./components"
3 |
4 | export default function View() {
5 | const globalState = useGlobalState();
6 |
7 |
8 | return <>
9 | {
10 | viewItems.map((Item, i) => {
11 | return globalState.activeView==Item.value? :null
12 | })
13 | }
14 | >
15 | }
--------------------------------------------------------------------------------
/next_app/public/icon-black.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/next_app/public/icon.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/next_app/src/components/menubar/components/all-projects.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from "@/components/ui/button";
2 | import { useGlobalState } from "@/hooks";
3 |
4 | export default function AllProjectsBtn() {
5 | const globalState = useGlobalState()
6 |
7 | return
12 | }
--------------------------------------------------------------------------------
/next_app/src/components/drawer/index.tsx:
--------------------------------------------------------------------------------
1 | import { useGlobalState } from "@/hooks"
2 | import drawerItems from "./components"
3 |
4 | export default function SidebarDrawer() {
5 | const globalState = useGlobalState()
6 |
7 | return
8 | {
9 | drawerItems.map((item, i) => {
10 | return item.value == globalState.activeSidebarItem ? : null
11 | })
12 | }
13 |
14 | }
--------------------------------------------------------------------------------
/next_app/src/components/views/components/index.ts:
--------------------------------------------------------------------------------
1 | import Home from "./home"
2 | import Editor from "./editor"
3 | import Settings from "./settings"
4 | import AllProjects from "./all-projects"
5 | import Marketplace from "./marketplace"
6 |
7 | const viewItems: TView[] = [Home, Editor, Settings, AllProjects, Marketplace];
8 |
9 | export default viewItems;
10 |
11 | export type TView = {
12 | component: React.FC;
13 | label: string;
14 | value: TViewOptions;
15 | }
16 |
17 | export type TViewOptions = null | "ALL_PROJECTS" | "EDITOR" | "SETTINGS" | "MARKETPLACE";
--------------------------------------------------------------------------------
/next_app/backend/routes/analytics/referrers.ts:
--------------------------------------------------------------------------------
1 | import { Router } from 'express';
2 | import db from '../../db/database';
3 |
4 | const router = Router();
5 |
6 | // Get referrers analytics
7 | router.get('/', (req, res) => {
8 | db.all(`SELECT referrer, COUNT(*) as count FROM codecell_loads GROUP BY referrer ORDER BY count DESC`, (err, rows) => {
9 | if (err) {
10 | console.log(err);
11 | res.status(500).send(err);
12 | } else {
13 | res.status(200).send(rows);
14 | }
15 | });
16 | });
17 |
18 | export default router;
--------------------------------------------------------------------------------
/next_app/src/components/sidebar/components/ai-chat.tsx:
--------------------------------------------------------------------------------
1 | import { TSidebarItem } from ".";
2 | import { BotMessageSquare, MessageCircleHeart } from "lucide-react"
3 | import { useGlobalState } from "@/hooks";
4 |
5 | const item: TSidebarItem = {
6 | icon: () => (
7 |
8 |
9 |
10 | NEW
11 |
12 |
)
13 | ,
14 | label: "AO Companion",
15 | value: "AI_CHAT"
16 | }
17 |
18 | export default item;
--------------------------------------------------------------------------------
/next_app/backend/utils/helpers.ts:
--------------------------------------------------------------------------------
1 | // Helper function to construct prompt
2 | export function constructPrompt({ message, fileContext = "" }: { message: string, fileContext: string }) {
3 | let contextualPrompt = "";
4 |
5 | if (fileContext) {
6 | contextualPrompt += `File context: ${fileContext}\n`;
7 | }
8 |
9 | contextualPrompt += `\nUser message: ${message}`;
10 |
11 | contextualPrompt += `\n\nrespond as concise as possible`;
12 | return contextualPrompt;
13 | }
14 |
15 | // Helper function to calculate and log token usage
16 | export function calculateCost(tokens: number) {
17 | console.log(`Token usage: ${tokens}`);
18 | }
--------------------------------------------------------------------------------
/next_app/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | archive/
4 | dist-*
5 | .env
6 | ao-cookbook/
7 |
8 | # dependencies
9 | /node_modules
10 | /.pnp
11 | .pnp.js
12 | .yarn/install-state.gz
13 |
14 | # testing
15 | /coverage
16 |
17 | # next.js
18 | /.next/
19 | /out/
20 |
21 | # production
22 | /build
23 |
24 | # misc
25 | .DS_Store
26 | *.pem
27 |
28 | # debug
29 | npm-debug.log*
30 | yarn-debug.log*
31 | yarn-error.log*
32 |
33 | # local env files
34 | .env*.local
35 |
36 | # vercel
37 | .vercel
38 |
39 | # typescript
40 | *.tsbuildinfo
41 | next-env.d.ts
42 |
43 | analytics.db
44 |
45 | test.html
--------------------------------------------------------------------------------
/next_app/src/templates/index.ts:
--------------------------------------------------------------------------------
1 | import { source as aoBot } from "@/templates/ao/ao-bot";
2 | import { source as arInGrid } from "@/templates/ao/ar-in-arena";
3 | import { source as memeFrame } from "@/templates/ao/memeframe";
4 | import { source as LlamaComplainer } from "@/templates/ao/llama-complainer";
5 | import { source as FantasyLlama } from "@/templates/ao/fantasy-llama";
6 |
7 | export const AOTemplates = {
8 | "": 'print("Hello AO!")',
9 | "Reality Agent - Chatter": FantasyLlama,
10 | "Reality Agent - Complainer": LlamaComplainer,
11 | "Deathmatch Arena": arInGrid,
12 | "Deathmatch Bot": aoBot,
13 | "MemeFrame": memeFrame
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/next_app/src/components/drawer/components/index.ts:
--------------------------------------------------------------------------------
1 | import { TSidebarOptions } from "@/components/sidebar/components";
2 | import FileList from "./file-list";
3 | import ProjectList from "./project-list";
4 | import PackageList from "./package-list";
5 | import SQLite from "./sqlite-explorer"
6 | import Interact from "./interact"
7 | import Sam from "./sam"
8 | import Templates from "./marketplace"
9 |
10 | const drawerItems: TDrawerItem[] = [FileList, ProjectList, PackageList, SQLite, Interact, Sam, Templates];
11 |
12 | export default drawerItems;
13 |
14 | export type TDrawerItem = {
15 | component: React.FC;
16 | label: string;
17 | value: TSidebarOptions;
18 | }
--------------------------------------------------------------------------------
/lua/sharecode.lua:
--------------------------------------------------------------------------------
1 | -- LUA code that handles the share code feature of BetterIDEa.
2 | -- The _BETTERIDEA_SHARE variable is set to a base64 encoded string of the project data json.
3 | -- The handler Get-Better-IDEa-Share is dryrun and loaded into the IDE by upon visiting the share code link.
4 |
5 | _BETTERIDEA_SHARE = 'BASE64_ENCODED_STRING_OF_THE_PROJECT_DATA_JSON'
6 |
7 | Handlers.add(
8 | "Get-Better-IDEa-Share",
9 | Handlers.utils.hasMatchingTag("Action", "Get-BetterIDEa-Share"),
10 | function(msg)
11 | ao.send({ Target = msg.From, Action = "BetterIDEa-Share-Response", Data = _BETTERIDEA_SHARE })
12 | return _BETTERIDEA_SHARE
13 | end
14 | )
15 |
--------------------------------------------------------------------------------
/next_app/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "lib": [
4 | "dom",
5 | "dom.iterable",
6 | "esnext"
7 | ],
8 | "allowJs": true,
9 | "skipLibCheck": true,
10 | "strict": false,
11 | "noEmit": true,
12 | "esModuleInterop": true,
13 | "module": "esnext",
14 | "moduleResolution": "bundler",
15 | "resolveJsonModule": true,
16 | "isolatedModules": true,
17 | "jsx": "preserve",
18 | "incremental": true,
19 | "paths": {
20 | "@/*": [
21 | "./src/*"
22 | ]
23 | },
24 | "target": "ES2017"
25 | },
26 | "include": [
27 | "next-env.d.ts",
28 | "**/*.ts",
29 | "**/*.tsx",
30 | "backend/index.ts"
31 | ],
32 | "exclude": [
33 | "node_modules"
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/next_app/backend/types.ts:
--------------------------------------------------------------------------------
1 | export type TBody = {
2 | action: "codecell_load" | "codecell_run"
3 | cellId: string
4 | userId: string
5 | appName: string
6 | messageId?: string
7 | referrer: string
8 | geo?: {
9 | country?: string
10 | countryCode?: string
11 | region?: string
12 | regionName?: string
13 | city?: string
14 | zip?: string
15 | lat?: number
16 | lon?: number
17 | timezone?: string
18 | isp?: string
19 | org?: string
20 | as?: string
21 | query?: string
22 | }
23 | }
24 |
25 | export type ChatRequest = {
26 | message: string
27 | fileContext?: string
28 | chat: Array<{ role: string, content: string }>
29 | model: string
30 | }
--------------------------------------------------------------------------------
/next_app/public/images/chat.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/next_app/src/components/ui/label.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import * as LabelPrimitive from "@radix-ui/react-label"
3 | import { cva, type VariantProps } from "class-variance-authority"
4 |
5 | import { cn } from "@/lib/utils"
6 |
7 | const labelVariants = cva(
8 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
9 | )
10 |
11 | const Label = React.forwardRef<
12 | React.ElementRef,
13 | React.ComponentPropsWithoutRef &
14 | VariantProps
15 | >(({ className, ...props }, ref) => (
16 |
21 | ))
22 | Label.displayName = LabelPrimitive.Root.displayName
23 |
24 | export { Label }
25 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: ankushKun
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
12 | polar: # Replace with a single Polar username
13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
14 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
15 |
--------------------------------------------------------------------------------
/next_app/next.config.mjs:
--------------------------------------------------------------------------------
1 | import { execSync } from "child_process";
2 | import packageJson from "./package.json" with { type: "json" };
3 | import NodePolyfillPlugin from "node-polyfill-webpack-plugin"
4 |
5 | // fetch local gitHash
6 | const gitHash = execSync("git rev-parse --short HEAD").toString().trim();
7 |
8 |
9 | /** @type {import('next').NextConfig} */
10 | const nextConfig = {
11 | reactStrictMode: true,
12 | output: "export",
13 | images: { unoptimized: true },
14 | basePath: "",
15 | env: {
16 | version: packageJson.version,
17 | gitHash: gitHash,
18 | },
19 | webpack: (config, { isServer }) => {
20 | // Only apply this plugin on the client-side bundle
21 | if (!isServer) {
22 | config.plugins.push(new NodePolyfillPlugin());
23 | }
24 | return config;
25 | }
26 | };
27 |
28 | export default nextConfig;
29 |
--------------------------------------------------------------------------------
/next_app/src/components/ui/textarea.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | import { cn } from "@/lib/utils"
4 |
5 | export interface TextareaProps
6 | extends React.TextareaHTMLAttributes {}
7 |
8 | const Textarea = React.forwardRef(
9 | ({ className, ...props }, ref) => {
10 | return (
11 |
19 | )
20 | }
21 | )
22 | Textarea.displayName = "Textarea"
23 |
24 | export { Textarea }
25 |
--------------------------------------------------------------------------------
/next_app/src/assets/icons/loading.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/next_app/src/components/sidebar/components/index.ts:
--------------------------------------------------------------------------------
1 | import { LucideIcon } from 'lucide-react';
2 |
3 | import Files from "./files";
4 | import AllProjects from "./projects";
5 | import Packages from "./packages";
6 | import SQLite from "./sqlite-explorer"
7 | import Interact from "./interact"
8 | import Sam from "./sam"
9 | import Templates from "./marketplace"
10 | import AiChat from "./ai-chat"
11 |
12 | export type TSidebarItem = {
13 | icon: LucideIcon | ((props: React.SVGProps) => JSX.Element);
14 | label: string;
15 | value: TSidebarOptions;
16 | }
17 |
18 | const sidebarItems: TSidebarItem[] = [Files, Packages, SQLite, Interact, Sam, Templates, AiChat];
19 |
20 | export default sidebarItems;
21 | export type TSidebarOptions = null | "SETTINGS" | "FILES" | "ALL_PROJECTS" | "PACKAGES" | "SQLITE_EXPLORER" | "INTERACT" | "SAM" | "MARKETPLACE" | "AI_CHAT";
--------------------------------------------------------------------------------
/next_app/src/components/ui/separator.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import * as SeparatorPrimitive from "@radix-ui/react-separator"
3 |
4 | import { cn } from "@/lib/utils"
5 |
6 | const Separator = React.forwardRef<
7 | React.ElementRef,
8 | React.ComponentPropsWithoutRef
9 | >(
10 | (
11 | { className, orientation = "horizontal", decorative = true, ...props },
12 | ref
13 | ) => (
14 |
25 | )
26 | )
27 | Separator.displayName = SeparatorPrimitive.Root.displayName
28 |
29 | export { Separator }
30 |
--------------------------------------------------------------------------------
/next_app/backend/index.ts:
--------------------------------------------------------------------------------
1 | import express from 'express';
2 | import cors from 'cors';
3 | import "dotenv/config";
4 |
5 | // Import routes
6 | import healthRoutes from './routes/health';
7 | import analyticsRoutes from './routes/analytics';
8 | import chatRoutes from './routes/chat';
9 | import systemRoutes from './routes/system';
10 |
11 | // Initialize express app
12 | const app = express();
13 | app.use(express.json());
14 | app.use(cors());
15 |
16 | // Define port
17 | const port = process.env.PORT || 3001;
18 |
19 | // Register routes
20 | app.use('/', healthRoutes);
21 | app.use('/analytics', analyticsRoutes);
22 | app.use('/chat', chatRoutes);
23 | app.use('/system', systemRoutes);
24 |
25 | // CORS options for specific routes
26 | app.options("/complete", cors());
27 | app.options("/chat", cors());
28 |
29 | // Start server
30 | app.listen(port, () => {
31 | console.log(`Server running at http://localhost:${port}`);
32 | });
--------------------------------------------------------------------------------
/next_app/src/components/ui/toaster.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | Toast,
3 | ToastClose,
4 | ToastDescription,
5 | ToastProvider,
6 | ToastTitle,
7 | ToastViewport,
8 | } from "@/components/ui/toast"
9 | import { useToast } from "@/components/ui/use-toast"
10 |
11 | export function Toaster() {
12 | const { toasts } = useToast()
13 |
14 | return (
15 |
16 | {toasts.map(function ({ id, title, description, action, ...props }) {
17 | return (
18 |
19 |
20 | {title && {title}}
21 | {description && (
22 | {description}
23 | )}
24 |
25 | {action}
26 |
27 |
28 | )
29 | })}
30 |
31 |
32 | )
33 | }
34 |
--------------------------------------------------------------------------------
/next_app/src/components/ui/input.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | import { cn } from "@/lib/utils"
4 |
5 | export interface InputProps
6 | extends React.InputHTMLAttributes { }
7 |
8 | const Input = React.forwardRef(
9 | ({ className, type, ...props }, ref) => {
10 | return (
11 |
20 | )
21 | }
22 | )
23 | Input.displayName = "Input"
24 |
25 | export { Input }
26 |
--------------------------------------------------------------------------------
/next_app/src/components/ui/sonner.tsx:
--------------------------------------------------------------------------------
1 | import { useTheme } from "next-themes"
2 | import { Toaster as Sonner } from "sonner"
3 |
4 | type ToasterProps = React.ComponentProps
5 |
6 | const Toaster = ({ ...props }: ToasterProps) => {
7 | const { theme = "system" } = useTheme()
8 |
9 | return (
10 |
26 | )
27 | }
28 |
29 | export { Toaster }
30 |
--------------------------------------------------------------------------------
/next_app/backend/db/database.ts:
--------------------------------------------------------------------------------
1 | import sqlite3 from 'sqlite3';
2 |
3 | // Initialize database
4 | sqlite3.verbose();
5 | const db = new sqlite3.Database('./analytics.db');
6 |
7 | // Create tables if they don't exist
8 | const codecell_load_table = `CREATE TABLE IF NOT EXISTS codecell_loads (
9 | timestamp NUMBER,
10 | userId TEXT,
11 | appName TEXT,
12 | referrer TEXT,
13 | country TEXT,
14 | countryCode TEXT,
15 | region TEXT,
16 | regionName TEXT,
17 | city TEXT,
18 | isp TEXT,
19 | org TEXT,
20 | as_ TEXT
21 | )`;
22 | db.run(codecell_load_table);
23 |
24 | const codecell_run_table = `CREATE TABLE IF NOT EXISTS codecell_runs (
25 | timestamp NUMBER,
26 | userId TEXT,
27 | appName TEXT,
28 | messageId TEXT,
29 | referrer TEXT,
30 | country TEXT,
31 | countryCode TEXT,
32 | region TEXT,
33 | regionName TEXT,
34 | city TEXT,
35 | isp TEXT,
36 | org TEXT,
37 | as_ TEXT
38 | )`;
39 | db.run(codecell_run_table);
40 |
41 | export default db;
--------------------------------------------------------------------------------
/next_app/src/components/menubar/components/duplicate-project.tsx:
--------------------------------------------------------------------------------
1 | import { useGlobalState, useProjectManager } from "@/hooks";
2 | import { toast } from "sonner";
3 |
4 | export default function DuplicateProject() {
5 | const globalState = useGlobalState();
6 | const manager = useProjectManager();
7 |
8 | function duplicateProject() {
9 | const project = manager.getProject(globalState.activeProject);
10 | if (!project) return;
11 | const duplicatedName = `copy - ${project.name}`;
12 | manager.newProject({
13 | name: duplicatedName,
14 | defaultFiletype: project.defaultFiletype,
15 | files: project.files,
16 | ownerWallet: project.ownerWallet,
17 | });
18 | const dupProject = manager.getProject(duplicatedName)
19 | manager.setProjectProcess(dupProject, project.process)
20 | toast.success("Project duplicated")
21 | }
22 |
23 | return duplicate project
24 | }
--------------------------------------------------------------------------------
/next_app/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import Layout from "@/components/layout";
3 | import Mobile from "@/components/mobile";
4 | import { useRouter } from "next/router";
5 | import TxRenderer from "@/pages/renderer";
6 | import { useKeyBinds } from "@/utils/keybinds";
7 | export default function Home() {
8 | const [isMobile, setIsMobile] = useState(false);
9 | const router = useRouter()
10 | const { tx } = router.query
11 | useKeyBinds()
12 |
13 | useEffect(() => {
14 | if (typeof window !== "undefined") {
15 | const userAgent = typeof window.navigator === "undefined" ? "bot" : navigator.userAgent;
16 | const isMobile = Boolean(userAgent.match(
17 | /Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile|WPDesktop/i
18 | ));
19 | setIsMobile(isMobile);
20 | }
21 | }, []);
22 |
23 | if (tx) {
24 | return
25 | }
26 |
27 | return isMobile ? :
28 |
29 |
30 |
31 | }
--------------------------------------------------------------------------------
/next_app/src/modules/ao/test.ts:
--------------------------------------------------------------------------------
1 | export const name = `Test`
2 | export const src = `
3 | local Test = {}
4 | Test.__index = Test
5 |
6 | function Test.new(name)
7 | local self = setmetatable({}, Test)
8 | self.name = name
9 | self.tests = {}
10 | return self
11 | end
12 |
13 | function Test:add(name, func)
14 | table.insert(self.tests, { name = name, func = func })
15 | end
16 |
17 | function Test:run()
18 | local output = ""
19 | local out = function (txt)
20 | output = output .. txt .. '\\n'
21 | end
22 | out("Running tests for " .. self.name)
23 | local passed = 0
24 | local failed = 0
25 | for _, test in ipairs(self.tests) do
26 | local status, err = pcall(test.func)
27 | if status then
28 | out("✔ " .. test.name)
29 | passed = passed + 1
30 | else
31 | out("✘ " .. test.name .. ": " .. err)
32 | failed = failed + 1
33 | end
34 | end
35 | out(string.format("Passed: %d, Failed: %d", passed, failed))
36 | return output
37 | end
38 |
39 | return Test
40 | `
--------------------------------------------------------------------------------
/next_app/backend/routes/system/index.ts:
--------------------------------------------------------------------------------
1 | import { Router } from 'express';
2 | import { execSync } from 'child_process';
3 |
4 | const router = Router();
5 |
6 | // System information route
7 | router.get('/', (req, res) => {
8 | // Execute screenfetch and strip ANSI escape codes
9 | const screenfetch = execSync('screenfetch -n')
10 | .toString()
11 | .replace(/\u001b\[[0-9;]*m/g, '') // Remove ANSI color codes
12 | .replace(/\u001b\[\d+[A-Z]/g, ''); // Remove ANSI control sequences
13 |
14 | // Extract system information using regex
15 | const cpuMatch = screenfetch.match(/CPU:\s*(.*)/);
16 | const ramMatch = screenfetch.match(/RAM:\s*(.*)/);
17 | const diskMatch = screenfetch.match(/Disk:\s*(.*)/);
18 | const osMatch = screenfetch.match(/OS:\s*(.*)/);
19 |
20 | const systemInfo = {
21 | cpu: cpuMatch ? cpuMatch[1].trim() : null,
22 | ram: ramMatch ? ramMatch[1].trim() : null,
23 | disk: diskMatch ? diskMatch[1].trim() : null,
24 | os: osMatch ? osMatch[1].trim() : null
25 | };
26 |
27 | res.json(systemInfo);
28 | });
29 |
30 | export default router;
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Ankush Singh
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/next_app/backend/utils/modelConfig.ts:
--------------------------------------------------------------------------------
1 | import { GoogleGenerativeAI } from "@google/generative-ai";
2 | import { SYSTEM_PROMPT, SYSTEM_PROMPT_SMALL } from "../systemPrompt";
3 | import "dotenv/config";
4 |
5 | // Available models
6 | export const availableModels = {
7 | "Deepseek R1": "deepseek-r1-distill-llama-70b",
8 | "Gemini 2.0 FL (high context)": "gemini-2.0-flash-lite",
9 | // "Qwen 2.5 coder": "qwen-2.5-coder-32b",
10 | "Llama 3": "llama3-70b-8192",
11 | "Llama 3.3 70b": "llama-3.3-70b-versatile",
12 | "Gemma 2": "gemma2-9b-it"
13 | };
14 |
15 | // Models that need larger context
16 | export const largeModels = ["gemini-2.0-flash-lite"];
17 |
18 | // Initialize the Google AI client
19 | const apiKey = process.env.GEMINI_API_KEY;
20 | export const genAI = new GoogleGenerativeAI(apiKey);
21 |
22 | export const gemini = genAI.getGenerativeModel({
23 | model: "gemini-2.0-flash-lite",
24 | systemInstruction: SYSTEM_PROMPT,
25 | generationConfig: {
26 | temperature: 1,
27 | topP: 0.95,
28 | topK: 40,
29 | maxOutputTokens: 8192,
30 | responseMimeType: "text/plain"
31 | }
32 | });
--------------------------------------------------------------------------------
/next_app/src/components/menubar/components/duplicate-file.tsx:
--------------------------------------------------------------------------------
1 | import { useGlobalState, useProjectManager } from "@/hooks";
2 | import { toast } from "sonner";
3 |
4 | export default function DuplicateFile() {
5 | const globalState = useGlobalState();
6 | const manager = useProjectManager();
7 |
8 | function duplicateFile() {
9 | const project = manager.getProject(globalState.activeProject);
10 | if (!project) return;
11 | const file = project?.files[globalState.activeFile];
12 | if(!file) return;
13 | const duplicatedName = `copy - ${file.name}`;
14 | manager.newFile(project, {
15 | name: duplicatedName,
16 | type: file.type,
17 | })
18 | const dupFile = project.getFile(duplicatedName)
19 | dupFile.content = file.content
20 | project.files[duplicatedName] = dupFile
21 | manager.projects[project.name] = project
22 | manager.saveProjects(manager.projects)
23 | toast.success("File duplicated")
24 | }
25 |
26 | return duplicate file
27 | }
--------------------------------------------------------------------------------
/next_app/src/modules/ao/db-admin.ts:
--------------------------------------------------------------------------------
1 | export const name = "DbAdmin"
2 | export const src = `
3 | local dbAdmin = {}
4 | dbAdmin.__index = dbAdmin
5 |
6 | -- Function to create a new database explorer instance
7 | function dbAdmin.new(db)
8 | local self = setmetatable({}, dbAdmin)
9 | self.db = db
10 | return self
11 | end
12 |
13 | -- Function to list all tables in the database
14 | function dbAdmin:tables()
15 | local tables = {}
16 | for row in self.db:nrows("SELECT name FROM sqlite_master WHERE type='table';") do
17 | table.insert(tables, row.name)
18 | end
19 | return tables
20 | end
21 |
22 | -- Function to get the record count of a table
23 | function dbAdmin:count(tableName)
24 | local count_query = string.format("SELECT COUNT(*) AS count FROM %s;", tableName)
25 | for row in self.db:nrows(count_query) do
26 | return row.count
27 | end
28 | end
29 |
30 | -- Function to execute a given SQL query
31 | function dbAdmin:exec(sql)
32 | local results = {}
33 | for row in self.db:nrows(sql) do
34 | table.insert(results, row)
35 | end
36 | return results
37 | end
38 |
39 | return dbAdmin
40 | `
--------------------------------------------------------------------------------
/next_app/src/components/menubar/components/download-file.tsx:
--------------------------------------------------------------------------------
1 | import { useGlobalState, useProjectManager } from "@/hooks"
2 |
3 | export default function DownloadFile() {
4 | const globalState = useGlobalState()
5 | const manager = useProjectManager()
6 |
7 | const project = globalState.activeProject && manager.getProject(globalState.activeProject)
8 | const file = globalState.activeFile &&globalState.activeProject && project?.getFile(globalState.activeFile)
9 |
10 |
11 | function downloadFile() {
12 | if (project && file) {
13 | const fname = file.name
14 | // NEED BETTER FILE CONTENT HANDLING
15 | const content = file.name.endsWith(".luanb")?JSON.stringify(file,null,2):file.content.cells[0].code
16 | const blob = new Blob([JSON.stringify(content)], { type: 'application/json' });
17 | const url = URL.createObjectURL(blob);
18 | const a = document.createElement('a');
19 | a.href = url;
20 | a.download = fname;
21 | a.click();
22 | }
23 | }
24 |
25 | return download file
26 | }
--------------------------------------------------------------------------------
/next_app/src/components/ui/checkbox.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
3 | import { Check } from "lucide-react"
4 |
5 | import { cn } from "@/lib/utils"
6 |
7 | const Checkbox = React.forwardRef<
8 | React.ElementRef,
9 | React.ComponentPropsWithoutRef
10 | >(({ className, ...props }, ref) => (
11 |
19 |
22 |
23 |
24 |
25 | ))
26 | Checkbox.displayName = CheckboxPrimitive.Root.displayName
27 |
28 | export { Checkbox }
29 |
--------------------------------------------------------------------------------
/next_app/src/components/ui/switch.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import * as SwitchPrimitives from "@radix-ui/react-switch"
3 |
4 | import { cn } from "@/lib/utils"
5 |
6 | const Switch = React.forwardRef<
7 | React.ElementRef,
8 | React.ComponentPropsWithoutRef
9 | >(({ className, ...props }, ref) => (
10 |
18 |
23 |
24 | ))
25 | Switch.displayName = SwitchPrimitives.Root.displayName
26 |
27 | export { Switch }
28 |
--------------------------------------------------------------------------------
/next_app/src/components/ui/tooltip.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import * as TooltipPrimitive from "@radix-ui/react-tooltip"
3 |
4 | import { cn } from "@/lib/utils"
5 |
6 | const TooltipProvider = TooltipPrimitive.Provider
7 |
8 | const Tooltip = TooltipPrimitive.Root
9 |
10 | const TooltipTrigger = TooltipPrimitive.Trigger
11 |
12 | const TooltipContent = React.forwardRef<
13 | React.ElementRef,
14 | React.ComponentPropsWithoutRef
15 | >(({ className, sideOffset = 4, ...props }, ref) => (
16 |
25 | ))
26 | TooltipContent.displayName = TooltipPrimitive.Content.displayName
27 |
28 | export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
29 |
--------------------------------------------------------------------------------
/next_app/src/components/views/components/editor/components/output.tsx:
--------------------------------------------------------------------------------
1 | import { useGlobalState, useProjectManager } from "@/hooks"
2 | import Ansi from "ansi-to-react"
3 | import Markdown from "react-markdown"
4 | import remarkGfm from "remark-gfm"
5 |
6 | export default function Output() {
7 | const globalState = useGlobalState()
8 | const manager = useProjectManager()
9 |
10 | const project = globalState.activeProject && manager.getProject(globalState.activeProject)
11 | const file = project && project.getFile(globalState.activeFile)
12 | const extension = file && file.name.split(".").pop()
13 |
14 | const output = extension == "md"? file.content.cells[0].code : globalState.lastOutput
15 |
16 | return <>
17 | {
18 | output ?
19 | {extension == "md" ?
21 | }} className="markdown">{output}:{output}}
22 | :
23 | Run lua to get output
24 |
25 | }
26 | >
27 | }
--------------------------------------------------------------------------------
/.github/workflows/sync-to-protocol-land.yml:
--------------------------------------------------------------------------------
1 | name: Archive
2 | on:
3 | workflow_dispatch:
4 | jobs:
5 | build:
6 | runs-on: ubuntu-latest
7 | steps:
8 | - name: 'Checkout repo (default branch)'
9 | uses: actions/checkout@v3
10 | with:
11 | # fetch all history for all branches:
12 | fetch-depth: 0
13 | - name: 'Checkout all branches'
14 | run: |
15 | default_branch=$(git branch | grep '*' | sed 's/\* //')
16 | for abranch in $(git branch -a | grep -v HEAD | grep remotes | sed "s/remotes\/origin\///g"); do git checkout $abranch ; done
17 | git checkout $default_branch
18 | git branch -a
19 | - name: 'Setup node 18'
20 | uses: actions/setup-node@v3
21 | with:
22 | node-version: 18.x
23 | - name: 'Sync repo to Protocol Land'
24 | run: npx @protocol.land/sync@0.3.0
25 | env:
26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27 | REPO_TITLE: ${{ github.event.repository.name }}
28 | REPO_DESCRIPTION: ${{ github.event.repository.description }}
29 | WALLET: ${{ secrets.WALLET }}
30 |
--------------------------------------------------------------------------------
/next_app/src/hooks/useUIState.ts:
--------------------------------------------------------------------------------
1 | import { create } from "zustand";
2 | import { TSidebarOptions } from "@/components/sidebar/components";
3 |
4 | interface UIState {
5 | // Sidebar state
6 | activeSidebarItem: TSidebarOptions;
7 | isSidebarCollapsed: boolean;
8 |
9 | // Theme state
10 | theme: 'light' | 'dark' | 'system';
11 |
12 | // Mobile view state
13 | isMobileMenuOpen: boolean;
14 |
15 | // Methods
16 | setActiveSidebarItem: (item: TSidebarOptions) => void;
17 | toggleSidebar: () => void;
18 | setTheme: (theme: 'light' | 'dark' | 'system') => void;
19 | toggleMobileMenu: () => void;
20 | setMobileMenuOpen: (isOpen: boolean) => void;
21 | }
22 |
23 | export const useUIState = create((set) => ({
24 | // Initial state
25 | activeSidebarItem: "FILES",
26 | isSidebarCollapsed: false,
27 | theme: 'dark',
28 | isMobileMenuOpen: false,
29 |
30 | // Methods
31 | setActiveSidebarItem: (item: TSidebarOptions) => set({ activeSidebarItem: item }),
32 | toggleSidebar: () => set((state) => ({ isSidebarCollapsed: !state.isSidebarCollapsed })),
33 | setTheme: (theme) => set({ theme }),
34 | toggleMobileMenu: () => set((state) => ({ isMobileMenuOpen: !state.isMobileMenuOpen })),
35 | setMobileMenuOpen: (isOpen) => set({ isMobileMenuOpen: isOpen }),
36 | }));
--------------------------------------------------------------------------------
/next_app/src/components/ui/popover.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import * as PopoverPrimitive from "@radix-ui/react-popover"
3 |
4 | import { cn } from "@/lib/utils"
5 |
6 | const Popover = PopoverPrimitive.Root
7 |
8 | const PopoverTrigger = PopoverPrimitive.Trigger
9 |
10 | const PopoverContent = React.forwardRef<
11 | React.ElementRef,
12 | React.ComponentPropsWithoutRef
13 | >(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
14 |
15 |
25 |
26 | ))
27 | PopoverContent.displayName = PopoverPrimitive.Content.displayName
28 |
29 | export { Popover, PopoverTrigger, PopoverContent }
30 |
--------------------------------------------------------------------------------
/next_app/src/components/menubar/components/download.tsx:
--------------------------------------------------------------------------------
1 | import { useGlobalState, useProjectManager } from "@/hooks";
2 | import JSZip from "jszip";
3 |
4 | export default function Download() {
5 | const globalState = useGlobalState();
6 | const projectManager = useProjectManager();
7 |
8 | function downloadProject() {
9 | const project = projectManager.getProject(globalState.activeProject);
10 | if (!project) return;
11 | const { files } = project;
12 | console.log(files)
13 | const fileContents = Object.values(files);
14 | const zip = new JSZip();
15 | fileContents.forEach(file => {
16 | console.log(file)
17 | // const fileName = file.name.split(".")[0] + ".luanb";
18 | const fileName = file.name;
19 | const contents = file.name.endsWith(".luanb") ? JSON.stringify(file) : file.content.cells[0].code;
20 | zip.file(fileName, contents);
21 | })
22 | zip.generateAsync({ type: "blob" }).then((blob) => {
23 | const url = URL.createObjectURL(blob);
24 | const a = document.createElement("a");
25 | a.href = url;
26 | a.download = `${globalState.activeProject}.zip`;
27 | a.click();
28 | })
29 |
30 | }
31 |
32 | return download
33 | }
--------------------------------------------------------------------------------
/next_app/src/templates/ao/fantasy-llama.ts:
--------------------------------------------------------------------------------
1 | export const source = `-- Name: FantasyLlama
2 |
3 | CHAT_TARGET = CHAT_TARGET or 'TODO: Put your world ID here'
4 |
5 | -- To add this agent to your world, configure your Static Entities table, e.g.:
6 | -- RealityEntitiesStatic = {
7 | -- [''] = {
8 | -- Position = { 10, 10 },
9 | -- Type = 'Avatar',
10 | -- Metadata = {
11 | -- DisplayName = 'Fantasy Llama',
12 | -- SkinNumber = 5,
13 | -- Interaction = {
14 | -- Type = 'Default',
15 | -- },
16 | -- },
17 | -- },
18 | -- }
19 |
20 | TIMESTAMP_LAST_MESSAGE_MS = TIMESTAMP_LAST_MESSAGE_MS or 0
21 |
22 | -- Limit sending a message to every so often
23 | COOLDOWN_MS = 10000 -- 10 seconds
24 |
25 | Handlers.add(
26 | 'DefaultInteraction',
27 | Handlers.utils.hasMatchingTag('Action', 'DefaultInteraction'),
28 | function(msg)
29 | print('DefaultInteraction')
30 | if ((msg.Timestamp - TIMESTAMP_LAST_MESSAGE_MS) < COOLDOWN_MS) then
31 | return print("Message on cooldown")
32 | end
33 |
34 | Send({
35 | Target = CHAT_TARGET,
36 | Tags = {
37 | Action = 'ChatMessage',
38 | ['Author-Name'] = 'Fantasy Llama',
39 | },
40 | Data =
41 | "Where on earth did you come from? I heard if you take the blue p...otion, you'll be able to return to your world.",
42 | })
43 |
44 | TIMESTAMP_LAST_MESSAGE_MS = msg.Timestamp
45 | end
46 | )`
--------------------------------------------------------------------------------
/next_app/src/components/ui/custom/switch.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as SwitchPrimitives from "@radix-ui/react-switch";
3 |
4 | import { cn } from "@/lib/utils";
5 |
6 | const SwitchCustom = React.forwardRef, React.ComponentPropsWithoutRef>(({ className, ...props }, ref) => (
7 |
8 | ao
9 | Warp
10 |
11 |
12 | ));
13 | SwitchCustom.displayName = SwitchPrimitives.Root.displayName + "Custom";
14 |
15 | export { SwitchCustom };
16 |
--------------------------------------------------------------------------------
/next_app/backend/inlineSystemPrompt.ts:
--------------------------------------------------------------------------------
1 |
2 | export const INLINE_SYSTEM_PROMPT = `INLINE AUTOCOMPLETE SYSTEM INSTRUCTIONS
3 |
4 | 1. CONTEXT AWARENESS
5 | -------------------
6 | - You are an inline code completion tool specialized in AO/aos development
7 | - You understand the Lua programming language with AO-specific extensions
8 | - You have knowledge of the AO message-based architecture and process system
9 | - You are aware of all built-in modules, globals, and standard patterns
10 |
11 | 2. COMPLETION PRIORITIES
12 | ----------------------
13 | a) Always prioritize completions in this order:
14 | 1. Built-in AO globals (ao, Handlers, Inbox, etc.)
15 | 2. Standard Lua syntax
16 | 3. Common AO patterns
17 | 4. User-defined variables in current scope
18 |
19 | b) For message construction, prioritize:
20 | 1. Required fields (Target, Action)
21 | 2. Common Tags
22 | 3. Optional fields (Data, etc.)
23 |
24 | 3. HANDLER COMPLETIONS
25 | --------------------
26 | - When detecting \`Handlers.add\`, automatically suggest three-parameter structure
27 | - Always include function parameter names in handler completions
28 | - Suggest common matcher patterns after handler name
29 | - Include documentation comments for complex handlers
30 |
31 | Example completion pattern:
32 | \`\`\`lua
33 | Handlers.add("name",
34 | function (msg)
35 | return msg.▋ // Suggest: Action, Tags, From, Data
36 | end,
37 | function (msg)
38 | ▋ // Suggest: ao.send, assert, common patterns
39 | end
40 | )`
--------------------------------------------------------------------------------
/next_app/src/pages/dev.tsx:
--------------------------------------------------------------------------------
1 | import { CodeCell, getInbox } from "@betteridea/codecell";
2 | import Ansi from "ansi-to-react";
3 | import { useState } from "react";
4 | import { toast } from "sonner";
5 |
6 | export default function Dev() {
7 | const devMode = typeof window == "undefined" ? true : window.location.hostname === "localhost";
8 | const [inbox, setInbox] = useState();
9 |
10 | return (
11 |
12 |
13 |
{
20 | message.forEach((m) => {
21 | if (m.Output)
22 | if (m.Output.print)
23 | // console.log(m.Output.data)
24 | toast.custom(() => {m.Output.data})
25 | })
26 | }}
27 | onAOProcess={(ao) => console.log("got process", ao)}
28 | onInbox={(inbox) => setInbox(inbox)}
29 | />
30 |
31 | {JSON.stringify(inbox, null, 2)}
32 |
33 |
34 | )
35 | }
36 |
--------------------------------------------------------------------------------
/next_app/src/utils/keybinds.ts:
--------------------------------------------------------------------------------
1 | import { useGlobalState } from '@/hooks'
2 | import { KeyboardEvent, useEffect } from 'react'
3 |
4 | export type Shortcut = {
5 | code: string,
6 | metaKey?: boolean,
7 | altKey?: boolean,
8 | shiftKey?: boolean,
9 | ctrlKey?: boolean,
10 | callback: () => void
11 | }
12 |
13 | export function useKeyBinds() {
14 | const { setIsAiPanelOpen, isAiPanelOpen } = useGlobalState()
15 |
16 | const shortcuts: { [key: string]: Shortcut } = {
17 | "open-ai-panel": {
18 | code: "KeyB",
19 | metaKey: true,
20 | altKey: true,
21 | callback: () => {
22 | setIsAiPanelOpen(!isAiPanelOpen)
23 | }
24 | }
25 | }
26 |
27 | function setupKeyBinds() {
28 | function onKeyDown(e: globalThis.KeyboardEvent) {
29 |
30 | const shortcut = Object.values(shortcuts).find(shortcut =>
31 | shortcut.code === e.code &&
32 | shortcut.metaKey === e.metaKey &&
33 | shortcut.altKey === e.altKey
34 | )
35 |
36 | if (shortcut) {
37 | e.preventDefault()
38 | console.log("shortcut found", shortcut)
39 | shortcut.callback()
40 | }
41 | }
42 |
43 | document.addEventListener("keydown", onKeyDown)
44 |
45 | return () => {
46 | document.removeEventListener("keydown", onKeyDown)
47 | }
48 | }
49 |
50 | useEffect(() => {
51 | return setupKeyBinds()
52 | }, [isAiPanelOpen])
53 | }
--------------------------------------------------------------------------------
/next_app/src/components/ui/avatar.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import * as AvatarPrimitive from "@radix-ui/react-avatar"
3 |
4 | import { cn } from "@/lib/utils"
5 |
6 | const Avatar = React.forwardRef<
7 | React.ElementRef,
8 | React.ComponentPropsWithoutRef
9 | >(({ className, ...props }, ref) => (
10 |
18 | ))
19 | Avatar.displayName = AvatarPrimitive.Root.displayName
20 |
21 | const AvatarImage = React.forwardRef<
22 | React.ElementRef,
23 | React.ComponentPropsWithoutRef
24 | >(({ className, ...props }, ref) => (
25 |
30 | ))
31 | AvatarImage.displayName = AvatarPrimitive.Image.displayName
32 |
33 | const AvatarFallback = React.forwardRef<
34 | React.ElementRef,
35 | React.ComponentPropsWithoutRef
36 | >(({ className, ...props }, ref) => (
37 |
45 | ))
46 | AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
47 |
48 | export { Avatar, AvatarImage, AvatarFallback }
49 |
--------------------------------------------------------------------------------
/next_app/src/components/ui/toggle.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import * as TogglePrimitive from "@radix-ui/react-toggle"
3 | import { cva, type VariantProps } from "class-variance-authority"
4 |
5 | import { cn } from "@/lib/utils"
6 |
7 | const toggleVariants = cva(
8 | "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground",
9 | {
10 | variants: {
11 | variant: {
12 | default: "bg-transparent",
13 | outline:
14 | "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground",
15 | },
16 | size: {
17 | default: "h-10 px-3",
18 | sm: "h-9 px-2.5",
19 | lg: "h-11 px-5",
20 | },
21 | },
22 | defaultVariants: {
23 | variant: "default",
24 | size: "default",
25 | },
26 | }
27 | )
28 |
29 | const Toggle = React.forwardRef<
30 | React.ElementRef,
31 | React.ComponentPropsWithoutRef &
32 | VariantProps
33 | >(({ className, variant, size, ...props }, ref) => (
34 |
39 | ))
40 |
41 | Toggle.displayName = TogglePrimitive.Root.displayName
42 |
43 | export { Toggle, toggleVariants }
44 |
--------------------------------------------------------------------------------
/next_app/src/components/ui/radio-group.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
3 | import { Circle } from "lucide-react"
4 |
5 | import { cn } from "@/lib/utils"
6 |
7 | const RadioGroup = React.forwardRef<
8 | React.ElementRef,
9 | React.ComponentPropsWithoutRef
10 | >(({ className, ...props }, ref) => {
11 | return (
12 |
17 | )
18 | })
19 | RadioGroup.displayName = RadioGroupPrimitive.Root.displayName
20 |
21 | const RadioGroupItem = React.forwardRef<
22 | React.ElementRef,
23 | React.ComponentPropsWithoutRef
24 | >(({ className, ...props }, ref) => {
25 | return (
26 |
34 |
35 |
36 |
37 |
38 | )
39 | })
40 | RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName
41 |
42 | export { RadioGroup, RadioGroupItem }
43 |
--------------------------------------------------------------------------------
/next_app/src/components/drawer/components/marketplace.tsx:
--------------------------------------------------------------------------------
1 | import { useGlobalState, useProjectManager } from "@/hooks";
2 | import { TDrawerItem } from "."
3 | import { Button } from "@/components/ui/button";
4 | import Link from "next/link";
5 | import { ChevronRight } from "lucide-react";
6 |
7 | function TemplateMarketplace() {
8 | return
9 |
TEMPLATE MARKETPLACE
10 |
11 |
Here you can find a variety of user submitted templates to help you get started with your projects quickly.
12 |
13 |
14 | Every Template is a {" "}
15 | Atomic Asset
16 | {" "} on the ao-bazar marketplace which anyone can buy and trade.
17 |
18 |
19 |
20 | To publish your own template, simply use the Project Publish Template option from the menu
21 |
22 |
23 |
24 | }
25 |
26 | const drawerItem: TDrawerItem = {
27 | component: TemplateMarketplace,
28 | label: "Template Marketplace",
29 | value: "MARKETPLACE"
30 | }
31 |
32 | export default drawerItem;
--------------------------------------------------------------------------------
/next_app/src/components/drawer/components/project-list.tsx:
--------------------------------------------------------------------------------
1 | import { useGlobalState, useProjectManager } from "@/hooks";
2 | import { TDrawerItem } from "."
3 | import { Button } from "@/components/ui/button";
4 | import { pushToRecents } from "@/lib/utils";
5 |
6 | function ProjectList() {
7 | const globalState = useGlobalState();
8 | const manager = useProjectManager();
9 | const projects = manager.projects;
10 |
11 | return
12 |
PROJECTS
13 |
14 | {
15 | Object.keys(projects).toSorted().map((pname, i) => (
16 |
27 | ))
28 | }
29 |
30 |
31 | }
32 |
33 | const drawerItem: TDrawerItem = {
34 | component: ProjectList,
35 | label: "Project List",
36 | value: "ALL_PROJECTS"
37 | }
38 |
39 | export default drawerItem;
--------------------------------------------------------------------------------
/next_app/backend/extract.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | SCRIPT_NAME=$(basename "$0")
4 | OUTPUT_FILE="cookbook.md"
5 | rm -f "$OUTPUT_FILE"
6 |
7 | rm -rf ao-cookbook
8 | git clone https://github.com/permaweb/ao-cookbook
9 |
10 | cd ao-cookbook/src
11 |
12 | echo "# Cookbook Documentation" > "$OUTPUT_FILE"
13 |
14 | echo "Starting script at $(date)"
15 |
16 | # Generate tree structure
17 | echo "Generating tree structure..."
18 | # echo "## Project Structure" >> "$OUTPUT_FILE"
19 | # echo '```' >> "$OUTPUT_FILE"
20 | # tree -I ".git|$OUTPUT_FILE|$SCRIPT_NAME" --gitignore >> "$OUTPUT_FILE"
21 | # echo '```' >> "$OUTPUT_FILE"
22 | # echo "" >> "$OUTPUT_FILE"
23 |
24 | echo "Processing markdown files..."
25 |
26 | # Directories to ignore
27 | IGNORE_DIRS="node_modules|dist|build|.git|zh|ja|kr|ru|0rbit|betteridea|aoconnect|aos|dev-cli|editor-setup.md|testnet-info"
28 |
29 | # Use tree to list only .md files, respecting .gitignore, excluding specific directories
30 | tree -if --noreport --gitignore -I "$IGNORE_DIRS" | grep '\.md$' | sed 's|^./||' | while read -r file; do
31 | # Skip the output file itself
32 | if [ "$file" != "$OUTPUT_FILE" ]; then
33 | echo "Adding $file"
34 | echo "## File: $file" >> "$OUTPUT_FILE"
35 | echo '```' >> "$OUTPUT_FILE"
36 | # Strip SVG tags and add content to output file
37 | cat "$file" | sed '/