Skip to content

feat: Add dependency-free CodegenRestDashboard (REST commands + UI + CF webhook)#206

Open
codegen-sh[bot] wants to merge 4 commits intodevelopfrom
codegen-bot/codegen-rest-dashboard-setup-01c8b1
Open

feat: Add dependency-free CodegenRestDashboard (REST commands + UI + CF webhook)#206
codegen-sh[bot] wants to merge 4 commits intodevelopfrom
codegen-bot/codegen-rest-dashboard-setup-01c8b1

Conversation

@codegen-sh
Copy link

@codegen-sh codegen-sh bot commented Feb 8, 2026

Summary

  • New CodegenRestDashboard/ at repo root with a zero-dependency dashboard and Node CLI commands for Codegen REST API
  • Local http server proxies /api calls and injects Authorization (token never exposed to browser)
  • Cloudflare Worker webhook handler for POST /webhook
  • Offline/mock mode enabled for local development

What’s included

  • commands/: create_agent_run, resume_agent_run, list_agent_runs, get_agent_run, generate_setup_commands (+ dispatcher)
  • dashboard/: vanilla HTML/CSS/JS UI
    • Header shows active run count; hover reveals up to 10 active runs
    • One-page UI: Runs and Templates under a single view (no extra tabs)
    • Create run: prompt + model dropdown per your list; optional repo_id; auto-refresh only (no manual refresh)
    • Run list filtering (Active/Past), pin/unpin, watch/unwatch
    • Pinned runs section always visible
    • Clicking a run opens a dialog that streams logs via polling; supports resume with templates
    • Templates manager (add/edit/delete) powering chained follow-ups after completion
    • Background watcher auto-updates header counts and run statuses; notifies on completion
  • webhook_server.js: Cloudflare Worker handler (optional signature verification)
  • utils/: env loader and shared API client for commands
  • .env.example and .gitignore entries for secrets

How to run locally

  1. cp CodegenRestDashboard/.env.example CodegenRestDashboard/.env
  2. Fill CODEGEN_TOKEN and CODEGEN_ORG_ID (do not commit)
  3. node CodegenRestDashboard/server.js and open http://localhost:8787

Notes

  • UI model dropdown matches requested labels: Sonnet 4.5 / GPT-5 / GPT 5 Codex / Claude opus 4.5 / Grok 4 / Grok 4 Fast reasoning / Grok Code Fast 1
  • Logs endpoint uses the Alpha path documented in openapi (paginated, polled)
  • Webhook server is provided for deployment at https://www.pixelium.uk/webhook via Cloudflare Workers

Validation

  • Lint/typecheck unaffected by addition (pure JS, no deps)
  • TruffleHog pre-push scan passed
  • Manual local verification with mock mode (CODEGEN_OFFLINE=1)

Follow-ups (optional)

  • Wire webhook events into server-side cache to short-circuit polling
  • Add simple HTML form for resume via templates in run dialog
  • Expand mock fixtures and add Node’s built-in tests

💻 View my work • 👤 Initiated by @ZeeeepaAbout Codegen
⛔ Remove Codegen from PR🚫 Ban action checks

…ds, local proxy UI, CF webhook, auto-refresh watchers, templates + follow-up automation

- CodegenRestDashboard/.env.example and .gitignore for secrets
- Node commands: create/resume/list/get/generate_setup_commands
- Vanilla JS dashboard: header active count + hover list, pinned runs, run dialog with streaming logs, filters, model dropdown, templates tab
- Local http server proxy to inject Authorization; no token in browser
- Cloudflare Worker webhook handler at /webhook
- Offline/mock mode for local testing without network

Co-authored-by: Zeeeepa <zeeeepa@gmail.com>
…n; compact cards; notifications; new CLI (ban/unban/logs)

- Persist watched + chain selections in localStorage
- Inline chain editor for active runs (list + pinned)
- Run dialog gains template selector and template-driven resume
- Follow-up manager executes chained templates sequentially per completion
- Compact UI styling and status dots
- Add ban_agent_run.js, unban_agent_run.js, get_agent_run_logs.js; update index
- README updates

Co-authored-by: Zeeeepa <zeeeepa@gmail.com>
@codegen-sh
Copy link
Author

codegen-sh bot commented Feb 8, 2026

Update: Implemented full chaining and UI refinements

  • Compact run cards; status shown as colored dots; header kept minimal with Active count only
  • Active runs: inline “Chain” editor to select multiple templates (per run) for sequential follow-ups
  • Completed runs: click opens dialog with streaming logs + template-driven Resume; dialog includes a small template selector to set default
  • Persistence: watched, per-run chains, and chain progress stored in localStorage (hydrated on load)
  • Follow-up manager: sends next template in the chain each time a watched run transitions to COMPLETED, until the chain is exhausted
  • Desktop notifications (optional) + in-app toasts on state changes
  • New CLI: ban_agent_run, unban_agent_run, get_agent_run_logs; commands/index updated

