@guuey/create-agentic-app 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -2
- package/dist/{chunk-JD4RAKEG.js → chunk-5V2IFXD4.js} +96 -21
- package/dist/cli.cjs +145 -17
- package/dist/cli.js +60 -5
- package/dist/index.cjs +97 -21
- package/dist/index.d.cts +33 -2
- package/dist/index.d.ts +33 -2
- package/dist/index.js +3 -1
- package/dist/templates/{openai-agents-sdk → agentic-app/claude-agent-sdk}/AGENTS.md +2 -2
- package/dist/templates/{openai-agents-sdk → agentic-app/claude-agent-sdk}/README.md +23 -7
- package/dist/templates/agentic-app/claude-agent-sdk/gitignore +5 -0
- package/dist/templates/agentic-app/claude-agent-sdk/guuey.app.json +28 -0
- package/dist/templates/agentic-app/claude-agent-sdk/guuey.app.schema.json +119 -0
- package/dist/templates/{claude-agent-sdk → agentic-app/claude-agent-sdk}/package.json +6 -3
- package/dist/templates/agentic-app/claude-agent-sdk/scripts/bootstrap.mjs +398 -0
- package/dist/templates/{claude-agent-sdk → agentic-app/claude-agent-sdk}/web/index.html +0 -1
- package/dist/templates/agentic-app/claude-agent-sdk/web/package.json +29 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/components/AgentChat.tsx +91 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/components/AppShell.tsx +139 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/components/BootstrapGate.tsx +30 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/components/QrLink.tsx +25 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/components/Shell.tsx +50 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/config.ts +148 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/lib/identity.ts +67 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/lib/oidc.ts +79 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/lib/status.ts +45 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/lib/widget.ts +96 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/main.tsx +51 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/pages/Dashboard.tsx +33 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/pages/Home.tsx +133 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/pages/Landing.tsx +65 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/pages/Login.tsx +81 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/pages/Reports.tsx +9 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/pages/TalkOnMobile.tsx +34 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/routes.ts +7 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/styles-app.css +130 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/styles.css +248 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/src/vite-env.d.ts +14 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/tsconfig.json +18 -0
- package/dist/templates/agentic-app/claude-agent-sdk/web/vite.config.ts +46 -0
- package/dist/templates/{google-adk → agentic-app/google-adk}/AGENTS.md +2 -2
- package/dist/templates/agentic-app/google-adk/gitignore +5 -0
- package/dist/templates/agentic-app/google-adk/guuey.app.json +28 -0
- package/dist/templates/agentic-app/google-adk/guuey.app.schema.json +119 -0
- package/dist/templates/{google-adk → agentic-app/google-adk}/package.json +6 -3
- package/dist/templates/agentic-app/google-adk/scripts/bootstrap.mjs +398 -0
- package/dist/templates/{google-adk → agentic-app/google-adk}/web/index.html +0 -1
- package/dist/templates/agentic-app/google-adk/web/package.json +29 -0
- package/dist/templates/agentic-app/google-adk/web/src/components/AgentChat.tsx +91 -0
- package/dist/templates/agentic-app/google-adk/web/src/components/AppShell.tsx +139 -0
- package/dist/templates/agentic-app/google-adk/web/src/components/BootstrapGate.tsx +30 -0
- package/dist/templates/agentic-app/google-adk/web/src/components/QrLink.tsx +25 -0
- package/dist/templates/agentic-app/google-adk/web/src/components/Shell.tsx +50 -0
- package/dist/templates/agentic-app/google-adk/web/src/config.ts +148 -0
- package/dist/templates/agentic-app/google-adk/web/src/lib/identity.ts +67 -0
- package/dist/templates/agentic-app/google-adk/web/src/lib/oidc.ts +79 -0
- package/dist/templates/agentic-app/google-adk/web/src/lib/status.ts +45 -0
- package/dist/templates/agentic-app/google-adk/web/src/lib/widget.ts +96 -0
- package/dist/templates/agentic-app/google-adk/web/src/main.tsx +51 -0
- package/dist/templates/agentic-app/google-adk/web/src/pages/Dashboard.tsx +33 -0
- package/dist/templates/agentic-app/google-adk/web/src/pages/Home.tsx +133 -0
- package/dist/templates/agentic-app/google-adk/web/src/pages/Landing.tsx +65 -0
- package/dist/templates/agentic-app/google-adk/web/src/pages/Login.tsx +81 -0
- package/dist/templates/agentic-app/google-adk/web/src/pages/Reports.tsx +9 -0
- package/dist/templates/agentic-app/google-adk/web/src/pages/TalkOnMobile.tsx +34 -0
- package/dist/templates/agentic-app/google-adk/web/src/routes.ts +7 -0
- package/dist/templates/agentic-app/google-adk/web/src/styles-app.css +130 -0
- package/dist/templates/agentic-app/google-adk/web/src/styles.css +248 -0
- package/dist/templates/agentic-app/google-adk/web/src/vite-env.d.ts +14 -0
- package/dist/templates/agentic-app/google-adk/web/tsconfig.json +18 -0
- package/dist/templates/agentic-app/google-adk/web/vite.config.ts +46 -0
- package/dist/templates/{claude-agent-sdk → agentic-app/openai-agents-sdk}/AGENTS.md +2 -2
- package/dist/templates/{claude-agent-sdk → agentic-app/openai-agents-sdk}/README.md +23 -7
- package/dist/templates/agentic-app/openai-agents-sdk/gitignore +5 -0
- package/dist/templates/agentic-app/openai-agents-sdk/guuey.app.json +28 -0
- package/dist/templates/agentic-app/openai-agents-sdk/guuey.app.schema.json +119 -0
- package/dist/templates/{openai-agents-sdk → agentic-app/openai-agents-sdk}/package.json +6 -3
- package/dist/templates/agentic-app/openai-agents-sdk/scripts/bootstrap.mjs +398 -0
- package/dist/templates/{openai-agents-sdk → agentic-app/openai-agents-sdk}/web/index.html +0 -1
- package/dist/templates/agentic-app/openai-agents-sdk/web/package.json +29 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/components/AgentChat.tsx +91 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/components/AppShell.tsx +139 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/components/BootstrapGate.tsx +30 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/components/QrLink.tsx +25 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/components/Shell.tsx +50 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/config.ts +148 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/lib/identity.ts +67 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/lib/oidc.ts +79 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/lib/status.ts +45 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/lib/widget.ts +96 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/main.tsx +51 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/pages/Dashboard.tsx +33 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/pages/Home.tsx +133 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/pages/Landing.tsx +65 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/pages/Login.tsx +81 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/pages/Reports.tsx +9 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/pages/TalkOnMobile.tsx +34 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/routes.ts +7 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/styles-app.css +130 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/styles.css +248 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/src/vite-env.d.ts +14 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/tsconfig.json +18 -0
- package/dist/templates/agentic-app/openai-agents-sdk/web/vite.config.ts +46 -0
- package/dist/templates/base/claude-agent-sdk/.env.example +4 -0
- package/dist/templates/base/claude-agent-sdk/.mcp.json +1 -0
- package/dist/templates/base/claude-agent-sdk/AGENTS.md +135 -0
- package/dist/templates/base/claude-agent-sdk/README.md +173 -0
- package/dist/templates/base/claude-agent-sdk/ggui/blueprints/.gitkeep +0 -0
- package/dist/templates/base/claude-agent-sdk/ggui/ggui.json +15 -0
- package/dist/templates/base/claude-agent-sdk/ggui/themes/.gitkeep +0 -0
- package/dist/templates/base/claude-agent-sdk/gitignore +5 -0
- package/dist/templates/base/claude-agent-sdk/guuey.app.json +28 -0
- package/dist/templates/base/claude-agent-sdk/guuey.app.schema.json +119 -0
- package/dist/templates/base/claude-agent-sdk/guuey.json +14 -0
- package/dist/templates/base/claude-agent-sdk/mcps/todo/Dockerfile +46 -0
- package/dist/templates/base/claude-agent-sdk/mcps/todo/package.json +22 -0
- package/dist/templates/base/claude-agent-sdk/mcps/todo/src/server.ts +173 -0
- package/dist/templates/base/claude-agent-sdk/mcps/todo/tsconfig.json +15 -0
- package/dist/templates/base/claude-agent-sdk/mcps/todo/tsup.config.ts +14 -0
- package/dist/templates/base/claude-agent-sdk/package.json +30 -0
- package/dist/templates/base/claude-agent-sdk/pnpm-workspace.yaml +24 -0
- package/dist/templates/base/claude-agent-sdk/prompts/system.md +4 -0
- package/dist/templates/base/claude-agent-sdk/scripts/bootstrap.mjs +398 -0
- package/dist/templates/base/claude-agent-sdk/scripts/dev.mjs +45 -0
- package/dist/templates/base/claude-agent-sdk/src/agent-config.ts +77 -0
- package/dist/templates/base/claude-agent-sdk/src/worker.ts +89 -0
- package/dist/templates/base/claude-agent-sdk/tsconfig.json +15 -0
- package/dist/templates/base/claude-agent-sdk/tsup.config.ts +9 -0
- package/dist/templates/base/claude-agent-sdk/web/index.html +12 -0
- package/dist/templates/{claude-agent-sdk → base/claude-agent-sdk}/web/package.json +11 -8
- package/dist/templates/base/claude-agent-sdk/web/src/components/AgentChat.tsx +91 -0
- package/dist/templates/base/claude-agent-sdk/web/src/components/BootstrapGate.tsx +30 -0
- package/dist/templates/base/claude-agent-sdk/web/src/components/QrLink.tsx +25 -0
- package/dist/templates/base/claude-agent-sdk/web/src/components/Shell.tsx +50 -0
- package/dist/templates/base/claude-agent-sdk/web/src/config.ts +148 -0
- package/dist/templates/base/claude-agent-sdk/web/src/lib/identity.ts +67 -0
- package/dist/templates/base/claude-agent-sdk/web/src/lib/oidc.ts +79 -0
- package/dist/templates/base/claude-agent-sdk/web/src/lib/status.ts +45 -0
- package/dist/templates/base/claude-agent-sdk/web/src/lib/widget.ts +96 -0
- package/dist/templates/base/claude-agent-sdk/web/src/main.tsx +52 -0
- package/dist/templates/base/claude-agent-sdk/web/src/pages/Chat.tsx +15 -0
- package/dist/templates/base/claude-agent-sdk/web/src/pages/Home.tsx +133 -0
- package/dist/templates/base/claude-agent-sdk/web/src/pages/Landing.tsx +65 -0
- package/dist/templates/base/claude-agent-sdk/web/src/pages/Login.tsx +81 -0
- package/dist/templates/base/claude-agent-sdk/web/src/routes.ts +7 -0
- package/dist/templates/base/claude-agent-sdk/web/src/styles.css +248 -0
- package/dist/templates/base/claude-agent-sdk/web/src/vite-env.d.ts +14 -0
- package/dist/templates/base/claude-agent-sdk/web/tsconfig.json +18 -0
- package/dist/templates/base/claude-agent-sdk/web/vite.config.ts +46 -0
- package/dist/templates/base/google-adk/.env.example +4 -0
- package/dist/templates/base/google-adk/.mcp.json +1 -0
- package/dist/templates/base/google-adk/AGENTS.md +135 -0
- package/dist/templates/base/google-adk/README.md +90 -0
- package/dist/templates/base/google-adk/ggui/blueprints/.gitkeep +0 -0
- package/dist/templates/base/google-adk/ggui/ggui.json +15 -0
- package/dist/templates/base/google-adk/ggui/themes/.gitkeep +0 -0
- package/dist/templates/base/google-adk/gitignore +5 -0
- package/dist/templates/base/google-adk/guuey.app.json +28 -0
- package/dist/templates/base/google-adk/guuey.app.schema.json +119 -0
- package/dist/templates/base/google-adk/guuey.json +15 -0
- package/dist/templates/base/google-adk/mcps/todo/Dockerfile +46 -0
- package/dist/templates/base/google-adk/mcps/todo/package.json +22 -0
- package/dist/templates/base/google-adk/mcps/todo/src/server.ts +173 -0
- package/dist/templates/base/google-adk/mcps/todo/tsconfig.json +15 -0
- package/dist/templates/base/google-adk/mcps/todo/tsup.config.ts +14 -0
- package/dist/templates/base/google-adk/package.json +30 -0
- package/dist/templates/base/google-adk/pnpm-workspace.yaml +34 -0
- package/dist/templates/base/google-adk/prompts/system.md +4 -0
- package/dist/templates/base/google-adk/scripts/bootstrap.mjs +398 -0
- package/dist/templates/base/google-adk/scripts/dev.mjs +45 -0
- package/dist/templates/base/google-adk/src/agent.ts +43 -0
- package/dist/templates/base/google-adk/tsconfig.json +15 -0
- package/dist/templates/base/google-adk/tsup.config.ts +13 -0
- package/dist/templates/base/google-adk/web/index.html +12 -0
- package/dist/templates/{google-adk → base/google-adk}/web/package.json +11 -8
- package/dist/templates/base/google-adk/web/src/components/AgentChat.tsx +91 -0
- package/dist/templates/base/google-adk/web/src/components/BootstrapGate.tsx +30 -0
- package/dist/templates/base/google-adk/web/src/components/QrLink.tsx +25 -0
- package/dist/templates/base/google-adk/web/src/components/Shell.tsx +50 -0
- package/dist/templates/base/google-adk/web/src/config.ts +148 -0
- package/dist/templates/base/google-adk/web/src/lib/identity.ts +67 -0
- package/dist/templates/base/google-adk/web/src/lib/oidc.ts +79 -0
- package/dist/templates/base/google-adk/web/src/lib/status.ts +45 -0
- package/dist/templates/base/google-adk/web/src/lib/widget.ts +96 -0
- package/dist/templates/base/google-adk/web/src/main.tsx +52 -0
- package/dist/templates/base/google-adk/web/src/pages/Chat.tsx +15 -0
- package/dist/templates/base/google-adk/web/src/pages/Home.tsx +133 -0
- package/dist/templates/base/google-adk/web/src/pages/Landing.tsx +65 -0
- package/dist/templates/base/google-adk/web/src/pages/Login.tsx +81 -0
- package/dist/templates/base/google-adk/web/src/routes.ts +7 -0
- package/dist/templates/base/google-adk/web/src/styles.css +248 -0
- package/dist/templates/base/google-adk/web/src/vite-env.d.ts +14 -0
- package/dist/templates/base/google-adk/web/tsconfig.json +18 -0
- package/dist/templates/base/google-adk/web/vite.config.ts +46 -0
- package/dist/templates/base/openai-agents-sdk/.env.example +4 -0
- package/dist/templates/base/openai-agents-sdk/.mcp.json +1 -0
- package/dist/templates/base/openai-agents-sdk/AGENTS.md +135 -0
- package/dist/templates/base/openai-agents-sdk/README.md +173 -0
- package/dist/templates/base/openai-agents-sdk/ggui/blueprints/.gitkeep +0 -0
- package/dist/templates/base/openai-agents-sdk/ggui/ggui.json +15 -0
- package/dist/templates/base/openai-agents-sdk/ggui/themes/.gitkeep +0 -0
- package/dist/templates/base/openai-agents-sdk/gitignore +5 -0
- package/dist/templates/base/openai-agents-sdk/guuey.app.json +28 -0
- package/dist/templates/base/openai-agents-sdk/guuey.app.schema.json +119 -0
- package/dist/templates/base/openai-agents-sdk/guuey.json +27 -0
- package/dist/templates/base/openai-agents-sdk/mcps/todo/Dockerfile +46 -0
- package/dist/templates/base/openai-agents-sdk/mcps/todo/package.json +22 -0
- package/dist/templates/base/openai-agents-sdk/mcps/todo/src/server.ts +173 -0
- package/dist/templates/base/openai-agents-sdk/mcps/todo/tsconfig.json +15 -0
- package/dist/templates/base/openai-agents-sdk/mcps/todo/tsup.config.ts +14 -0
- package/dist/templates/base/openai-agents-sdk/package.json +30 -0
- package/dist/templates/base/openai-agents-sdk/pnpm-workspace.yaml +24 -0
- package/dist/templates/base/openai-agents-sdk/prompts/system.md +4 -0
- package/dist/templates/base/openai-agents-sdk/scripts/bootstrap.mjs +398 -0
- package/dist/templates/base/openai-agents-sdk/scripts/dev.mjs +45 -0
- package/dist/templates/base/openai-agents-sdk/src/agent-config.ts +77 -0
- package/dist/templates/base/openai-agents-sdk/src/worker.ts +75 -0
- package/dist/templates/base/openai-agents-sdk/tsconfig.json +15 -0
- package/dist/templates/base/openai-agents-sdk/tsup.config.ts +16 -0
- package/dist/templates/base/openai-agents-sdk/web/index.html +12 -0
- package/dist/templates/{openai-agents-sdk → base/openai-agents-sdk}/web/package.json +11 -8
- package/dist/templates/base/openai-agents-sdk/web/src/components/AgentChat.tsx +91 -0
- package/dist/templates/base/openai-agents-sdk/web/src/components/BootstrapGate.tsx +30 -0
- package/dist/templates/base/openai-agents-sdk/web/src/components/QrLink.tsx +25 -0
- package/dist/templates/base/openai-agents-sdk/web/src/components/Shell.tsx +50 -0
- package/dist/templates/base/openai-agents-sdk/web/src/config.ts +148 -0
- package/dist/templates/base/openai-agents-sdk/web/src/lib/identity.ts +67 -0
- package/dist/templates/base/openai-agents-sdk/web/src/lib/oidc.ts +79 -0
- package/dist/templates/base/openai-agents-sdk/web/src/lib/status.ts +45 -0
- package/dist/templates/base/openai-agents-sdk/web/src/lib/widget.ts +96 -0
- package/dist/templates/base/openai-agents-sdk/web/src/main.tsx +52 -0
- package/dist/templates/base/openai-agents-sdk/web/src/pages/Chat.tsx +15 -0
- package/dist/templates/base/openai-agents-sdk/web/src/pages/Home.tsx +133 -0
- package/dist/templates/base/openai-agents-sdk/web/src/pages/Landing.tsx +65 -0
- package/dist/templates/base/openai-agents-sdk/web/src/pages/Login.tsx +81 -0
- package/dist/templates/base/openai-agents-sdk/web/src/routes.ts +7 -0
- package/dist/templates/base/openai-agents-sdk/web/src/styles.css +248 -0
- package/dist/templates/base/openai-agents-sdk/web/src/vite-env.d.ts +14 -0
- package/dist/templates/base/openai-agents-sdk/web/tsconfig.json +18 -0
- package/dist/templates/base/openai-agents-sdk/web/vite.config.ts +46 -0
- package/package.json +6 -3
- package/dist/templates/claude-agent-sdk/web/.env.example +0 -17
- package/dist/templates/claude-agent-sdk/web/sandbox-proxy.ts +0 -239
- package/dist/templates/claude-agent-sdk/web/src/App.tsx +0 -272
- package/dist/templates/claude-agent-sdk/web/src/main.tsx +0 -12
- package/dist/templates/claude-agent-sdk/web/src/useAgentChat.ts +0 -122
- package/dist/templates/claude-agent-sdk/web/src/vite-env.d.ts +0 -27
- package/dist/templates/claude-agent-sdk/web/tsconfig.json +0 -20
- package/dist/templates/claude-agent-sdk/web/vite.config.ts +0 -12
- package/dist/templates/google-adk/web/.env.example +0 -17
- package/dist/templates/google-adk/web/sandbox-proxy.ts +0 -239
- package/dist/templates/google-adk/web/src/App.tsx +0 -272
- package/dist/templates/google-adk/web/src/main.tsx +0 -12
- package/dist/templates/google-adk/web/src/useAgentChat.ts +0 -122
- package/dist/templates/google-adk/web/src/vite-env.d.ts +0 -27
- package/dist/templates/google-adk/web/tsconfig.json +0 -20
- package/dist/templates/google-adk/web/vite.config.ts +0 -12
- package/dist/templates/openai-agents-sdk/web/.env.example +0 -17
- package/dist/templates/openai-agents-sdk/web/sandbox-proxy.ts +0 -239
- package/dist/templates/openai-agents-sdk/web/src/App.tsx +0 -272
- package/dist/templates/openai-agents-sdk/web/src/main.tsx +0 -12
- package/dist/templates/openai-agents-sdk/web/src/useAgentChat.ts +0 -122
- package/dist/templates/openai-agents-sdk/web/src/vite-env.d.ts +0 -27
- package/dist/templates/openai-agents-sdk/web/tsconfig.json +0 -20
- package/dist/templates/openai-agents-sdk/web/vite.config.ts +0 -12
- /package/dist/templates/{claude-agent-sdk → agentic-app/claude-agent-sdk}/.env.example +0 -0
- /package/dist/templates/{claude-agent-sdk → agentic-app/claude-agent-sdk}/.mcp.json +0 -0
- /package/dist/templates/{claude-agent-sdk → agentic-app/claude-agent-sdk}/ggui/blueprints/.gitkeep +0 -0
- /package/dist/templates/{claude-agent-sdk → agentic-app/claude-agent-sdk}/ggui/ggui.json +0 -0
- /package/dist/templates/{claude-agent-sdk → agentic-app/claude-agent-sdk}/ggui/themes/.gitkeep +0 -0
- /package/dist/templates/{claude-agent-sdk → agentic-app/claude-agent-sdk}/guuey.json +0 -0
- /package/dist/templates/{claude-agent-sdk → agentic-app/claude-agent-sdk}/mcps/todo/Dockerfile +0 -0
- /package/dist/templates/{claude-agent-sdk → agentic-app/claude-agent-sdk}/mcps/todo/package.json +0 -0
- /package/dist/templates/{claude-agent-sdk → agentic-app/claude-agent-sdk}/mcps/todo/src/server.ts +0 -0
- /package/dist/templates/{claude-agent-sdk → agentic-app/claude-agent-sdk}/mcps/todo/tsconfig.json +0 -0
- /package/dist/templates/{claude-agent-sdk → agentic-app/claude-agent-sdk}/mcps/todo/tsup.config.ts +0 -0
- /package/dist/templates/{claude-agent-sdk → agentic-app/claude-agent-sdk}/pnpm-workspace.yaml +0 -0
- /package/dist/templates/{claude-agent-sdk → agentic-app/claude-agent-sdk}/prompts/system.md +0 -0
- /package/dist/templates/{claude-agent-sdk → agentic-app/claude-agent-sdk}/scripts/dev.mjs +0 -0
- /package/dist/templates/{claude-agent-sdk → agentic-app/claude-agent-sdk}/src/agent-config.ts +0 -0
- /package/dist/templates/{claude-agent-sdk → agentic-app/claude-agent-sdk}/src/worker.ts +0 -0
- /package/dist/templates/{claude-agent-sdk → agentic-app/claude-agent-sdk}/tsconfig.json +0 -0
- /package/dist/templates/{claude-agent-sdk → agentic-app/claude-agent-sdk}/tsup.config.ts +0 -0
- /package/dist/templates/{google-adk → agentic-app/google-adk}/.env.example +0 -0
- /package/dist/templates/{google-adk → agentic-app/google-adk}/.mcp.json +0 -0
- /package/dist/templates/{google-adk → agentic-app/google-adk}/README.md +0 -0
- /package/dist/templates/{google-adk → agentic-app/google-adk}/ggui/blueprints/.gitkeep +0 -0
- /package/dist/templates/{google-adk → agentic-app/google-adk}/ggui/ggui.json +0 -0
- /package/dist/templates/{google-adk → agentic-app/google-adk}/ggui/themes/.gitkeep +0 -0
- /package/dist/templates/{google-adk → agentic-app/google-adk}/guuey.json +0 -0
- /package/dist/templates/{google-adk → agentic-app/google-adk}/mcps/todo/Dockerfile +0 -0
- /package/dist/templates/{google-adk → agentic-app/google-adk}/mcps/todo/package.json +0 -0
- /package/dist/templates/{google-adk → agentic-app/google-adk}/mcps/todo/src/server.ts +0 -0
- /package/dist/templates/{google-adk → agentic-app/google-adk}/mcps/todo/tsconfig.json +0 -0
- /package/dist/templates/{google-adk → agentic-app/google-adk}/mcps/todo/tsup.config.ts +0 -0
- /package/dist/templates/{google-adk → agentic-app/google-adk}/pnpm-workspace.yaml +0 -0
- /package/dist/templates/{google-adk → agentic-app/google-adk}/prompts/system.md +0 -0
- /package/dist/templates/{google-adk → agentic-app/google-adk}/scripts/dev.mjs +0 -0
- /package/dist/templates/{google-adk → agentic-app/google-adk}/src/agent.ts +0 -0
- /package/dist/templates/{google-adk → agentic-app/google-adk}/tsconfig.json +0 -0
- /package/dist/templates/{google-adk → agentic-app/google-adk}/tsup.config.ts +0 -0
- /package/dist/templates/{openai-agents-sdk → agentic-app/openai-agents-sdk}/.env.example +0 -0
- /package/dist/templates/{openai-agents-sdk → agentic-app/openai-agents-sdk}/.mcp.json +0 -0
- /package/dist/templates/{openai-agents-sdk → agentic-app/openai-agents-sdk}/ggui/blueprints/.gitkeep +0 -0
- /package/dist/templates/{openai-agents-sdk → agentic-app/openai-agents-sdk}/ggui/ggui.json +0 -0
- /package/dist/templates/{openai-agents-sdk → agentic-app/openai-agents-sdk}/ggui/themes/.gitkeep +0 -0
- /package/dist/templates/{openai-agents-sdk → agentic-app/openai-agents-sdk}/guuey.json +0 -0
- /package/dist/templates/{openai-agents-sdk → agentic-app/openai-agents-sdk}/mcps/todo/Dockerfile +0 -0
- /package/dist/templates/{openai-agents-sdk → agentic-app/openai-agents-sdk}/mcps/todo/package.json +0 -0
- /package/dist/templates/{openai-agents-sdk → agentic-app/openai-agents-sdk}/mcps/todo/src/server.ts +0 -0
- /package/dist/templates/{openai-agents-sdk → agentic-app/openai-agents-sdk}/mcps/todo/tsconfig.json +0 -0
- /package/dist/templates/{openai-agents-sdk → agentic-app/openai-agents-sdk}/mcps/todo/tsup.config.ts +0 -0
- /package/dist/templates/{openai-agents-sdk → agentic-app/openai-agents-sdk}/pnpm-workspace.yaml +0 -0
- /package/dist/templates/{openai-agents-sdk → agentic-app/openai-agents-sdk}/prompts/system.md +0 -0
- /package/dist/templates/{openai-agents-sdk → agentic-app/openai-agents-sdk}/scripts/dev.mjs +0 -0
- /package/dist/templates/{openai-agents-sdk → agentic-app/openai-agents-sdk}/src/agent-config.ts +0 -0
- /package/dist/templates/{openai-agents-sdk → agentic-app/openai-agents-sdk}/src/worker.ts +0 -0
- /package/dist/templates/{openai-agents-sdk → agentic-app/openai-agents-sdk}/tsconfig.json +0 -0
- /package/dist/templates/{openai-agents-sdk → agentic-app/openai-agents-sdk}/tsup.config.ts +0 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// pnpm dev — boots the whole local stack. Ctrl-C tears everything down.
|
|
3
|
+
import { spawn } from "node:child_process";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
|
|
6
|
+
const procs = [];
|
|
7
|
+
function boot(name, command, args, opts = {}) {
|
|
8
|
+
const child = spawn(command, args, { stdio: ["ignore", "pipe", "pipe"], ...opts });
|
|
9
|
+
const prefix = `[${name}]`.padEnd(9);
|
|
10
|
+
child.stdout.on("data", (d) => process.stdout.write(String(d).replace(/^/gm, prefix)));
|
|
11
|
+
child.stderr.on("data", (d) => process.stderr.write(String(d).replace(/^/gm, prefix)));
|
|
12
|
+
child.on("exit", (code) => {
|
|
13
|
+
if (code !== 0 && !shuttingDown) shutdown(`${name} exited (${code})`, 1);
|
|
14
|
+
});
|
|
15
|
+
procs.push(child);
|
|
16
|
+
}
|
|
17
|
+
let shuttingDown = false;
|
|
18
|
+
function shutdown(reason, code = 0) {
|
|
19
|
+
if (shuttingDown) return;
|
|
20
|
+
shuttingDown = true;
|
|
21
|
+
console.log(`\n${reason} — shutting down`);
|
|
22
|
+
for (const p of procs) p.kill("SIGTERM");
|
|
23
|
+
setTimeout(() => process.exit(code), 500);
|
|
24
|
+
}
|
|
25
|
+
process.on("SIGINT", () => shutdown("interrupted"));
|
|
26
|
+
process.on("SIGTERM", () => shutdown("terminated"));
|
|
27
|
+
|
|
28
|
+
if (!existsSync(".env.local"))
|
|
29
|
+
console.warn("hint: cp .env.example .env.local and set your LLM key");
|
|
30
|
+
|
|
31
|
+
boot("worker", "pnpm", ["exec", "tsup", "--watch"]); // rebuilds guuey.worker.js on change
|
|
32
|
+
// `guuey dev` auto-spawns every `kind: 'colocated'` mcpServers entry itself
|
|
33
|
+
// (name→localhost devPort resolution) — the todo MCP is colocated, so it no
|
|
34
|
+
// longer needs its own boot() here; a manual second spawn would double-bind
|
|
35
|
+
// :6782 and crash with EADDRINUSE.
|
|
36
|
+
boot("agent", "pnpm", ["exec", "guuey", "dev", "--serve", "--port", "6790"]);
|
|
37
|
+
boot("ggui", "pnpm", ["exec", "ggui", "serve", "--mcp-only", "--dev-allow-all", "--port", "6781"], {
|
|
38
|
+
cwd: "ggui",
|
|
39
|
+
});
|
|
40
|
+
boot("web", "pnpm", ["--filter", "@agentic-app-template/web", "dev"], {
|
|
41
|
+
env: { ...process.env, PORT: "6890" },
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
console.log("\n agent http://localhost:6790 todo-mcp http://localhost:6782");
|
|
45
|
+
console.log(" ggui http://localhost:6781 web http://localhost:6890\n");
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Your agent — pure Google-ADK code. No Guuey SDK, no harness, no event
|
|
3
|
+
* plumbing: export it and the platform runs it (locally via `pnpm dev`,
|
|
4
|
+
* hosted via `guuey deploy`).
|
|
5
|
+
*
|
|
6
|
+
* The default export is a FACTORY receiving everything Guuey resolved for
|
|
7
|
+
* the current turn (`GuueyContext`): the model + instruction from
|
|
8
|
+
* guuey.json, ready-to-use MCP toolsets for every server declared there,
|
|
9
|
+
* the end user's identity, file storage paths, and the conversation state.
|
|
10
|
+
* See the README for the full context tour.
|
|
11
|
+
*/
|
|
12
|
+
import { FunctionTool, LlmAgent, type MCPToolset } from "@google/adk";
|
|
13
|
+
import { z } from "zod";
|
|
14
|
+
import type { GuueyContext } from "@guuey/config";
|
|
15
|
+
|
|
16
|
+
/** A plain ADK tool — everything the ADK offers works unchanged. */
|
|
17
|
+
const rollDice = new FunctionTool({
|
|
18
|
+
name: "roll_dice",
|
|
19
|
+
description: "Roll an N-sided die and return the result.",
|
|
20
|
+
parameters: z.object({
|
|
21
|
+
sides: z.number().int().min(2).describe("number of faces on the die"),
|
|
22
|
+
}),
|
|
23
|
+
execute: async ({ sides }) => ({
|
|
24
|
+
result: 1 + Math.floor(Math.random() * sides),
|
|
25
|
+
}),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export default (guuey: GuueyContext<MCPToolset>) =>
|
|
29
|
+
new LlmAgent({
|
|
30
|
+
name: "my_agent",
|
|
31
|
+
model: guuey.model,
|
|
32
|
+
// `instruction` already carries your system prompt PLUS the conversation
|
|
33
|
+
// preamble (history, thread memory, working state) — your agent is
|
|
34
|
+
// conversational without writing any state code. Wrapped as a function:
|
|
35
|
+
// ADK applies `{var}` session-state substitution to a STRING instruction,
|
|
36
|
+
// and the preamble embeds prior user messages verbatim — if one contains
|
|
37
|
+
// `{anything}`, a string instruction crashes the turn. The function form
|
|
38
|
+
// bypasses substitution entirely.
|
|
39
|
+
instruction: () => guuey.instruction,
|
|
40
|
+
// Your own tools compose with the MCP servers from guuey.json. Drop
|
|
41
|
+
// `...guuey.mcpToolsets` if you want a fully self-contained agent.
|
|
42
|
+
tools: [rollDice, ...guuey.mcpToolsets],
|
|
43
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2023",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"noEmit": true,
|
|
10
|
+
"resolveJsonModule": true,
|
|
11
|
+
"isolatedModules": true
|
|
12
|
+
},
|
|
13
|
+
"include": ["src"],
|
|
14
|
+
"exclude": ["node_modules", "dist"]
|
|
15
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineConfig } from "tsup";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
entry: { agent: "src/agent.ts" },
|
|
5
|
+
format: ["esm"],
|
|
6
|
+
outDir: ".",
|
|
7
|
+
clean: false,
|
|
8
|
+
// Dependencies stay EXTERNAL (tsup's default): the platform installs them
|
|
9
|
+
// from the lockfile at image-build time and the Guuey host imports your
|
|
10
|
+
// agent.js — with @google/adk resolved from YOUR node_modules (your pinned
|
|
11
|
+
// version wins). Do NOT bundle @google/adk; its dependency tree is not
|
|
12
|
+
// bundler-safe.
|
|
13
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>agentic-app-template</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentic-app-template/web",
|
|
3
|
-
"version": "0.0.0",
|
|
4
3
|
"private": true,
|
|
4
|
+
"version": "0.0.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"dev": "vite --port 6890",
|
|
@@ -9,17 +9,20 @@
|
|
|
9
9
|
"typecheck": "tsc --noEmit"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@
|
|
13
|
-
"
|
|
12
|
+
"@guuey/chat": "0.11.0",
|
|
13
|
+
"oidc-client-ts": "^3.1.0",
|
|
14
|
+
"qrcode": "^1.5.4",
|
|
14
15
|
"react": "^19.0.0",
|
|
15
|
-
"react-dom": "^19.0.0"
|
|
16
|
+
"react-dom": "^19.0.0",
|
|
17
|
+
"react-router-dom": "^7.1.0"
|
|
16
18
|
},
|
|
17
19
|
"devDependencies": {
|
|
18
|
-
"@types/node": "^
|
|
20
|
+
"@types/node": "^24.0.0",
|
|
21
|
+
"@types/qrcode": "^1.5.5",
|
|
19
22
|
"@types/react": "^19.0.0",
|
|
20
23
|
"@types/react-dom": "^19.0.0",
|
|
21
|
-
"@vitejs/plugin-react": "^4.3.
|
|
22
|
-
"typescript": "^5.
|
|
23
|
-
"vite": "^
|
|
24
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
25
|
+
"typescript": "^5.7.2",
|
|
26
|
+
"vite": "^7.0.0"
|
|
24
27
|
}
|
|
25
28
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The configured `<GuueyChat>` for this app — distribution way #2, the
|
|
3
|
+
* embedded chat SDK. One place wires endpoint, history, identity and theme;
|
|
4
|
+
* every chat surface (the /chat page here, the fullscreen agent canvas in
|
|
5
|
+
* the agentic-app template) renders this.
|
|
6
|
+
*
|
|
7
|
+
* Identity rule: ONE mode per surface. When OIDC is configured AND a
|
|
8
|
+
* session exists, the bearer wins; otherwise the client-minted guest
|
|
9
|
+
* secret. Never both.
|
|
10
|
+
*/
|
|
11
|
+
import { useEffect, useState, type CSSProperties } from "react";
|
|
12
|
+
import { GuueyChat } from "@guuey/chat/react";
|
|
13
|
+
import type { PlanViewSummary, ViewRefItem } from "@guuey/chat";
|
|
14
|
+
import { agentEndpointUrl, appConfig, historyBaseUrl } from "../config";
|
|
15
|
+
import { currentIdentityMode, ensureGuestSecret } from "../lib/identity";
|
|
16
|
+
import { getBearerToken, currentUser, oidcConfigured } from "../lib/oidc";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The chat-rail bridge (agentic-app shell): with `viewsBridge` set, the
|
|
20
|
+
* chat runs the kit's CHIPS presentation — generative views collapse to
|
|
21
|
+
* compact chips in the rail, the full renders belong to the host's main
|
|
22
|
+
* canvas (fed by `onViewsChange`), and chip clicks re-select
|
|
23
|
+
* (`onViewRef` → `promotedViewKey`, the browser-history mechanic).
|
|
24
|
+
*/
|
|
25
|
+
export interface ViewsBridge {
|
|
26
|
+
promotedViewKey?: string | undefined;
|
|
27
|
+
onViewRef: (item: ViewRefItem) => void;
|
|
28
|
+
onViewsChange: (views: PlanViewSummary[]) => void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Module scope on purpose: props want STABLE identities. An inline
|
|
32
|
+
// `policy={{ … }}` literal (or per-render arrow getters) re-mints every
|
|
33
|
+
// render; the kit stabilizes structurally since 0.11.0, but the template
|
|
34
|
+
// models the correct shape — one identity for the app's whole life.
|
|
35
|
+
const RAIL_POLICY = { view: { timeoutMs: 8000, presentation: "chips" as const } };
|
|
36
|
+
|
|
37
|
+
export function AgentChat({
|
|
38
|
+
className,
|
|
39
|
+
style,
|
|
40
|
+
viewsBridge,
|
|
41
|
+
}: {
|
|
42
|
+
className?: string;
|
|
43
|
+
style?: CSSProperties;
|
|
44
|
+
viewsBridge?: ViewsBridge;
|
|
45
|
+
}) {
|
|
46
|
+
// The user's CHOSEN mode wins: an explicit "Continue as guest" must never
|
|
47
|
+
// be shadowed by a cached OIDC session. Only when no choice is recorded
|
|
48
|
+
// does a live session imply oidc.
|
|
49
|
+
const chosen = currentIdentityMode();
|
|
50
|
+
const [identity, setIdentity] = useState<"resolving" | "guest" | "oidc">(
|
|
51
|
+
chosen === "guest" || !oidcConfigured() ? "guest" : chosen === "oidc" ? "oidc" : "resolving",
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
if (identity !== "resolving") return;
|
|
56
|
+
let cancelled = false;
|
|
57
|
+
void currentUser().then((user) => {
|
|
58
|
+
if (!cancelled) setIdentity(user ? "oidc" : "guest");
|
|
59
|
+
});
|
|
60
|
+
return () => {
|
|
61
|
+
cancelled = true;
|
|
62
|
+
};
|
|
63
|
+
}, [identity]);
|
|
64
|
+
|
|
65
|
+
if (identity === "resolving") return null;
|
|
66
|
+
|
|
67
|
+
const shared = {
|
|
68
|
+
endpointUrl: agentEndpointUrl(),
|
|
69
|
+
appId: appConfig.link?.appId ?? "local",
|
|
70
|
+
apiBaseUrl: historyBaseUrl(),
|
|
71
|
+
mode: appConfig.theme.mode,
|
|
72
|
+
className,
|
|
73
|
+
style,
|
|
74
|
+
...(viewsBridge !== undefined
|
|
75
|
+
? {
|
|
76
|
+
policy: RAIL_POLICY,
|
|
77
|
+
promotedViewKey: viewsBridge.promotedViewKey,
|
|
78
|
+
onViewRef: viewsBridge.onViewRef,
|
|
79
|
+
onViewsChange: viewsBridge.onViewsChange,
|
|
80
|
+
}
|
|
81
|
+
: {}),
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// The lib functions ARE the stable getters — no wrapping arrows (a fresh
|
|
85
|
+
// closure per render is the identity churn RAIL_POLICY exists to avoid).
|
|
86
|
+
return identity === "oidc" ? (
|
|
87
|
+
<GuueyChat {...shared} getAccessToken={getBearerToken} />
|
|
88
|
+
) : (
|
|
89
|
+
<GuueyChat {...shared} getGuestSecret={ensureGuestSecret} />
|
|
90
|
+
);
|
|
91
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dev-time gate: until `pnpm bootstrap` has run, every page renders this
|
|
3
|
+
* setup screen instead of a half-configured app. Production builds are
|
|
4
|
+
* gated harder — vite.config.ts fails the build outright.
|
|
5
|
+
*/
|
|
6
|
+
import type { ReactNode } from "react";
|
|
7
|
+
import { appConfig } from "../config";
|
|
8
|
+
|
|
9
|
+
export function BootstrapGate({ children }: { children: ReactNode }) {
|
|
10
|
+
if (appConfig.bootstrapped) return <>{children}</>;
|
|
11
|
+
return (
|
|
12
|
+
<main className="gate">
|
|
13
|
+
<div className="gate-card">
|
|
14
|
+
<h1>Run bootstrap first</h1>
|
|
15
|
+
<p>
|
|
16
|
+
This project has not been configured yet. From the project root:
|
|
17
|
+
</p>
|
|
18
|
+
<pre>
|
|
19
|
+
<code>pnpm bootstrap</code>
|
|
20
|
+
</pre>
|
|
21
|
+
<p>
|
|
22
|
+
That writes <code>guuey.app.json</code> (brand, theme, copy) and
|
|
23
|
+
regenerates <code>AGENTS.md</code>. Then start the local stack with{" "}
|
|
24
|
+
<code>pnpm dev</code>. When you are ready to bind a deployed guuey
|
|
25
|
+
app: <code>pnpm bootstrap -- --link</code>.
|
|
26
|
+
</p>
|
|
27
|
+
</div>
|
|
28
|
+
</main>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** A QR code for a URL, with the plain link beneath — mobile hand-off. */
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
import QRCode from "qrcode";
|
|
4
|
+
|
|
5
|
+
export function QrLink({ url, size = 200 }: { url: string; size?: number }) {
|
|
6
|
+
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
|
7
|
+
const [error, setError] = useState<string | null>(null);
|
|
8
|
+
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
if (!canvasRef.current) return;
|
|
11
|
+
QRCode.toCanvas(canvasRef.current, url, { width: size, margin: 1 }).catch((err: unknown) => {
|
|
12
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
13
|
+
});
|
|
14
|
+
}, [url, size]);
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<span className="qr-link">
|
|
18
|
+
<canvas ref={canvasRef} className="qr" />
|
|
19
|
+
<a href={url} target="_blank" rel="noreferrer">
|
|
20
|
+
{url}
|
|
21
|
+
</a>
|
|
22
|
+
{error ? <span className="error">QR render failed: {error}</span> : null}
|
|
23
|
+
</span>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base-template chrome: brand header + nav + auth affordance. Pages render
|
|
3
|
+
* inside via the router outlet.
|
|
4
|
+
*/
|
|
5
|
+
import { Link, NavLink, Outlet, useLocation, useNavigate } from "react-router-dom";
|
|
6
|
+
import { appConfig } from "../config";
|
|
7
|
+
import { CHAT_PATH, HOME_PATH } from "../routes";
|
|
8
|
+
import { currentIdentityMode, logOut } from "../lib/identity";
|
|
9
|
+
import { oidcConfigured, signOutOidc } from "../lib/oidc";
|
|
10
|
+
|
|
11
|
+
export function Shell() {
|
|
12
|
+
const navigate = useNavigate();
|
|
13
|
+
// Subscribing to the location re-renders this chrome on every navigation,
|
|
14
|
+
// so the render-time read below stays fresh after login/logout. (A
|
|
15
|
+
// `storage` listener would NOT work — that event only fires in OTHER
|
|
16
|
+
// tabs, never the one that wrote the change.)
|
|
17
|
+
useLocation();
|
|
18
|
+
const mode = currentIdentityMode();
|
|
19
|
+
|
|
20
|
+
async function handleLogOut() {
|
|
21
|
+
if (mode === "oidc" && oidcConfigured()) await signOutOidc();
|
|
22
|
+
logOut();
|
|
23
|
+
navigate("/");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div className="shell">
|
|
28
|
+
<header className="topbar">
|
|
29
|
+
<Link to="/" className="brand">
|
|
30
|
+
<span className="brand-mark">{appConfig.brand.logoText}</span>
|
|
31
|
+
<span>{appConfig.brand.name}</span>
|
|
32
|
+
</Link>
|
|
33
|
+
<nav>
|
|
34
|
+
<NavLink to={CHAT_PATH}>Chat</NavLink>
|
|
35
|
+
<NavLink to={HOME_PATH}>Home</NavLink>
|
|
36
|
+
{mode === null ? (
|
|
37
|
+
<NavLink to="/login" className="btn btn-accent">
|
|
38
|
+
Sign in
|
|
39
|
+
</NavLink>
|
|
40
|
+
) : (
|
|
41
|
+
<button type="button" className="btn" onClick={() => void handleLogOut()}>
|
|
42
|
+
Log out{mode === "guest" ? " (guest)" : ""}
|
|
43
|
+
</button>
|
|
44
|
+
)}
|
|
45
|
+
</nav>
|
|
46
|
+
</header>
|
|
47
|
+
<Outlet />
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed access to `guuey.app.json` — the ONE file `pnpm bootstrap` writes.
|
|
3
|
+
*
|
|
4
|
+
* The JSON is validated structurally here (not just cast) so a hand-edited
|
|
5
|
+
* config fails with a named path instead of an undefined-deep-in-React
|
|
6
|
+
* crash. The schema is documented in `../guuey.app.schema.json`.
|
|
7
|
+
*/
|
|
8
|
+
import rawConfig from "../../guuey.app.json";
|
|
9
|
+
|
|
10
|
+
export interface OidcConfig {
|
|
11
|
+
/** OIDC issuer URL (https). Discovery via /.well-known/openid-configuration. */
|
|
12
|
+
issuer: string;
|
|
13
|
+
clientId: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface AppLink {
|
|
17
|
+
appId: string;
|
|
18
|
+
env: "dev" | "staging" | "release";
|
|
19
|
+
/** Public API base ending in /v1 — history + persisted-card reads. */
|
|
20
|
+
apiBaseUrl: string;
|
|
21
|
+
/** The agent pod's public origin — live chat + health probe. */
|
|
22
|
+
endpointUrl: string;
|
|
23
|
+
/** Widget host origin serving /v1.js for this environment. */
|
|
24
|
+
widgetOrigin: string;
|
|
25
|
+
/** Portal web origin (the "talk on mobile" target). */
|
|
26
|
+
portalUrl: string;
|
|
27
|
+
slug: string | null;
|
|
28
|
+
/** The agent's own hosted page (https://<slug>.agents...), when slugged. */
|
|
29
|
+
pageUrl: string | null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface AppConfig {
|
|
33
|
+
schema: number;
|
|
34
|
+
bootstrapped: boolean;
|
|
35
|
+
brand: { name: string; tagline: string; logoText: string };
|
|
36
|
+
theme: { accent: string; mode: "light" | "dark" };
|
|
37
|
+
copy: {
|
|
38
|
+
landing: { headline: string; sub: string };
|
|
39
|
+
login: { guestHint: string };
|
|
40
|
+
};
|
|
41
|
+
auth: { oidc: OidcConfig | null };
|
|
42
|
+
link: AppLink | null;
|
|
43
|
+
demoMode: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
class ConfigError extends Error {
|
|
47
|
+
constructor(path: string, expected: string) {
|
|
48
|
+
super(`guuey.app.json: ${path} — expected ${expected}. Re-run \`pnpm bootstrap\` or fix the file by hand (schema: guuey.app.schema.json).`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function str(v: unknown, path: string): string {
|
|
53
|
+
if (typeof v !== "string" || v.length === 0) throw new ConfigError(path, "a non-empty string");
|
|
54
|
+
return v;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function bool(v: unknown, path: string): boolean {
|
|
58
|
+
if (typeof v !== "boolean") throw new ConfigError(path, "a boolean");
|
|
59
|
+
return v;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function obj(v: unknown, path: string): Record<string, unknown> {
|
|
63
|
+
if (typeof v !== "object" || v === null || Array.isArray(v)) throw new ConfigError(path, "an object");
|
|
64
|
+
return v as Record<string, unknown>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function validate(raw: unknown): AppConfig {
|
|
68
|
+
const root = obj(raw, "$");
|
|
69
|
+
if (root.schema !== 1) throw new ConfigError("schema", "the literal 1");
|
|
70
|
+
|
|
71
|
+
const brand = obj(root.brand, "brand");
|
|
72
|
+
const theme = obj(root.theme, "theme");
|
|
73
|
+
const mode = theme.mode;
|
|
74
|
+
if (mode !== "light" && mode !== "dark") throw new ConfigError("theme.mode", '"light" | "dark"');
|
|
75
|
+
const copy = obj(root.copy, "copy");
|
|
76
|
+
const landing = obj(copy.landing, "copy.landing");
|
|
77
|
+
const login = obj(copy.login, "copy.login");
|
|
78
|
+
const auth = obj(root.auth, "auth");
|
|
79
|
+
|
|
80
|
+
let oidc: OidcConfig | null = null;
|
|
81
|
+
if (auth.oidc !== null && auth.oidc !== undefined) {
|
|
82
|
+
const o = obj(auth.oidc, "auth.oidc");
|
|
83
|
+
oidc = { issuer: str(o.issuer, "auth.oidc.issuer"), clientId: str(o.clientId, "auth.oidc.clientId") };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
let link: AppLink | null = null;
|
|
87
|
+
if (root.link !== null && root.link !== undefined) {
|
|
88
|
+
const l = obj(root.link, "link");
|
|
89
|
+
const env = l.env;
|
|
90
|
+
if (env !== "dev" && env !== "staging" && env !== "release") {
|
|
91
|
+
throw new ConfigError("link.env", '"dev" | "staging" | "release"');
|
|
92
|
+
}
|
|
93
|
+
link = {
|
|
94
|
+
appId: str(l.appId, "link.appId"),
|
|
95
|
+
env,
|
|
96
|
+
apiBaseUrl: str(l.apiBaseUrl, "link.apiBaseUrl"),
|
|
97
|
+
// Normalize to the ORIGIN whatever shape was stored: the platform's
|
|
98
|
+
// deployment records carry the full `…/agent/invoke` URL, while this
|
|
99
|
+
// contract (and the probe) wants the base. The chat kit accepts
|
|
100
|
+
// either, so normalizing here makes both consumers correct.
|
|
101
|
+
endpointUrl: str(l.endpointUrl, "link.endpointUrl").replace(/\/agent\/invoke\/?$/, ""),
|
|
102
|
+
widgetOrigin: str(l.widgetOrigin, "link.widgetOrigin"),
|
|
103
|
+
portalUrl: str(l.portalUrl, "link.portalUrl"),
|
|
104
|
+
slug: typeof l.slug === "string" ? l.slug : null,
|
|
105
|
+
pageUrl: typeof l.pageUrl === "string" ? l.pageUrl : null,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
schema: 1,
|
|
111
|
+
bootstrapped: bool(root.bootstrapped, "bootstrapped"),
|
|
112
|
+
brand: {
|
|
113
|
+
name: str(brand.name, "brand.name"),
|
|
114
|
+
tagline: str(brand.tagline, "brand.tagline"),
|
|
115
|
+
logoText: str(brand.logoText, "brand.logoText"),
|
|
116
|
+
},
|
|
117
|
+
theme: { accent: str(theme.accent, "theme.accent"), mode },
|
|
118
|
+
copy: {
|
|
119
|
+
landing: { headline: str(landing.headline, "copy.landing.headline"), sub: str(landing.sub, "copy.landing.sub") },
|
|
120
|
+
login: { guestHint: str(login.guestHint, "copy.login.guestHint") },
|
|
121
|
+
},
|
|
122
|
+
auth: { oidc },
|
|
123
|
+
link,
|
|
124
|
+
demoMode: bool(root.demoMode ?? false, "demoMode"),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export const appConfig: AppConfig = validate(rawConfig);
|
|
129
|
+
|
|
130
|
+
/** The local `guuey dev --serve` router (scripts/dev.mjs boots it). */
|
|
131
|
+
export const DEV_AGENT_URL = "http://localhost:6790";
|
|
132
|
+
|
|
133
|
+
export const isLinked: boolean = appConfig.link !== null;
|
|
134
|
+
|
|
135
|
+
/** Live-chat base: the bound pod when linked, the local dev router otherwise. */
|
|
136
|
+
export function agentEndpointUrl(): string {
|
|
137
|
+
return appConfig.link?.endpointUrl ?? DEV_AGENT_URL;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* History/read-plane base. When linked this is the public API (`…/v1`);
|
|
142
|
+
* in local dev, `guuey dev --serve` exposes the same read-plane route
|
|
143
|
+
* shape (`/threads/:id/messages`) on its own origin, so history and
|
|
144
|
+
* rehydration work locally too.
|
|
145
|
+
*/
|
|
146
|
+
export function historyBaseUrl(): string {
|
|
147
|
+
return appConfig.link?.apiBaseUrl ?? DEV_AGENT_URL;
|
|
148
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-user identity for this app's chat surfaces.
|
|
3
|
+
*
|
|
4
|
+
* ONE mode per surface — never both resolvers at once (a bearer + a guest
|
|
5
|
+
* secret on the same request is a silent-downgrade hazard the platform
|
|
6
|
+
* refuses to guess about):
|
|
7
|
+
*
|
|
8
|
+
* - **Guest** (always available): a client-minted 64-hex secret stored at
|
|
9
|
+
* `localStorage["guuey:guest-secret:<appId>"]` and sent as the
|
|
10
|
+
* `x-guuey-guest` header. Per-browser and persistent, so the agent
|
|
11
|
+
* remembers the visitor across reloads. This is the same mechanic the
|
|
12
|
+
* guuey widget uses. "Log out" deletes the secret — a fresh one next
|
|
13
|
+
* visit is a fresh person as far as the agent is concerned.
|
|
14
|
+
* - **Signed in** (when `auth.oidc` is configured in guuey.app.json): an
|
|
15
|
+
* OIDC ID token from your IdP (see ./oidc.ts), sent as a Bearer. The
|
|
16
|
+
* bound guuey app must be in BYO auth mode for the same issuer
|
|
17
|
+
* (`guuey apps update <appId> --auth-mode byo --issuer-url … --audience <clientId>`).
|
|
18
|
+
*/
|
|
19
|
+
import { appConfig } from "../config";
|
|
20
|
+
|
|
21
|
+
export type IdentityMode = "guest" | "oidc";
|
|
22
|
+
|
|
23
|
+
const scope = appConfig.link?.appId ?? "local";
|
|
24
|
+
const GUEST_KEY = `guuey:guest-secret:${scope}`;
|
|
25
|
+
const MODE_KEY = `guuey:identity-mode:${scope}`;
|
|
26
|
+
|
|
27
|
+
function mintSecret(): string {
|
|
28
|
+
const bytes = new Uint8Array(32);
|
|
29
|
+
crypto.getRandomValues(bytes);
|
|
30
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** The stored guest secret, minting one on first use. */
|
|
34
|
+
export function ensureGuestSecret(): string {
|
|
35
|
+
const existing = localStorage.getItem(GUEST_KEY);
|
|
36
|
+
if (existing && /^[0-9a-f]{64}$/.test(existing)) return existing;
|
|
37
|
+
const fresh = mintSecret();
|
|
38
|
+
localStorage.setItem(GUEST_KEY, fresh);
|
|
39
|
+
return fresh;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function getStoredGuestSecret(): string | null {
|
|
43
|
+
const v = localStorage.getItem(GUEST_KEY);
|
|
44
|
+
return v && /^[0-9a-f]{64}$/.test(v) ? v : null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function currentIdentityMode(): IdentityMode | null {
|
|
48
|
+
const v = localStorage.getItem(MODE_KEY);
|
|
49
|
+
return v === "guest" || v === "oidc" ? v : null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function setIdentityMode(mode: IdentityMode | null): void {
|
|
53
|
+
if (mode === null) localStorage.removeItem(MODE_KEY);
|
|
54
|
+
else localStorage.setItem(MODE_KEY, mode);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** "Continue as guest": ensure a secret exists and select guest mode. */
|
|
58
|
+
export function continueAsGuest(): void {
|
|
59
|
+
ensureGuestSecret();
|
|
60
|
+
setIdentityMode("guest");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Log out of whichever mode is active. Guest logout forgets the secret. */
|
|
64
|
+
export function logOut(): void {
|
|
65
|
+
if (currentIdentityMode() === "guest") localStorage.removeItem(GUEST_KEY);
|
|
66
|
+
setIdentityMode(null);
|
|
67
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BYO-OIDC sign-in seam (only active when `auth.oidc` is configured in
|
|
3
|
+
* guuey.app.json).
|
|
4
|
+
*
|
|
5
|
+
* Standard authorization-code + PKCE via oidc-client-ts. The ID TOKEN is
|
|
6
|
+
* what the guuey pod verifies in BYO auth mode (audience = your client id),
|
|
7
|
+
* so `getAccessToken` below returns `user.id_token` — forwarding the OAuth
|
|
8
|
+
* access token instead is the classic mistake (wrong audience → 401).
|
|
9
|
+
*
|
|
10
|
+
* Works with any spec-compliant IdP that can host a "Sign in with Google"
|
|
11
|
+
* (Auth0, AWS Cognito, Okta, Keycloak, …). Configure the IdP's allowed
|
|
12
|
+
* callback URL to `<your site origin>/login`.
|
|
13
|
+
*/
|
|
14
|
+
import { UserManager, WebStorageStateStore, type User } from "oidc-client-ts";
|
|
15
|
+
import { appConfig, type OidcConfig } from "../config";
|
|
16
|
+
|
|
17
|
+
let manager: UserManager | null = null;
|
|
18
|
+
|
|
19
|
+
export function oidcConfigured(): boolean {
|
|
20
|
+
return appConfig.auth.oidc !== null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function requireManager(oidc: OidcConfig): UserManager {
|
|
24
|
+
if (manager) return manager;
|
|
25
|
+
manager = new UserManager({
|
|
26
|
+
authority: oidc.issuer,
|
|
27
|
+
client_id: oidc.clientId,
|
|
28
|
+
redirect_uri: `${window.location.origin}/login`,
|
|
29
|
+
response_type: "code",
|
|
30
|
+
scope: "openid profile email",
|
|
31
|
+
userStore: new WebStorageStateStore({ store: window.localStorage }),
|
|
32
|
+
});
|
|
33
|
+
return manager;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Kick off the redirect sign-in flow. */
|
|
37
|
+
export async function signIn(): Promise<void> {
|
|
38
|
+
const oidc = appConfig.auth.oidc;
|
|
39
|
+
if (!oidc) throw new Error("auth.oidc is not configured in guuey.app.json");
|
|
40
|
+
await requireManager(oidc).signinRedirect();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Complete the flow when the IdP redirected back to /login?code=… */
|
|
44
|
+
export async function completeSignIn(): Promise<User> {
|
|
45
|
+
const oidc = appConfig.auth.oidc;
|
|
46
|
+
if (!oidc) throw new Error("auth.oidc is not configured in guuey.app.json");
|
|
47
|
+
return requireManager(oidc).signinCallback() as Promise<User>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function isSigninCallback(): boolean {
|
|
51
|
+
const q = new URLSearchParams(window.location.search);
|
|
52
|
+
return q.has("code") && q.has("state");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function currentUser(): Promise<User | null> {
|
|
56
|
+
const oidc = appConfig.auth.oidc;
|
|
57
|
+
if (!oidc) return null;
|
|
58
|
+
const user = await requireManager(oidc).getUser();
|
|
59
|
+
return user && !user.expired ? user : null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* `getAccessToken` for `<GuueyChat>`: the current stored ID token, or null
|
|
64
|
+
* when signed out / expired (the chat surfaces it as needs-sign-in; they
|
|
65
|
+
* never silently fall back to guest — one identity mode per surface).
|
|
66
|
+
* There is NO silent renew here — when the session expires the user signs
|
|
67
|
+
* in again via /login. Wiring `automaticSilentRenew` (plus a silent
|
|
68
|
+
* redirect page) is the documented upgrade if your IdP supports it.
|
|
69
|
+
*/
|
|
70
|
+
export async function getBearerToken(): Promise<string | null> {
|
|
71
|
+
const user = await currentUser();
|
|
72
|
+
return user?.id_token ?? null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export async function signOutOidc(): Promise<void> {
|
|
76
|
+
const oidc = appConfig.auth.oidc;
|
|
77
|
+
if (!oidc || !manager) return;
|
|
78
|
+
await manager.removeUser();
|
|
79
|
+
}
|