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:
2026-01-10 01:35:17 +00:00
parent de876ab130
commit f49ae7bf7e
3 changed files with 121 additions and 86 deletions

View File

@@ -49,3 +49,7 @@ Avoid stagnation; improve structure, clarity, and expressiveness over time.
Roadmap discipline.
If you run out of ROADMAP.md tasks, stop and report.
We should reassess priorities before inventing work.
React component logic (just above the bottom jsx) can be converted to one or more custom hooks.
Use atomic React components.

View File

@@ -1,6 +1,6 @@
"use client";
import { useEffect, useMemo, useState } from "react";
import { useEffect } from "react";
import { Alert, Snackbar } from "@mui/material";
import DashboardSection from "../components/sections/DashboardSection";
import PromptSection from "../components/sections/PromptSection";
@@ -8,42 +8,29 @@ 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 useWebhook, { emitWebhook } from "../hooks/useWebhook";
import {
fetchContext,
fetchWorkflowPackage,
runBot,
savePrompt,
saveSettings,
saveWorkflow,
} from "../lib/api";
import { UIContext } from "../lib/types";
import useDashboardContext from "../hooks/useDashboardContext";
import { emitWebhook, useWebhook } from "../hooks/useWebhook";
import { fetchWorkflowPackage, runBot, savePrompt, saveSettings, saveWorkflow } from "../lib/api";
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 [snack, setSnack] = useState("");
const [snackOpen, setSnackOpen] = useState(false);
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);
}
};
const {
context,
selectedSection,
setSelectedSection,
loading,
error,
snack,
setSnack,
snackOpen,
setSnackOpen,
ready,
loadContext,
t,
} = useDashboardContext();
useEffect(() => {
void loadContext();
}, []);
}, [loadContext]);
useWebhook(
"botRunComplete",
@@ -55,39 +42,13 @@ export default function HomePage() {
[]
);
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();
emitWebhook("runRequested", payload);
};
const handleWorkflowSave = async (content: string) => {
await saveWorkflow(content);
emitWebhook("botRunComplete", payload);
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) {
if (isLoading) {
return (
<main className="app-loading">
<p>Loading dashboard</p>
@@ -95,7 +56,7 @@ export default function HomePage() {
);
}
if (error || !context) {
if (error || !ready || !context) {
return (
<main className="app-loading">
<p>{error || "Unable to load context."}</p>
@@ -108,31 +69,54 @@ export default function HomePage() {
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 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={async (content) => {
await saveWorkflow(content);
emitWebhook("workflow.save", { content });
await loadContext();
}}
onTemplateSelect={async (id) => {
const pkg = await fetchWorkflowPackage(id);
if (pkg.workflow) {
const workflowPayload = JSON.stringify(pkg.workflow ?? {}, null, 2);
await saveWorkflow(workflowPayload);
emitWebhook("workflow.template.selected", { id });
await loadContext();
}
}}
t={t}
/>
)}
{selectedSection === "prompt" && (
<PromptSection
content={context.prompt_content}
onSave={async (content) => {
await savePrompt(content);
emitWebhook("prompt.save", { content });
await loadContext();
}}
t={t}
/>
)}
{selectedSection === "settings" && (
<SettingsSection
envVars={context.env_vars}
onSave={async (values) => {
await saveSettings(values);
emitWebhook("settings.save", { values });
await loadContext();
}}
t={t}
/>
)}
{selectedSection === "translations" && <TranslationsSection languages={context.translations} onRefresh={loadContext} t={t} />}
</PageLayout>
<Snackbar open={snackOpen} autoHideDuration={4000} onClose={() => setSnackOpen(false)}>
<Alert onClose={() => setSnackOpen(false)} severity="info" sx={{ width: "100%" }}>

View File

@@ -0,0 +1,47 @@
import { useEffect, useMemo, useState } from "react";
import { fetchContext } from "../lib/api";
import { UIContext } from "../lib/types";
export default function useDashboardContext() {
const [context, setContext] = useState<UIContext | null>(null);
const [selectedSection, setSelectedSection] = useState("dashboard");
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
const [snack, setSnack] = useState("");
const [snackOpen, setSnackOpen] = useState(false);
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);
}
};
const ready = context !== null;
const t = useMemo(
() => (key: string, fallback?: string) => (context?.messages[key] ?? fallback ?? key),
[context]
);
return {
context,
selectedSection,
setSelectedSection,
loading,
error,
snack,
setSnack,
snackOpen,
setSnackOpen,
loadContext,
t,
ready,
};
}