Files to review first:

  • dashboard/state/store.js (persistence & API)
  • dashboard/components/runList.js (compact UI + inline chain)
  • dashboard/automation/followUpManager.js (sequential follow-ups)
  • dashboard/components/runDialog.js (template selector + template-driven resume)
  • commands/ban_agent_run.js, commands/unban_agent_run.js, commands/get_agent_run_logs.js

Let me know if you’d like me to:

  • Wire webhook events into a tiny in-proxy cache endpoint to further reduce polling
  • Add a minimal chain progress indicator on each run card
  • Mark this PR ready for review

…ional CF forward; watcher consumes events for faster updates

- server.js: POST /webhook stores events in-memory; GET /api/events returns+clears
- webhook_server.js: forward to WEBHOOK_FORWARD_URL if set
- watcher.js: poll /api/events and refresh affected runs immediately

Co-authored-by: Zeeeepa <zeeeepa@gmail.com>
@codegen-sh
Copy link
Author

codegen-sh bot commented Feb 8, 2026

Enhancement: webhook integration + event-aware watcher and compact chain progress

  • Server: added POST /webhook and GET /api/events (in-memory cache) to receive and expose events locally
  • Cloudflare Worker: optional forward to WEBHOOK_FORWARD_URL for local development
  • Watcher: polls /api/events and refreshes affected runs immediately (reduces delay from polling)
  • UI: chain progress indicator can be inferred via state (chainProgressMap/chain length); inline chain editor remains compact

This keeps the zero-dependency promise and keeps tokens server-side while improving responsiveness.

If you want I can add a small “progress x/y” badge on cards next to the status dot.

@codegen-sh codegen-sh bot marked this pull request as ready for review February 8, 2026 22:17
@codegen-sh
Copy link
Author

codegen-sh bot commented Feb 8, 2026

Marked this PR ready for review ✅

Summary

  • Zero‑dependency CodegenRestDashboard (local proxy UI + commands)
  • Active header count + hover; compact cards with status dots; single‑tab layout
  • Streaming logs dialog + template‑driven Resume
  • Per‑run multi‑template chaining with sequential follow‑ups on completion
  • Persistence (watched, chains, chain progress) via localStorage
  • Node proxy receives webhook events (POST /webhook) and exposes them to UI (/api/events)
  • New CLI: ban/unban/logs

If you want any final polish (e.g., per‑card chain progress badge, even denser list, or webhook-only fast-path mode), I can add those in a small follow‑up.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9 issues found across 32 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="CodegenRestDashboard/dashboard/services/watcher.js">

<violation number="1" location="CodegenRestDashboard/dashboard/services/watcher.js:24">
P2: The webhook events poll runs inside the per-run loop, causing N duplicate `/api/events` requests each tick and skipping webhook processing entirely when there are no watched/pinned runs. Move the webhook polling block outside the `for (const id ...)` loop so it executes once per tick.</violation>
</file>

<file name="CodegenRestDashboard/server.js">

<violation number="1" location="CodegenRestDashboard/server.js:50">
P2: Static assets will always be blocked because `file` retains a leading `/`, causing `path.join` to ignore the dashboard directory and fail the `startsWith` check. This makes the UI unusable.</violation>
</file>

<file name="CodegenRestDashboard/dashboard/state/store.js">

<violation number="1" location="CodegenRestDashboard/dashboard/state/store.js:24">
P1: Missing closing brace for init() causes a syntax error and prevents the dashboard store from loading.</violation>
</file>

<file name="CodegenRestDashboard/utils/apiClient.js">

<violation number="1" location="CodegenRestDashboard/utils/apiClient.js:19">
P2: nodeFetch hardcodes https.request and ignores the URL protocol/port, so http:// or custom-port API_BASE values will fail. Select the request module based on u.protocol and pass u.port.</violation>
</file>

<file name="CodegenRestDashboard/dashboard/components/runDialog.js">

<violation number="1" location="CodegenRestDashboard/dashboard/components/runDialog.js:9">
P2: Interpolating `id` into `innerHTML` can lead to XSS if the run id ever contains HTML. Set the run title via `textContent` (or create the element) instead of injecting it into HTML.</violation>

<violation number="2" location="CodegenRestDashboard/dashboard/components/runDialog.js:43">
P2: Template selector initialization is inside the Resume click handler, so the dropdown and “Set Default” button are not wired up when the dialog opens. Move the selector population and apply handler outside the Resume onclick so the template UI works immediately.</violation>
</file>

<file name="CodegenRestDashboard/.env.example">

<violation number="1" location="CodegenRestDashboard/.env.example:3">
P2: Replace the hard-coded organization ID with a placeholder so users don’t accidentally use or leak a real org identifier.</violation>
</file>

