mirror of
https://github.com/hanzo-apps/world.git
synced 2026-10-30 14:53:09 +00:00
PART 1 — one introspectable command registry + one dispatcher (decomplected): - src/services/app-commands.ts is the single source of truth: AppHost capability port + 16 typed commands (name, JSON-schema params, human description, run()) + commandManifest() + the ONE dispatch(): gate (sign-in) → validate → execute → visible action log. Full control now covers panels (show/hide/move/resize), map (layers, 2D/3D, fly-to, region, time range), variant, theme, search, reset layout, custom feeds, and org switch — each driving existing App APIs through the port (no reaching into internals). - analyst-actions.ts reduced to a type shim (AnalystHost=AppHost). AnalystChat dispatches through the registry and renders per-command ✓/✗ entries. - Go tool contract DERIVES from the registry: the client sends its manifest with every request; handlers_analyst.go builds the action-contract prompt from it (renderCommandContract) and passes actions through generically, gated by the manifest's type set — the backend no longer duplicates the schema. Embedded mirror data/analyst_commands.json (generated by scripts/gen-analyst-commands.mjs, drift-guarded by TestAnalystCommandManifest) covers callers that omit a manifest. Model dropdown + backend plane (CTO directive): - Chat header carries a monochrome model select (Zen family first, then upstream /v1/models + agents); choice persists and rides every request. New same-origin /v1/world/models proxy; model passes through to inference (chatMessagesModel). "agent:<ref>" ids route to the agents run plane (invoke an agent in-chat). P0 — errors always visible: the chat never shows a blank. An empty/degraded/errored backend reply (e.g. prod's aud=hanzo-world 401) now surfaces the reason inline. PART 2 — transport seam: src/services/analyst-transport.ts isolates the wire; HTTP is the real impl, registerTransport() is the ZAP seam. Verdict: real browser ZAP (@zap-proto/web) exists and is production-wired in hanzo/platform, but world has no ZAP dep and no Go WS-ZAP server, and ZAP has no streaming primitive today — so HTTP stays default, ZAP wiring documented in-file (no fantasy transport). Gates: tsc + vite build + go build + go test ./internal/world/ all pass; Playwright (e2e/analyst-command.spec.ts) proves signed-out sign-in prompt and a signed-in command round-trip that visibly moves a panel + logs the action (screens/). Co-authored-by: Hanzo Dev <[email protected]>
41 lines
1.5 KiB
JavaScript
41 lines
1.5 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Generate the backend's static command manifest mirror from the ONE source of
|
|
* truth — src/services/app-commands.ts (the client registry).
|
|
*
|
|
* The client always sends its live manifest with each analyst request, so the
|
|
* runtime contract has zero drift by construction. This generated file is the
|
|
* FALLBACK the Go backend embeds for callers that don't send one, and the Go
|
|
* test (TestAnalystCommandManifest) verifies it stays structurally sound and
|
|
* complete. Re-run after changing the registry:
|
|
*
|
|
* node scripts/gen-analyst-commands.mjs
|
|
*
|
|
* app-commands.ts imports nothing, so esbuild transpiles it standalone.
|
|
*/
|
|
import { build } from 'esbuild';
|
|
import { writeFileSync, mkdtempSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import { pathToFileURL } from 'node:url';
|
|
|
|
const SRC = new URL('../src/services/app-commands.ts', import.meta.url).pathname;
|
|
const OUT = new URL('../internal/world/data/analyst_commands.json', import.meta.url).pathname;
|
|
|
|
const res = await build({
|
|
entryPoints: [SRC],
|
|
bundle: true,
|
|
format: 'esm',
|
|
platform: 'neutral',
|
|
write: false,
|
|
});
|
|
|
|
const tmp = join(mkdtempSync(join(tmpdir(), 'zap-cmds-')), 'app-commands.mjs');
|
|
writeFileSync(tmp, res.outputFiles[0].text);
|
|
|
|
const mod = await import(pathToFileURL(tmp).href);
|
|
const manifest = mod.commandManifest();
|
|
|
|
writeFileSync(OUT, JSON.stringify(manifest, null, 2) + '\n');
|
|
console.log(`wrote ${manifest.length} commands → ${OUT}`);
|