diff --git a/create-a-container/bin/test-docker-registry.js b/create-a-container/bin/test-docker-registry.js new file mode 100755 index 00000000..8263944d --- /dev/null +++ b/create-a-container/bin/test-docker-registry.js @@ -0,0 +1,82 @@ +#!/usr/bin/env node +/** + * Test script for docker-registry utilities + * Usage: node test-docker-registry.js + * Example: node test-docker-registry.js nginx:alpine + */ + +const { parseDockerRef, getImageConfig, extractImageMetadata } = require('../utils/docker-registry'); + +// Normalize function copied from routers/containers.js +function normalizeDockerRef(ref) { + if (ref.startsWith('http://') || ref.startsWith('https://') || ref.startsWith('git@')) { + return ref; + } + + let tag = 'latest'; + let imagePart = ref; + + const lastColon = ref.lastIndexOf(':'); + if (lastColon !== -1) { + const potentialTag = ref.substring(lastColon + 1); + if (!potentialTag.includes('/')) { + tag = potentialTag; + imagePart = ref.substring(0, lastColon); + } + } + + const parts = imagePart.split('/'); + + let host = 'docker.io'; + let org = 'library'; + let image; + + if (parts.length === 1) { + image = parts[0]; + } else if (parts.length === 2) { + if (parts[0].includes('.') || parts[0].includes(':')) { + host = parts[0]; + image = parts[1]; + } else { + org = parts[0]; + image = parts[1]; + } + } else { + host = parts[0]; + image = parts[parts.length - 1]; + org = parts.slice(1, -1).join('/'); + } + + return `${host}/${org}/${image}:${tag}`; +} + +async function test(imageRef) { + try { + console.log('Testing image:', imageRef); + console.log('---'); + + const normalized = normalizeDockerRef(imageRef); + console.log('Normalized:', normalized); + + const parsed = parseDockerRef(normalized); + console.log('Parsed:', parsed); + + const repo = `${parsed.namespace}/${parsed.image}`; + console.log('Fetching config from registry...'); + + const config = await getImageConfig(parsed.registry, repo, parsed.tag); + console.log('✓ Config fetched successfully'); + + const metadata = extractImageMetadata(config); + console.log('---'); + console.log('Metadata:'); + console.log(JSON.stringify(metadata, null, 2)); + + } catch (err) { + console.error('✗ Error:', err.message); + process.exit(1); + } +} + +const imageRef = process.argv[2] || 'nginx:alpine'; +test(imageRef); diff --git a/create-a-container/config/ozwell-agent.yaml b/create-a-container/config/ozwell-agent.yaml new file mode 100644 index 00000000..291c8a9f --- /dev/null +++ b/create-a-container/config/ozwell-agent.yaml @@ -0,0 +1,36 @@ +name: MIE Container Manager Assistant +model: llama3.1:latest +temperature: 0.1 +instructions: > + You are MIE Assistant. You help users manage their containers, nodes, domains, and settings. + + CRITICAL RULES: + 1. NEVER write JSON in your text responses. Use tool calls instead. + 2. NEVER describe or narrate tool calls. Just call them silently. + 3. NEVER claim you did something without actually calling a tool. + 4. ALWAYS call get_page_contents FIRST before any other tool. This tells you what fields, tables, buttons, and links are on the page. + 5. If get_page_contents shows available actions (buttons/links), use click_element to click them. + 6. Only use set_page_contents when the page has form fields to fill. + 7. Keep text responses short - one or two sentences max. + + NAVIGATION: When the user asks to create/add something and the page shows a + "New..." button in the actions list, use click_element to click that button. + Do NOT try to set_page_contents on a list/table page — navigate first. + + FORM WORKFLOW (only on pages with form fields): + Step 1: Call get_page_contents to see available fields. + Step 2: Call set_page_contents with fields and submit:true. + Step 3: Report success or failure in plain English. + + FIELD MAPPING: Use the name attribute from get_page_contents results. + For custom Docker images, set customTemplate to the image name. The + template field will auto-select. + +# Ozwell uses simple string tool names for Ollama compatibility. +# Full tool definitions (descriptions, parameters) are provided by the +# widget's OzwellChatConfig on the client side and sent in each API request. +tools: + - get_page_contents + - set_page_contents + - submit_form + - click_element diff --git a/create-a-container/public/js/chatbot-tools.js b/create-a-container/public/js/chatbot-tools.js new file mode 100644 index 00000000..59e9b513 --- /dev/null +++ b/create-a-container/public/js/chatbot-tools.js @@ -0,0 +1,493 @@ +/** + * Generic tool handlers for the Ozwell chatbot widget. + * Handles get_page_contents and set_page_contents tool calls + * via the ozwell-tool-call DOM event. + */ +(function () { + 'use strict'; + + /** + * Find the label text for a form element. + */ + function getFieldLabel(el) { + // Explicit