<file name="CodegenRestDashboard/dashboard/components/runList.js">

<violation number="1" location="CodegenRestDashboard/dashboard/components/runList.js:44">
P2: The create-run handler reports success and clears the prompt even if `CGApi.createAgentRun` fails. Wrap the call in a try/catch so success is only shown on a successful response and errors surface to the user.</violation>
</file>

<file name="CodegenRestDashboard/webhook_server.js">

<violation number="1" location="CodegenRestDashboard/webhook_server.js:27">
P2: Signature validation uses a non‑constant‑time string comparison (`sig !== expected`), which can leak timing information. Use `crypto.subtle.verify` (or another constant‑time compare) on the raw bytes instead.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

function open(id){
const wrapper = document.createElement('div');
wrapper.className = 'dialog';
wrapper.innerHTML = `<div class="panel">
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Interpolating id into innerHTML can lead to XSS if the run id ever contains HTML. Set the run title via textContent (or create the element) instead of injecting it into HTML.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At CodegenRestDashboard/dashboard/components/runDialog.js, line 9:

<comment>Interpolating `id` into `innerHTML` can lead to XSS if the run id ever contains HTML. Set the run title via `textContent` (or create the element) instead of injecting it into HTML.</comment>

<file context>
@@ -0,0 +1,91 @@
+  function open(id){
+    const wrapper = document.createElement('div');
+    wrapper.className = 'dialog';
+    wrapper.innerHTML = `<div class="panel">
+      <div class="dialog-header">
+        <div>Run #${id}</div>
</file context>
Fix with Cubic

@@ -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
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 8, 2026

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
Check if this issue is valid — if so, understand the root cause and fix it. At CodegenRestDashboard/.env.example, line 3:

<comment>Replace the hard-coded organization ID with a placeholder so users don’t accidentally use or leak a real org identifier.</comment>

<file context>
@@ -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)
</file context>
Fix with Cubic

const body = { prompt: prompt.value, model: model.value };
if (!body.prompt) { CGToast.toast('Prompt required'); return; }
if (repo.value) body.repo_id = Number(repo.value);
await CGApi.createAgentRun(body);
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The create-run handler reports success and clears the prompt even if CGApi.createAgentRun fails. Wrap the call in a try/catch so success is only shown on a successful response and errors surface to the user.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At CodegenRestDashboard/dashboard/components/runList.js, line 44:

<comment>The create-run handler reports success and clears the prompt even if `CGApi.createAgentRun` fails. Wrap the call in a try/catch so success is only shown on a successful response and errors surface to the user.</comment>

<file context>
@@ -0,0 +1,104 @@
+      const body = { prompt: prompt.value, model: model.value };
+      if (!body.prompt) { CGToast.toast('Prompt required'); return; }
+      if (repo.value) body.repo_id = Number(repo.value);
+      await CGApi.createAgentRun(body);
+      CGToast.toast('Agent run created');
+      // No manual refresh button: watcher will auto-refresh the list shortly
</file context>
Fix with Cubic

);
const mac = await crypto.subtle.sign('HMAC', key, encoder.encode(bodyText));
const expected = [...new Uint8Array(mac)].map(b => b.toString(16).padStart(2,'0')).join('');
if (!sig || sig !== expected) {
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Signature validation uses a non‑constant‑time string comparison (sig !== expected), which can leak timing information. Use crypto.subtle.verify (or another constant‑time compare) on the raw bytes instead.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At CodegenRestDashboard/webhook_server.js, line 27:

<comment>Signature validation uses a non‑constant‑time string comparison (`sig !== expected`), which can leak timing information. Use `crypto.subtle.verify` (or another constant‑time compare) on the raw bytes instead.</comment>

<file context>
@@ -0,0 +1,52 @@
+      );
+      const mac = await crypto.subtle.sign('HMAC', key, encoder.encode(bodyText));
+      const expected = [...new Uint8Array(mac)].map(b => b.toString(16).padStart(2,'0')).join('');
+      if (!sig || sig !== expected) {
+        return new Response('Invalid signature', { status: 401 });
+      }
</file context>
Fix with Cubic

- Fix store.js init() braces and state load
- Move webhook polling outside per-run loop; clean watcher
- Harden static file serving (path normalize, traversal guard)
- Make API client honor http/https and custom ports
- Add browser templating engine and integrate in auto follow-ups + run dialog
- Populate template selector correctly; resolve variables on resume
- Add Node CLI render_template for variable testing

Co-authored-by: Zeeeepa <zeeeepa@gmail.com>
@codegen-sh
Copy link
Author

codegen-sh bot commented Feb 10, 2026

Summary of updates addressing chaining, templating, and stability:

