mirror of
https://github.com/johndoe6345789/AutoMetabuilder.git
synced 2026-04-24 13:54:59 +00:00
Introduce AutoMetabuilder core components and workflow packages:
- Implement core components: CLI argument parsing, environment loading, GitHub service creation, and logging configuration. - Add support for OpenAI client setup and model resolution. - Develop SDLC context loader from GitHub and repository files. - Implement workflow context and engine builders. - Introduce major workflow packages: `game_tick_loop` and `contextual_iterative_loop`. - Update localization files with new package descriptions and labels. - Streamline web navigation by loading items from a dedicated JSON file.
This commit is contained in:
@@ -30,7 +30,7 @@ def build_prompt_yaml(system_content: str | None, user_content: str | None, mode
|
||||
model_value = model or "openai/gpt-4o"
|
||||
system_block = indent_block(system_content)
|
||||
user_block = indent_block(user_content)
|
||||
return f\"\"\"messages:
|
||||
return f"""messages:
|
||||
- role: system
|
||||
content: >-
|
||||
{system_block}
|
||||
@@ -38,7 +38,7 @@ def build_prompt_yaml(system_content: str | None, user_content: str | None, mode
|
||||
content: >-
|
||||
{user_block}
|
||||
model: {model_value}
|
||||
\"\"\"
|
||||
"""
|
||||
|
||||
|
||||
def load_metadata() -> Dict[str, Any]:
|
||||
|
||||
2462
backend/poetry.lock
generated
2462
backend/poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,32 +0,0 @@
|
||||
[tool.poetry]
|
||||
name = "autometabuilder"
|
||||
version = "0.1.0"
|
||||
description = "AutoMetabuilder"
|
||||
authors = ["Your Name <you@example.com>"]
|
||||
readme = "README.md"
|
||||
packages = [{include = "autometabuilder", from = "backend"}]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.10"
|
||||
requests = "^2.31.0"
|
||||
pyyaml = "^6.0.1"
|
||||
python-dotenv = "^1.0.0"
|
||||
openai = "^1.0.0"
|
||||
PyGithub = "^2.1.1"
|
||||
tenacity = "^9.1.2"
|
||||
flask = "^2.3.3"
|
||||
slack-sdk = "^3.39.0"
|
||||
discord-py = "^2.6.4"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
autometabuilder = "autometabuilder.main:main"
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"playwright (>=1.57.0,<2.0.0)",
|
||||
"pytest-playwright (>=0.7.2,<0.8.0)"
|
||||
]
|
||||
@@ -5,7 +5,7 @@ from autometabuilder import load_messages
|
||||
|
||||
class TestMetadata(unittest.TestCase):
|
||||
def test_metadata_exists(self):
|
||||
metadata_path = os.path.join("src", "autometabuilder", "metadata.json")
|
||||
metadata_path = os.path.join("backend", "autometabuilder", "metadata.json")
|
||||
self.assertTrue(os.path.exists(metadata_path))
|
||||
|
||||
with open(metadata_path, "r") as f:
|
||||
@@ -33,9 +33,12 @@ def run_server(port, holder):
|
||||
server.run()
|
||||
|
||||
def get_free_port():
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||
sock.bind(("127.0.0.1", 0))
|
||||
return sock.getsockname()[1]
|
||||
try:
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||
sock.bind(("127.0.0.1", 0))
|
||||
return sock.getsockname()[1]
|
||||
except PermissionError:
|
||||
pytest.skip("Sandbox denies socket creation for UI tests.")
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def server():
|
||||
@@ -8,7 +8,7 @@ from playwright.sync_api import Page, expect
|
||||
def wait_for_nav(page: Page):
|
||||
page.wait_for_selector("[data-section='dashboard']")
|
||||
|
||||
UI_MESSAGES_PATH = os.path.join(os.path.dirname(__file__), "../../src/autometabuilder/messages_en.json")
|
||||
UI_MESSAGES_PATH = os.path.join(os.path.dirname(__file__), "../../autometabuilder/messages_en.json")
|
||||
with open(UI_MESSAGES_PATH, "r", encoding="utf-8") as f:
|
||||
UI_MESSAGES = json.load(f)
|
||||
|
||||
@@ -153,7 +153,7 @@ def test_choices_dropdowns_exist(page: Page, server: str):
|
||||
def test_autocomplete_values_from_json(page: Page, server: str):
|
||||
"""Test that dropdown options are populated from metadata.json"""
|
||||
# Load metadata.json
|
||||
metadata_path = os.path.join(os.path.dirname(__file__), "../../src/autometabuilder/metadata.json")
|
||||
metadata_path = os.path.join(os.path.dirname(__file__), "../../autometabuilder/metadata.json")
|
||||
with open(metadata_path, 'r') as f:
|
||||
metadata = json.load(f)
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"extends": "next/core-web-vitals",
|
||||
"rules": {
|
||||
"react/react-in-jsx-scope": "off"
|
||||
}
|
||||
}
|
||||
6
frontend/next-env.d.ts
vendored
6
frontend/next-env.d.ts
vendored
@@ -1,2 +1,6 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/types/global" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
import "./.next/types/routes.d.ts";
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
{
|
||||
"name": "autometabuilder-frontend",
|
||||
"name": "frontend",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
"lint": "eslint"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "14.4.4",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1"
|
||||
"next": "16.1.1",
|
||||
"react": "19.2.3",
|
||||
"react-dom": "19.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "22.4.2",
|
||||
"@types/react": "18.3.1",
|
||||
"eslint": "8.47.0",
|
||||
"eslint-config-next": "14.4.4",
|
||||
"sass": "2.1.0",
|
||||
"typescript": "5.6.4"
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "16.1.1",
|
||||
"sass": "^1.95.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
import type { AppProps } from "next/app";
|
||||
import "../styles/globals.scss";
|
||||
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
return <Component {...pageProps} />;
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import DashboardSection from "../components/sections/DashboardSection";
|
||||
import PromptSection from "../components/sections/PromptSection";
|
||||
import SettingsSection from "../components/sections/SettingsSection";
|
||||
import TranslationsSection from "../components/sections/TranslationsSection";
|
||||
import WorkflowSection from "../components/sections/WorkflowSection";
|
||||
import PageLayout from "../components/layout/PageLayout";
|
||||
import {
|
||||
fetchContext,
|
||||
fetchWorkflowPackage,
|
||||
runBot,
|
||||
savePrompt,
|
||||
saveSettings,
|
||||
saveWorkflow,
|
||||
} from "../lib/api";
|
||||
import { UIContext } from "../lib/types";
|
||||
|
||||
export default function HomePage() {
|
||||
const [context, setContext] = useState<UIContext | null>(null);
|
||||
const [selectedSection, setSelectedSection] = useState("dashboard");
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState("");
|
||||
|
||||
const loadContext = async () => {
|
||||
setLoading(true);
|
||||
setError("");
|
||||
try {
|
||||
const data = await fetchContext();
|
||||
setContext(data);
|
||||
setSelectedSection((prev) => prev ?? data.navigation[0]?.section ?? "dashboard");
|
||||
} catch (err) {
|
||||
setError(String(err));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
void loadContext();
|
||||
}, []);
|
||||
|
||||
const t = useMemo(
|
||||
() => (key: string, fallback?: string) => context?.messages[key] ?? fallback ?? key,
|
||||
[context]
|
||||
);
|
||||
|
||||
const handleRun = async (payload: Parameters<typeof runBot>[0]) => {
|
||||
await runBot(payload);
|
||||
await loadContext();
|
||||
};
|
||||
|
||||
const handleWorkflowSave = async (content: string) => {
|
||||
await saveWorkflow(content);
|
||||
await loadContext();
|
||||
};
|
||||
|
||||
const handleTemplateSelect = async (id: string) => {
|
||||
const pkg = await fetchWorkflowPackage(id);
|
||||
const workflowPayload = JSON.stringify(pkg.workflow ?? {}, null, 2);
|
||||
setContext((prev) => (prev ? { ...prev, workflow_content: workflowPayload } : prev));
|
||||
};
|
||||
|
||||
const handlePromptSave = async (content: string) => {
|
||||
await savePrompt(content);
|
||||
await loadContext();
|
||||
};
|
||||
|
||||
const handleSettingsSave = async (values: Record<string, string>) => {
|
||||
await saveSettings(values);
|
||||
await loadContext();
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<main className="app-loading">
|
||||
<p>Loading dashboard…</p>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
if (error || !context) {
|
||||
return (
|
||||
<main className="app-loading">
|
||||
<p>{error || "Unable to load context."}</p>
|
||||
<button type="button" onClick={loadContext}>
|
||||
Retry
|
||||
</button>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<PageLayout navItems={context.navigation} section={selectedSection} onSectionChange={setSelectedSection} t={t}>
|
||||
{selectedSection === "dashboard" && (
|
||||
<DashboardSection logs={context.logs} status={context.status} onRun={handleRun} t={t} />
|
||||
)}
|
||||
{selectedSection === "workflow" && (
|
||||
<WorkflowSection
|
||||
content={context.workflow_content}
|
||||
packages={context.workflow_packages}
|
||||
onSave={handleWorkflowSave}
|
||||
onTemplateSelect={handleTemplateSelect}
|
||||
t={t}
|
||||
/>
|
||||
)}
|
||||
{selectedSection === "prompt" && <PromptSection content={context.prompt_content} onSave={handlePromptSave} t={t} />}
|
||||
{selectedSection === "settings" && (
|
||||
<SettingsSection envVars={context.env_vars} onSave={handleSettingsSave} t={t} />
|
||||
)}
|
||||
{selectedSection === "translations" && (
|
||||
<TranslationsSection languages={context.translations} onRefresh={loadContext} t={t} />
|
||||
)}
|
||||
</PageLayout>
|
||||
);
|
||||
}
|
||||
@@ -1,19 +1,34 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2020",
|
||||
"target": "ES2017",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve"
|
||||
"jsx": "react-jsx",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts",
|
||||
".next/dev/types/**/*.ts",
|
||||
"**/*.mts"
|
||||
],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user