UNPKG

@blundergoat/goat-flow

Version:

AI coding agent harness and local dashboard for Claude Code, OpenAI Codex, Google Antigravity, and GitHub Copilot - setup audits, guardrails, structured skills, deny hooks, and persistent learning loops.

474 lines (463 loc) 16.2 kB
<!-- ═══ Setup View ═══ --> <div x-show="activeView === 'setup'" x-cloak style="height: calc(100vh - 3.5rem); overflow-y: auto" > <div style="max-width: 1100px; margin: 0 auto; padding: 20px 24px 24px"> <div style="margin-bottom: 14px"> <h2 class="gf-text-primary" style="font-size: 18px; font-weight: 600; margin-bottom: 4px" > Setup </h2> <p class="gf-text-muted" style="font-size: 14px; max-width: 760px"> Generate and run a setup prompt to install or refresh goat-flow for a specific target agent. The header Runner executes the selected setup prompt in Workspace. </p> </div> <!-- Status banner (full width) --> <div class="gf-card" style="padding: 14px 18px; margin-bottom: 12px"> <div style=" display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; " > <div style="display: flex; align-items: center; gap: 12px; flex-wrap: wrap" > <span class="gf-status-dot" :class="report?.scopes?.setup?.status === 'pass' ? 'gf-status-pass' : 'gf-status-danger'" :aria-label="report?.scopes?.setup?.status === 'pass' ? 'Passing' : 'Failing'" x-text="report?.scopes?.setup?.status === 'pass' ? '✓' : '!'" ></span> <span class="gf-text-primary" style="font-size: 15px; font-weight: 600" x-text="projectName" ></span> <span class="gf-text-muted">·</span> <span style="font-size: 14px; font-weight: 500" :style="{ color: report?.scopes?.setup?.status === 'pass' ? 'var(--status-pass)' : 'var(--red-400)' }" x-text="(() => { const checks = report?.scopes?.setup?.checks || []; const p = checks.filter(c => c.status === 'pass').length; return `${p} of ${checks.length} installed`; })()" ></span> <span class="gf-text-muted">·</span> <span class="gf-text-muted" style="font-size: 13px" >audited just now</span > </div> <button @click="runAudit(true)" :disabled="auditing" class="gf-btn gf-btn-md gf-btn-secondary" > <span x-text="auditing ? 'Auditing...' : 'Re-audit'"></span> </button> </div> </div> <!-- Runner selector (full width) --> <div style="margin-bottom: 12px"> <div class="section-label" style="margin-bottom: 8px">Setup target</div> <div style=" display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; " > <template x-for="agent in supportedAgents" :key="'setup-runner-' + agent.id" > <button @click="setupSelectedAgent = agent.id; generateSetupPrompt();" class="gf-card" :style="setupSelectedAgent === agent.id ? { borderColor: 'var(--accent-border)', background: 'var(--accent-bg)' } : {}" style="padding: 11px 12px; text-align: left" > <div class="gf-text-primary" style="font-size: 14px; font-weight: 500" x-text="agent.name" ></div> <div style=" display: flex; align-items: baseline; gap: 6px; margin-top: 4px; " > <span style="color: var(--accent); font-size: 18px; font-weight: 600" x-text="setupTargetGrade(agent.id)" ></span> <span class="gf-text-muted" style="font-size: 13px" x-text="setupTargetPercent(agent.id)" ></span> </div> </button> </template> </div> </div> <!-- Two-column layout --> <div style=" display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-items: start; " > <!-- LEFT COLUMN: config, installs, recommendation --> <div style="display: flex; flex-direction: column; gap: 12px"> <!-- Detected config --> <div class="gf-card" style="padding: 16px 18px"> <div class="section-label" style="margin-bottom: 10px"> Detected configuration </div> <div style="display: flex; flex-direction: column; gap: 6px"> <div x-show="setupDetecting" class="gf-text-muted" style="font-size: 13px; padding: 4px 0" > Detecting project configuration... </div> </div> <div x-show="!setupDetecting" style="display: flex; flex-direction: column; gap: 6px" > <div style=" display: grid; grid-template-columns: 90px 1fr; gap: 10px; align-items: center; " > <span class="gf-text-muted" style="font-size: 13px" >Languages</span > <div style="display: flex; gap: 6px; flex-wrap: wrap"> <template x-for="lang in setupData.languages" :key="'set-lang-' + lang" > <span class="gf-tag" x-text="lang"></span> </template> <span x-show="setupData.languages.length === 0" class="gf-text-muted" style="font-size: 13px; font-style: italic" >None detected</span > </div> </div> <div style=" display: grid; grid-template-columns: 90px 1fr; gap: 10px; align-items: center; " > <span class="gf-text-muted" style="font-size: 13px" >Frameworks</span > <div style="display: flex; gap: 6px; flex-wrap: wrap"> <template x-for="fw in setupData.frameworks" :key="'set-fw-' + fw" > <span class="gf-tag" x-text="fw"></span> </template> <span x-show="setupData.frameworks.length === 0" class="gf-text-muted" style="font-size: 13px; font-style: italic" >None detected</span > </div> </div> <div style=" display: grid; grid-template-columns: 90px 1fr; gap: 10px; align-items: center; " > <span class="gf-text-muted" style="font-size: 13px">Build</span> <span class="gf-text-secondary mono" style="font-size: 12.5px" x-text="setupData.commands.build || '-'" ></span> </div> <div style=" display: grid; grid-template-columns: 90px 1fr; gap: 10px; align-items: center; " > <span class="gf-text-muted" style="font-size: 13px">Test</span> <span class="gf-text-secondary mono" style="font-size: 12.5px" x-text="setupData.commands.test || '-'" ></span> </div> <div style=" display: grid; grid-template-columns: 90px 1fr; gap: 10px; align-items: center; " > <span class="gf-text-muted" style="font-size: 13px">Lint</span> <span class="gf-text-secondary mono" style="font-size: 12.5px" x-text="setupData.commands.lint || '-'" ></span> </div> <div style=" display: grid; grid-template-columns: 90px 1fr; gap: 10px; align-items: center; " > <span class="gf-text-muted" style="font-size: 13px" >Formatter</span > <span class="gf-text-secondary mono" style="font-size: 12.5px" x-text="setupData.commands.format || '-'" ></span> </div> </div> </div> <div class="gf-card" style="padding: 16px 18px"> <div class="section-label" style="margin-bottom: 10px"> Setup installs or refreshes </div> <div style=" display: flex; flex-direction: column; gap: 8px; font-size: 13px; " > <div style="display: grid; grid-template-columns: 92px 1fr; gap: 8px" > <span class="gf-text-muted">Skills</span> <span class="gf-text-secondary mono" style="font-size: 12px" >goat, goat-debug, goat-plan, goat-review, goat-critique, goat-security, goat-qa</span > </div> <div style="display: grid; grid-template-columns: 92px 1fr; gap: 8px" > <span class="gf-text-muted">Hooks</span> <span class="gf-text-secondary mono" style="font-size: 12px" >guardrails</span > </div> <div style="display: grid; grid-template-columns: 92px 1fr; gap: 8px" > <span class="gf-text-muted">Instructions</span> <span class="gf-text-secondary mono" style="font-size: 12px" x-text="setupInstructionSurfaces()" ></span> </div> <div style="display: grid; grid-template-columns: 92px 1fr; gap: 8px" > <span class="gf-text-muted">Templates</span> <span class="gf-text-secondary mono" style="font-size: 12px" >.goat-flow/learning-loop/footguns, /lessons, /decisions</span > </div> </div> </div> <div class="gf-card" style="padding: 14px 16px; border-color: rgba(245, 158, 11, 0.35)" > <div class="section-label" style="color: #fbbf24; margin-bottom: 6px"> Recommendation </div> <p class="gf-text-muted" style="font-size: 13px; margin: 0 0 8px"> <span x-text="report?.scopes?.setup?.status === 'pass' ? 'Setup checks are passing. Add project-specific architecture and pitfalls context when you want stronger harness scores.' : 'Run setup or fix missing setup files before relying on this project harness.'" ></span> </p> <button @click="activeView = 'home'" class="gf-btn gf-btn-sm"> View harness on Home </button> </div> </div> <!-- RIGHT COLUMN: prompt card --> <div class="gf-prompt-card" style="position: sticky; top: 20px"> <div class="gf-prompt-hdr"> <div> <div class="section-label">Setup prompt</div> <div class="gf-text-muted" style="font-size: 13px; margin-top: 2px"> for <span class="gf-text-primary" style="font-weight: 500" x-text="agentName(setupSelectedAgent)" ></span> </div> </div> <div style="display: flex; gap: 6px"> <button x-data="{ copied: false }" @click="if (setupOutputs[setupSelectedAgent]) { copyText(setupOutputs[setupSelectedAgent]); copied = true; setTimeout(() => copied = false, 1200); }" class="gf-btn gf-btn-md gf-btn-secondary" > <span x-text="copied ? 'Copied' : 'Copy'"></span> </button> <button @click="generateSetupPrompt(true)" :disabled="setupGenerating" class="gf-btn gf-btn-md gf-btn-secondary" > Regenerate </button> </div> </div> <div x-show="!setupGenerating" class="gf-terminal-cta" style="padding: 14px 16px; border-radius: 0" > <button @click="if (setupOutputs[setupSelectedAgent]) { launchPreset(setupOutputs[setupSelectedAgent], activeRunner, 'Setup ' + agentName(setupSelectedAgent) + ' via ' + agentName(activeRunner)); activeView = 'workspace'; }" :disabled="launching || !setupOutputs[setupSelectedAgent]" class="gf-btn-terminal-cta" style="width: 100%; justify-content: center; padding: 11px" > <span x-text="launching ? 'Starting setup...' : 'Run Setup in Terminal'" ></span> <svg x-show="!launching" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24" > <path stroke-linecap="round" stroke-linejoin="round" d="M14 5l7 7m0 0l-7 7m7-7H3" /> </svg> </button> <p class="gf-text-muted" style="font-size: 13px; margin: 10px 0 0; line-height: 1.5" > Runs with <span class="mono gf-text-secondary" x-text="agentName(activeRunner)" ></span> against the <span class="mono gf-text-secondary" x-text="agentName(setupSelectedAgent)" ></span> setup prompt. </p> </div> <div x-show="setupGenerating" class="gf-prompt-loading"> <svg class="animate-spin" style="width: 16px; height: 16px; color: var(--accent)" fill="none" viewBox="0 0 24 24" > <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" /> <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" /> </svg> <span class="gf-text-muted" style="font-size: 12px" x-text="'Generating setup prompt for ' + agentName(setupSelectedAgent) + '...'" ></span> </div> <pre x-show="!setupGenerating && setupOutputs[setupSelectedAgent]" class="gf-prompt-body" x-text="setupOutputs[setupSelectedAgent]" ></pre> <p x-show="!setupGenerating && !setupOutputs[setupSelectedAgent]" class="gf-text-disabled" style=" flex: 1; display: flex; align-items: center; justify-content: center; font-size: 12px; " > Select an agent to auto-generate the setup prompt. </p> </div> </div> <div class="gf-footer" style="text-align: center; font-size: 11px; padding: 12px 0" > Built by <a href="https://www.blundergoat.com" target="_blank" class="gf-footer-link" >BlunderGOAT</a > · <span x-text="dashboardVersion ? `v${dashboardVersion}` : ''"></span> </div> </div> </div>