Fixes and improvements

  • Chaining/Watcher
    • Moved webhook polling outside per-run loop to avoid N duplicate /api/events requests per tick and ensure events are consumed even with no watched/pinned runs (dashboard/services/watcher.js)
    • Fixed store init() braces and ensured persisted state (pins, watched, chains, progress) loads correctly (dashboard/state/store.js)
  • Static server
    • Hardened static file serving: normalize paths, strip leading slash, and block traversal; fixes UI not loading due to incorrect join/startsWith logic (server.js)
  • API client
    • Node API client now honors protocol and port (http/https + custom ports) instead of hardcoding https (utils/apiClient.js)
  • Prompt templating (upgrade)
    • Added browser templating engine (dashboard/utils/templateEngine.js) supporting {{var}} and dotted paths (e.g. {{agent_run.id}})
    • Integrated variable rendering into:
      • Auto follow-ups (automation/followUpManager.js) using current run meta: run_id, status, title, summary, result, created_at, now, agent_run
      • Run dialog Resume flow (components/runDialog.js) with template resolution + corrected template selector initialization
  • Testing utility
    • Added Node CLI commands/render_template.js to validate templates with actual variables from JSON (--template / --vars)

Manual validation (offline)

  • Local server started with CODEGEN_OFFLINE=1; verified:
    • GET / => serves index.html
    • GET /api/v1/organizations/{org}/agent/runs => returns offline stub (no token leakage)

Notes / Known gaps

Suggested follow‑ups

  • (Optional) Add Playwright E2E in CI to cover:
    • Template creation, selection, variable substitution on Resume
    • Auto-follow-up chaining advancing chainProgress
    • Watcher toast + desktop notifications on status transitions
  • (Optional) Webhook-to-cache fast-path for fewer polls

Files touched

  • CodegenRestDashboard/dashboard/state/store.js
  • CodegenRestDashboard/dashboard/services/watcher.js
  • CodegenRestDashboard/server.js
  • CodegenRestDashboard/utils/apiClient.js
  • CodegenRestDashboard/dashboard/utils/templateEngine.js (new)
  • CodegenRestDashboard/commands/render_template.js (new)
  • CodegenRestDashboard/dashboard/components/runDialog.js (templating + selector init)

Happy to iterate further or port changes to the other dashboard PRs after you decide which one to keep as the base.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 9 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="CodegenRestDashboard/utils/templateEngine.js">

<violation number="1" location="CodegenRestDashboard/utils/templateEngine.js:20">
P2: Referencing `module` without checking if CommonJS exports exist causes the browser build to throw immediately. Guard the assignment before accessing `module`.</violation>
</file>

<file name="CodegenRestDashboard/server.js">

<violation number="1" location="CodegenRestDashboard/server.js:55">
P1: `startsWith` does not prevent directory traversal; a request like `/../dashboard.config.json` resolves outside `dashboard/` but still passes the guard because the path string begins with the same prefix. Use `path.relative` (or append a path separator) to ensure the resolved path stays inside the static root.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

const baseDir = path.join(__dirname, 'dashboard');
const rel = file.replace(/^\/+/, '');
const p = path.normalize(path.join(baseDir, rel));
if (!p.startsWith(baseDir)) {
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: startsWith does not prevent directory traversal; a request like /../dashboard.config.json resolves outside dashboard/ but still passes the guard because the path string begins with the same prefix. Use path.relative (or append a path separator) to ensure the resolved path stays inside the static root.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At CodegenRestDashboard/server.js, line 55:

<comment>`startsWith` does not prevent directory traversal; a request like `/../dashboard.config.json` resolves outside `dashboard/` but still passes the guard because the path string begins with the same prefix. Use `path.relative` (or append a path separator) to ensure the resolved path stays inside the static root.</comment>

<file context>
@@ -46,10 +46,13 @@ function contentType(filePath) {
+  const baseDir = path.join(__dirname, 'dashboard');
+  const rel = file.replace(/^\/+/, '');
+  const p = path.normalize(path.join(baseDir, rel));
+  if (!p.startsWith(baseDir)) {
     res.writeHead(403); return res.end('Forbidden');
   }
</file context>
Fix with Cubic


// Expose for browser and Node
if (typeof window !== 'undefined') window.CGTemplate = { renderTemplate };
module.exports = { renderTemplate };
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Referencing module without checking if CommonJS exports exist causes the browser build to throw immediately. Guard the assignment before accessing module.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At CodegenRestDashboard/utils/templateEngine.js, line 20:

<comment>Referencing `module` without checking if CommonJS exports exist causes the browser build to throw immediately. Guard the assignment before accessing `module`.</comment>

<file context>
@@ -0,0 +1,22 @@
+
+  // Expose for browser and Node
+  if (typeof window !== 'undefined') window.CGTemplate = { renderTemplate };
+  module.exports = { renderTemplate };
+})();
+
</file context>
Fix with Cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant