forked from codegen-sh/codegen
-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Add dependency-free CodegenRestDashboard (REST commands + UI + CF webhook) #206
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
codegen-sh
wants to merge
4
commits into
develop
Choose a base branch
from
codegen-bot/codegen-rest-dashboard-setup-01c8b1
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
76392fb
feat(dashboard): add dependency-free CodegenRestDashboard with comman…
codegen-sh[bot] 1773d1f
feat(dashboard): chaining UI + persistence; per-run template selectio…
codegen-sh[bot] bc22b3b
feat(webhook+watcher): add local /webhook receiver + /api/events; opt…
codegen-sh[bot] 46e900a
Dashboard fixes and templating:
codegen-sh[bot] File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| # Copy to .env and fill your values. Do NOT commit the .env file. | ||
| CODEGEN_API_BASE=https://api.codegen.com | ||
| CODEGEN_ORG_ID=323 | ||
| CODEGEN_TOKEN=sk-REPLACE_ME | ||
| # Optional: run in mock/offline mode (server serves fixtures; no network calls) | ||
| CODEGEN_OFFLINE=0 | ||
| # Optional: Webhook HMAC secret (if you enable signature verification) | ||
| CODEGEN_WEBHOOK_SECRET= | ||
| # Server port | ||
| PORT=8787 | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| # CodegenRestDashboard (No-deps REST UI + Commands) | ||
|
|
||
| This package adds a dependency-free dashboard and Node.js command scripts to interact with the Codegen REST API. | ||
|
|
||
| Important: | ||
| - Do NOT commit real secrets. Create CodegenRestDashboard/.env locally (see .env.example) | ||
| - The browser UI never receives your API token; a tiny local proxy server injects auth headers | ||
| - Cloudflare Worker webhook is provided separately for production webhooks | ||
|
|
||
| ## Quick start | ||
|
|
||
| 1) Copy .env.example to .env and fill in your values | ||
| ``` | ||
| cp CodegenRestDashboard/.env.example CodegenRestDashboard/.env | ||
| ``` | ||
|
|
||
| 2) Start the local server (serves UI and proxies API) | ||
| ``` | ||
| node CodegenRestDashboard/server.js | ||
| ``` | ||
| Then open http://localhost:8787 | ||
|
|
||
| 3) Use commands (examples) | ||
| ``` | ||
| node CodegenRestDashboard/commands/create_agent_run.js --prompt "Hello" --model "Sonnet 4.5" | ||
| node CodegenRestDashboard/commands/list_agent_runs.js --state active --limit 20 | ||
| node CodegenRestDashboard/commands/get_agent_run.js --id 123 | ||
| node CodegenRestDashboard/commands/resume_agent_run.js --id 123 --prompt "Continue" | ||
| node CodegenRestDashboard/commands/generate_setup_commands.js --repo_id 999 | ||
| ``` | ||
|
|
||
| 4) Mock mode (no network) | ||
| ``` | ||
| CODEGEN_OFFLINE=1 node CodegenRestDashboard/server.js | ||
| ``` | ||
|
|
||
| ## Files | ||
| - commands/: Node CLI scripts, no external deps | ||
| - dashboard/: Vanilla HTML/CSS/JS UI | ||
| - utils/env.js: safe .env loader (Node-only) | ||
| - utils/apiClient.js: shared REST client for Node context | ||
| - server.js: local static server + API proxy (injects Authorization) | ||
| - webhook_server.js: Cloudflare Worker handler for /webhook | ||
| - mock/: local fixtures for offline development | ||
|
|
||
| ## Security | ||
| - .env is in .gitignore. Do not commit it. | ||
| - The token is used only in Node (server/commands). The browser never sees it. | ||
|
|
||
| ## Webhook (Cloudflare) | ||
| - Deploy CodegenRestDashboard/webhook_server.js as a Worker (route /webhook) | ||
| - Configure your DNS so https://www.pixelium.uk/webhook points to the Worker | ||
| - Optionally set CODEGEN_WEBHOOK_SECRET and verify HMAC in the worker | ||
|
|
||
| ## New features | ||
| - Auto-refresh only UI (no manual refresh button) | ||
| - Header shows only Active count (hover reveals top active runs) | ||
| - Compact run cards with status dots; click a completed run to open logs/resume dialog; click an active run’s “Chain” to configure multi-template chaining | ||
| - Per-run template selection and chaining (Templates tab manages templates) | ||
| - Follow-up automation sends templates in sequence on each completion cycle | ||
| - Desktop notifications (optional, via browser permission) + in-app toasts | ||
|
|
||
| ## Extra commands | ||
| ``` | ||
| node CodegenRestDashboard/commands/get_agent_run_logs.js --id 123 --skip 0 --limit 100 | ||
| node CodegenRestDashboard/commands/ban_agent_run.js --id 123 [--before <order>] [--after <order>] | ||
| node CodegenRestDashboard/commands/unban_agent_run.js --id 123 [--before <order>] [--after <order>] | ||
| ``` | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| #!/usr/bin/env node | ||
| const { apiPost } = require('../utils/apiClient'); | ||
| const { loadEnv } = require('../utils/env'); | ||
| const path = require('path'); | ||
| loadEnv(path.join(__dirname, '..', '.env')); | ||
|
|
||
| function pathBan(org){ return `/v1/organizations/${org}/agent/run/ban`; } | ||
|
|
||
| async function main(){ | ||
| const args = process.argv.slice(2); | ||
| let id; let before=null; let after=null; | ||
| for (let i=0;i<args.length;i++){ | ||
| if (args[i]==='--id') id = Number(args[++i]); | ||
| else if (args[i]==='--before') before = args[++i]; | ||
| else if (args[i]==='--after') after = args[++i]; | ||
| } | ||
| if (!id) { console.error('Usage: ban_agent_run.js --id <runId> [--before <order>] [--after <order>]'); process.exit(2); } | ||
| const org = process.env.CODEGEN_ORG_ID; | ||
| const body = { agent_run_id: id }; | ||
| if (before!==null) body.before_card_order_id = before; | ||
| if (after!==null) body.after_card_order_id = after; | ||
| const data = await apiPost(pathBan(org), body); | ||
| console.log(JSON.stringify(data, null, 2)); | ||
| } | ||
|
|
||
| if (require.main===module){ main().catch(e=>{ console.error(e.message||e); process.exit(1); }); } | ||
| module.exports = main; | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| #!/usr/bin/env node | ||
| const { apiPost, pathCreate } = require('../utils/apiClient'); | ||
|
|
||
| const MODELS = [ | ||
| 'Sonnet 4.5', | ||
| 'GPT-5', | ||
| 'GPT 5 Codex', | ||
| 'Claude opus 4.5', | ||
| 'Grok 4', | ||
| 'Grok 4 Fast reasoning', | ||
| 'Grok Code Fast 1', | ||
| ]; | ||
|
|
||
| async function main() { | ||
| const args = process.argv.slice(2); | ||
| let prompt = ''; | ||
| let model = ''; | ||
| let repo_id = undefined; | ||
|
|
||
| for (let i = 0; i < args.length; i++) { | ||
| if (args[i] === '--prompt') prompt = args[++i] || ''; | ||
| else if (args[i] === '--model') model = args[++i] || ''; | ||
| else if (args[i] === '--repo_id') repo_id = Number(args[++i]); | ||
| } | ||
|
|
||
| if (!prompt) { | ||
| console.error('Usage: create_agent_run.js --prompt "..." [--model "Sonnet 4.5"|...] [--repo_id 123]'); | ||
| process.exit(2); | ||
| } | ||
| if (model && !MODELS.includes(model)) { | ||
| console.error(`Model must be one of: ${MODELS.join(', ')}`); | ||
| process.exit(2); | ||
| } | ||
|
|
||
| const body = { prompt }; | ||
| if (model) body.model = model; | ||
| if (repo_id) body.repo_id = repo_id; | ||
|
|
||
| const data = await apiPost(pathCreate(), body); | ||
| console.log(JSON.stringify(data, null, 2)); | ||
| } | ||
|
|
||
| if (require.main === module) { | ||
| main().catch((e) => { console.error(e.message || e); process.exit(1); }); | ||
| } | ||
|
|
||
| module.exports = main; | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| #!/usr/bin/env node | ||
| const { apiPost, pathGenerateSetup } = require('../utils/apiClient'); | ||
|
|
||
| async function main() { | ||
| const args = process.argv.slice(2); | ||
| let repo_id = undefined; | ||
| let language = undefined; // optional | ||
|
|
||
| for (let i = 0; i < args.length; i++) { | ||
| if (args[i] === '--repo_id') repo_id = Number(args[++i]); | ||
| else if (args[i] === '--language') language = args[++i] || undefined; | ||
| } | ||
|
|
||
| if (!repo_id) { | ||
| console.error('Usage: generate_setup_commands.js --repo_id 123 [--language node|python|...]'); | ||
| process.exit(2); | ||
| } | ||
|
|
||
| const body = { repo_id }; | ||
| if (language) body.language = language; | ||
|
|
||
| const data = await apiPost(pathGenerateSetup(), body); | ||
| console.log(JSON.stringify(data, null, 2)); | ||
| } | ||
|
|
||
| if (require.main === module) { | ||
| main().catch((e) => { console.error(e.message || e); process.exit(1); }); | ||
| } | ||
|
|
||
| module.exports = main; | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| #!/usr/bin/env node | ||
| const { apiGet, pathGet, pathLogs } = require('../utils/apiClient'); | ||
|
|
||
| async function main() { | ||
| const args = process.argv.slice(2); | ||
| let id = undefined; | ||
| let withLogs = false; | ||
| let skip = 0; | ||
| let limit = 50; | ||
|
|
||
| for (let i = 0; i < args.length; i++) { | ||
| if (args[i] === '--id') id = Number(args[++i]); | ||
| else if (args[i] === '--logs') withLogs = true; | ||
| else if (args[i] === '--skip') skip = Number(args[++i]); | ||
| else if (args[i] === '--limit') limit = Number(args[++i]); | ||
| } | ||
|
|
||
| if (!id) { | ||
| console.error('Usage: get_agent_run.js --id 123 [--logs] [--skip 0] [--limit 50]'); | ||
| process.exit(2); | ||
| } | ||
|
|
||
| const res = await apiGet(pathGet(id)); | ||
| if (!withLogs) return console.log(JSON.stringify(res, null, 2)); | ||
|
|
||
| const logs = await apiGet(pathLogs(id), { skip, limit }); | ||
| console.log(JSON.stringify({ run: res, logs }, null, 2)); | ||
| } | ||
|
|
||
| if (require.main === module) { | ||
| main().catch((e) => { console.error(e.message || e); process.exit(1); }); | ||
| } | ||
|
|
||
| module.exports = main; | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| #!/usr/bin/env node | ||
| const { apiGet, pathLogs } = require('../utils/apiClient'); | ||
|
|
||
| async function main(){ | ||
| const args = process.argv.slice(2); | ||
| let id; let skip=0; let limit=100; | ||
| for (let i=0;i<args.length;i++){ | ||
| if (args[i]==='--id') id = Number(args[++i]); | ||
| else if (args[i]==='--skip') skip = Number(args[++i]); | ||
| else if (args[i]==='--limit') limit = Number(args[++i]); | ||
| } | ||
| if (!id) { console.error('Usage: get_agent_run_logs.js --id <runId> [--skip 0] [--limit 100]'); process.exit(2); } | ||
| const data = await apiGet(pathLogs(id), { skip, limit }); | ||
| console.log(JSON.stringify(data, null, 2)); | ||
| } | ||
|
|
||
| if (require.main===module){ main().catch(e=>{ console.error(e.message||e); process.exit(1); }); } | ||
| module.exports = main; | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| #!/usr/bin/env node | ||
| const path = require('path'); | ||
| const { loadEnv } = require('../utils/env'); | ||
| loadEnv(path.join(__dirname, '..', '.env')); | ||
|
|
||
| module.exports = { | ||
| create: require('./create_agent_run'), | ||
| resume: require('./resume_agent_run'), | ||
| list: require('./list_agent_runs'), | ||
| get: require('./get_agent_run'), | ||
| logs: require('./get_agent_run_logs'), | ||
| genSetup: require('./generate_setup_commands'), | ||
| ban: require('./ban_agent_run'), | ||
| unban: require('./unban_agent_run'), | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| #!/usr/bin/env node | ||
| const { apiGet, pathList } = require('../utils/apiClient'); | ||
|
|
||
| async function main() { | ||
| const args = process.argv.slice(2); | ||
| let state = ''; | ||
| let page = 1; | ||
| let limit = 50; | ||
|
|
||
| for (let i = 0; i < args.length; i++) { | ||
| if (args[i] === '--state') state = args[++i] || ''; | ||
| else if (args[i] === '--page') page = Number(args[++i]); | ||
| else if (args[i] === '--limit') limit = Number(args[++i]); | ||
| } | ||
|
|
||
| const params = { page, limit }; | ||
| if (state) params.state = state; // server may ignore if unsupported | ||
|
|
||
| const data = await apiGet(pathList(), params); | ||
| console.log(JSON.stringify(data, null, 2)); | ||
| } | ||
|
|
||
| if (require.main === module) { | ||
| main().catch((e) => { console.error(e.message || e); process.exit(1); }); | ||
| } | ||
|
|
||
| module.exports = main; | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| #!/usr/bin/env node | ||
| const path = require('path'); | ||
| const { loadEnv } = require('../utils/env'); | ||
| loadEnv(path.join(__dirname, '..', '.env')); | ||
|
|
||
| // Minimal inlined renderer to avoid depending on dashboard file | ||
| function getPath(obj, p){ try { return p.split('.').reduce((a,k)=>(a&&a[k]!=null?a[k]:undefined), obj);} catch(_){ return undefined; } } | ||
| function renderTemplate(tpl, vars){ return String(tpl||'').replace(/\{\{\s*([a-zA-Z0-9_.]+)\s*\}\}/g,(_,k)=>{ const v=getPath(vars||{},k); return v==null? '': String(v); }); } | ||
|
|
||
| async function main(){ | ||
| const args = process.argv.slice(2); | ||
| let template = ''; | ||
| let varsJson = '{}'; | ||
| for (let i=0;i<args.length;i++){ | ||
| if (args[i]==='--template') template = args[++i]||''; | ||
| else if (args[i]==='--vars') varsJson = args[++i]||'{}'; | ||
| } | ||
| if (!template){ | ||
| console.error('Usage: render_template.js --template "Hello {{run_id}}" --vars "{\"run_id\":123,\"result\":\"OK\"}"'); | ||
| process.exit(2); | ||
| } | ||
| let vars={}; | ||
| try { vars = JSON.parse(varsJson); } catch(e){ console.error('Invalid JSON for --vars'); process.exit(2); } | ||
| const out = renderTemplate(template, vars); | ||
| console.log(out); | ||
| } | ||
|
|
||
| if (require.main===module){ main().catch(e=>{ console.error(e.message||e); process.exit(1); }); } | ||
| module.exports = main; | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| #!/usr/bin/env node | ||
| const { apiPost, pathResume } = require('../utils/apiClient'); | ||
|
|
||
| async function main() { | ||
| const args = process.argv.slice(2); | ||
| let id = undefined; | ||
| let prompt = ''; | ||
|
|
||
| for (let i = 0; i < args.length; i++) { | ||
| if (args[i] === '--id') id = Number(args[++i]); | ||
| else if (args[i] === '--prompt') prompt = args[++i] || ''; | ||
| } | ||
|
|
||
| if (!id) { | ||
| console.error('Usage: resume_agent_run.js --id 123 [--prompt "..."]'); | ||
| process.exit(2); | ||
| } | ||
|
|
||
| const body = { agent_run_id: id }; | ||
| if (prompt) body.prompt = prompt; | ||
|
|
||
| const data = await apiPost(pathResume(), body); | ||
| console.log(JSON.stringify(data, null, 2)); | ||
| } | ||
|
|
||
| if (require.main === module) { | ||
| main().catch((e) => { console.error(e.message || e); process.exit(1); }); | ||
| } | ||
|
|
||
| module.exports = main; | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| #!/usr/bin/env node | ||
| const cmds = require('./index'); | ||
|
|
||
| async function main() { | ||
| const [,, name, ...rest] = process.argv; | ||
| if (!name || !cmds[name]) { | ||
| console.error('Usage: runCommand.js <create|resume|list|get|genSetup> [args...]'); | ||
| process.exit(2); | ||
| } | ||
| // Re-dispatch by spawning module main | ||
| await cmds[name](); | ||
| } | ||
|
|
||
| main().catch((e)=>{ console.error(e.message || e); process.exit(1); }); | ||
|
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Replace the hard-coded organization ID with a placeholder so users don’t accidentally use or leak a real org identifier.
Prompt for AI agents