@samy-clivolt/create-pi-ag-ui 0.1.2

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.
Files changed (39) hide show
  1. package/README.md +50 -0
  2. package/dist/index.js +236 -0
  3. package/package.json +40 -0
  4. package/template/README.md +408 -0
  5. package/template/_env.example +27 -0
  6. package/template/_eslintrc.json +3 -0
  7. package/template/_gitignore +37 -0
  8. package/template/justfile +19 -0
  9. package/template/next-env.d.ts +6 -0
  10. package/template/next.config.ts +13 -0
  11. package/template/package.json +42 -0
  12. package/template/postcss.config.js +6 -0
  13. package/template/src/app/api/copilotkit/route.ts +63 -0
  14. package/template/src/app/api/models/route.ts +77 -0
  15. package/template/src/app/api/thinking/route.ts +38 -0
  16. package/template/src/app/globals.css +130 -0
  17. package/template/src/app/layout.tsx +19 -0
  18. package/template/src/app/page.tsx +214 -0
  19. package/template/src/components/ActivityPanel.tsx +83 -0
  20. package/template/src/components/AgentExtrasPanel.tsx +21 -0
  21. package/template/src/components/AgentStatePanel.tsx +194 -0
  22. package/template/src/components/ChatToolbar.tsx +42 -0
  23. package/template/src/components/ChatUI.tsx +258 -0
  24. package/template/src/components/FrontendTools.tsx +509 -0
  25. package/template/src/components/InterruptHandler.tsx +183 -0
  26. package/template/src/components/ModelPicker.tsx +179 -0
  27. package/template/src/components/PiAgentProvider.tsx +28 -0
  28. package/template/src/components/ThinkingBlock.tsx +70 -0
  29. package/template/src/components/ThinkingPicker.tsx +112 -0
  30. package/template/src/components/ThreadSwitcher.tsx +51 -0
  31. package/template/src/components/ToolRenderers.tsx +409 -0
  32. package/template/src/components/chat/MessageSkeleton.tsx +17 -0
  33. package/template/src/components/chat/StreamingIndicator.tsx +37 -0
  34. package/template/src/components/layout/MobileSidebarDrawer.tsx +82 -0
  35. package/template/src/components/state/MetricsCard.tsx +36 -0
  36. package/template/src/components/state/StepTimeline.tsx +56 -0
  37. package/template/src/lib/agent-state-context.tsx +183 -0
  38. package/template/tailwind.config.ts +11 -0
  39. package/template/tsconfig.json +40 -0
package/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # @samy-clivolt/create-pi-ag-ui
2
+
3
+ Scaffold a new **Pi AG-UI** project — an AG-UI protocol bridge with a CopilotKit-powered frontend.
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ npx @samy-clivolt/create-pi-ag-ui my-app
9
+ ```
10
+
11
+ Then follow the prompts.
12
+
13
+ ### Options
14
+
15
+ ```bash
16
+ npx @samy-clivolt/create-pi-ag-ui my-app --pm pnpm # Use pnpm
17
+ npx @samy-clivolt/create-pi-ag-ui my-app --skip-install # Don't install deps
18
+ npx @samy-clivolt/create-pi-ag-ui --help # Show help
19
+ ```
20
+
21
+ ### What you get
22
+
23
+ A fully-featured AG-UI project with:
24
+
25
+ - 🔌 **24/24 AG-UI events** — full protocol coverage
26
+ - 💬 **CopilotKit chat** — streaming, reasoning, tool calls
27
+ - 🛠️ **Frontend tools** — 7 example tools with generative UI
28
+ - 🧠 **Thinking/Reasoning** — collapsible reasoning blocks
29
+ - 📊 **Agent state panel** — live status, metrics, activities
30
+ - 🔄 **Multi-thread** — isolated sessions per conversation
31
+ - 💾 **Persistence** — optional JSONL session storage
32
+ - 📱 **Responsive** — mobile-friendly layout
33
+
34
+ ### Quick start after scaffolding
35
+
36
+ ```bash
37
+ cd my-app
38
+
39
+ # Add your API key
40
+ echo "ANTHROPIC_API_KEY=sk-ant-..." >> .env.local
41
+
42
+ # Start
43
+ npm run dev
44
+ ```
45
+
46
+ Open http://localhost:3000.
47
+
48
+ ## License
49
+
50
+ MIT
package/dist/index.js ADDED
@@ -0,0 +1,236 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync } from "fs";
3
+ import { cp, mkdir, readdir, readFile, writeFile } from "fs/promises";
4
+ import { resolve, join, dirname } from "path";
5
+ import { fileURLToPath } from "url";
6
+ import { createInterface } from "readline";
7
+ import { execSync } from "child_process";
8
+ // ── ANSI helpers ──────────────────────────────────────────────
9
+ const bold = (s) => `\x1b[1m${s}\x1b[0m`;
10
+ const green = (s) => `\x1b[32m${s}\x1b[0m`;
11
+ const cyan = (s) => `\x1b[36m${s}\x1b[0m`;
12
+ const red = (s) => `\x1b[31m${s}\x1b[0m`;
13
+ const dim = (s) => `\x1b[2m${s}\x1b[0m`;
14
+ const yellow = (s) => `\x1b[33m${s}\x1b[0m`;
15
+ function parseArgs(argv) {
16
+ const args = argv.slice(2);
17
+ let projectName = "";
18
+ let pm = "";
19
+ let skipInstall = false;
20
+ let help = false;
21
+ for (let i = 0; i < args.length; i++) {
22
+ const arg = args[i];
23
+ if (arg === "--help" || arg === "-h") {
24
+ help = true;
25
+ }
26
+ else if (arg === "--skip-install") {
27
+ skipInstall = true;
28
+ }
29
+ else if (arg === "--pm" && i + 1 < args.length) {
30
+ pm = args[++i];
31
+ }
32
+ else if (!arg.startsWith("-")) {
33
+ projectName = arg;
34
+ }
35
+ }
36
+ return { projectName, pm, skipInstall, help };
37
+ }
38
+ // ── Interactive prompts (zero deps) ──────────────────────────
39
+ function ask(message, fallback) {
40
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
41
+ const hint = fallback ? dim(` (${fallback})`) : "";
42
+ return new Promise((resolve) => {
43
+ rl.question(` ${message}${hint}: `, (answer) => {
44
+ rl.close();
45
+ resolve(answer.trim() || fallback || "");
46
+ });
47
+ });
48
+ }
49
+ function choose(message, options, defaultIdx = 0) {
50
+ return new Promise(async (res) => {
51
+ console.log(`\n ${message}`);
52
+ for (let i = 0; i < options.length; i++) {
53
+ const marker = i === defaultIdx ? green("❯") : " ";
54
+ console.log(` ${marker} ${i + 1}. ${options[i]}`);
55
+ }
56
+ const answer = await ask(` Choose [1-${options.length}]`, String(defaultIdx + 1));
57
+ const idx = parseInt(answer) - 1;
58
+ res(options[idx] ?? options[defaultIdx]);
59
+ });
60
+ }
61
+ // ── Package manager detection ────────────────────────────────
62
+ const VALID_PMS = ["npm", "pnpm", "yarn", "bun"];
63
+ function detectPM() {
64
+ for (const pm of ["pnpm", "yarn", "bun"]) {
65
+ try {
66
+ execSync(`${pm} --version`, { stdio: "ignore" });
67
+ return pm;
68
+ }
69
+ catch {
70
+ /* not installed */
71
+ }
72
+ }
73
+ return "npm";
74
+ }
75
+ function installCmd(pm) {
76
+ return pm === "yarn" ? "yarn" : `${pm} install`;
77
+ }
78
+ function runCmd(pm, script) {
79
+ if (pm === "yarn")
80
+ return `yarn ${script}`;
81
+ if (pm === "bun")
82
+ return `bun run ${script}`;
83
+ return `${pm} run ${script}`;
84
+ }
85
+ // ── Template copy with _dotfile → .dotfile renaming ──────────
86
+ async function copyDir(src, dest) {
87
+ await mkdir(dest, { recursive: true });
88
+ const entries = await readdir(src, { withFileTypes: true });
89
+ for (const entry of entries) {
90
+ const srcPath = join(src, entry.name);
91
+ // _gitignore → .gitignore, _env.example → .env.example
92
+ // But keep __tests__, __mocks__, etc. (double underscore = convention)
93
+ const destName = entry.name.startsWith("_") && !entry.name.startsWith("__")
94
+ ? `.${entry.name.slice(1)}`
95
+ : entry.name;
96
+ const destPath = join(dest, destName);
97
+ if (entry.isDirectory()) {
98
+ await copyDir(srcPath, destPath);
99
+ }
100
+ else {
101
+ await cp(srcPath, destPath);
102
+ }
103
+ }
104
+ }
105
+ // ── Main ─────────────────────────────────────────────────────
106
+ async function main() {
107
+ const { projectName: argName, pm: argPM, skipInstall, help } = parseArgs(process.argv);
108
+ // ── Help ──
109
+ if (help) {
110
+ console.log(`
111
+ ${bold("@samy-clivolt/create-pi-ag-ui")} — Scaffold a new Pi AG-UI project
112
+
113
+ ${bold("Usage:")}
114
+ npx @samy-clivolt/create-pi-ag-ui ${dim("[project-name]")} ${dim("[options]")}
115
+
116
+ ${bold("Options:")}
117
+ --pm ${dim("<npm|pnpm|yarn|bun>")} Package manager (default: auto-detect)
118
+ --skip-install Skip dependency installation
119
+ -h, --help Show this help
120
+
121
+ ${bold("Examples:")}
122
+ npx @samy-clivolt/create-pi-ag-ui my-app
123
+ npx @samy-clivolt/create-pi-ag-ui my-app --pm pnpm
124
+ npx @samy-clivolt/create-pi-ag-ui my-app --skip-install
125
+ `);
126
+ process.exit(0);
127
+ }
128
+ // ── Banner ──
129
+ console.log(`
130
+ ${bold("🚀 @samy-clivolt/create-pi-ag-ui")}
131
+ ${dim("AG-UI protocol bridge with CopilotKit frontend")}
132
+ `);
133
+ // ── 1. Project name ──
134
+ let projectName = argName;
135
+ if (!projectName) {
136
+ if (!process.stdin.isTTY) {
137
+ console.error(red(" ✖ Project name is required in non-interactive mode."));
138
+ console.error(dim(" Usage: npx @samy-clivolt/create-pi-ag-ui <project-name>"));
139
+ process.exit(1);
140
+ }
141
+ projectName = await ask("Project name", "my-pi-ag-ui-app");
142
+ }
143
+ if (!projectName) {
144
+ console.error(red(" ✖ Project name is required."));
145
+ process.exit(1);
146
+ }
147
+ // Validate name
148
+ if (!/^[a-zA-Z0-9_@][a-zA-Z0-9._@/-]*$/.test(projectName)) {
149
+ console.error(red(` ✖ Invalid project name: "${projectName}"`));
150
+ process.exit(1);
151
+ }
152
+ const projectDir = resolve(process.cwd(), projectName);
153
+ if (existsSync(projectDir)) {
154
+ console.error(red(` ✖ Directory "${projectName}" already exists.`));
155
+ process.exit(1);
156
+ }
157
+ // ── 2. Package manager ──
158
+ let pm;
159
+ if (argPM && VALID_PMS.includes(argPM)) {
160
+ pm = argPM;
161
+ }
162
+ else if (process.stdin.isTTY) {
163
+ const detected = detectPM();
164
+ const choice = await choose("Package manager:", [...VALID_PMS], VALID_PMS.indexOf(detected));
165
+ pm = choice;
166
+ }
167
+ else {
168
+ pm = detectPM();
169
+ }
170
+ // ── 3. Scaffolding ──
171
+ console.log(`\n ${dim("Scaffolding")} ${bold(projectName)} ${dim("...")}`);
172
+ const __filename = fileURLToPath(import.meta.url);
173
+ const __dirname = dirname(__filename);
174
+ const templateDir = resolve(__dirname, "..", "template");
175
+ if (!existsSync(templateDir)) {
176
+ console.error(red(" ✖ Template directory not found. Package may be corrupted."));
177
+ process.exit(1);
178
+ }
179
+ await copyDir(templateDir, projectDir);
180
+ // ── 4. Patch package.json ──
181
+ const pkgPath = join(projectDir, "package.json");
182
+ const pkg = JSON.parse(await readFile(pkgPath, "utf-8"));
183
+ pkg.name = projectName;
184
+ await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
185
+ // ── 5. Create .env.local ──
186
+ const envExamplePath = join(projectDir, ".env.example");
187
+ const envLocalPath = join(projectDir, ".env.local");
188
+ if (existsSync(envExamplePath)) {
189
+ const envContent = await readFile(envExamplePath, "utf-8");
190
+ await writeFile(envLocalPath, envContent);
191
+ }
192
+ // ── 6. Init git repo ──
193
+ try {
194
+ execSync("git init", { cwd: projectDir, stdio: "ignore" });
195
+ execSync("git add -A", { cwd: projectDir, stdio: "ignore" });
196
+ execSync('git commit -m "Initial commit from @samy-clivolt/create-pi-ag-ui"', {
197
+ cwd: projectDir,
198
+ stdio: "ignore",
199
+ });
200
+ }
201
+ catch {
202
+ // git not available — skip silently
203
+ }
204
+ // ── 7. Install deps ──
205
+ if (!skipInstall) {
206
+ console.log(` ${dim(`Installing dependencies with ${pm}...`)}\n`);
207
+ try {
208
+ execSync(installCmd(pm), { cwd: projectDir, stdio: "inherit" });
209
+ }
210
+ catch {
211
+ console.warn(`\n ${yellow("⚠")} Failed to install dependencies. Run manually:`);
212
+ console.warn(` cd ${projectName} && ${installCmd(pm)}\n`);
213
+ }
214
+ }
215
+ // ── 8. Done ──
216
+ console.log(`
217
+ ${green("✅ Project created successfully!")}
218
+
219
+ ${bold("Next steps:")}
220
+
221
+ ${cyan(`cd ${projectName}`)}
222
+ ${skipInstall ? ` ${cyan(installCmd(pm))}\n` : ""} ${dim("# Add your API key to .env.local")}
223
+ ${yellow("ANTHROPIC_API_KEY=sk-ant-...")}
224
+
225
+ ${cyan(runCmd(pm, "dev"))}
226
+
227
+ ${dim("Then open")} ${cyan("http://localhost:3000")}
228
+
229
+ ${dim("─────────────────────────────────────────")}
230
+ ${dim("Docs: https://github.com/samy-clivolt/pi-ag-ui")}
231
+ `);
232
+ }
233
+ main().catch((err) => {
234
+ console.error(red(`\n ✖ ${err.message}`));
235
+ process.exit(1);
236
+ });
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@samy-clivolt/create-pi-ag-ui",
3
+ "version": "0.1.2",
4
+ "description": "Scaffold a Pi AG-UI project — AG-UI protocol bridge with CopilotKit frontend",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-pi-ag-ui": "dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "template"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "dev": "tsc --watch",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "keywords": [
19
+ "ag-ui",
20
+ "copilotkit",
21
+ "pi",
22
+ "agent",
23
+ "scaffold",
24
+ "create",
25
+ "template"
26
+ ],
27
+ "author": "",
28
+ "license": "MIT",
29
+ "publishConfig": {
30
+ "registry": "https://registry.npmjs.org",
31
+ "access": "public"
32
+ },
33
+ "engines": {
34
+ "node": ">=18.0.0"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^22.0.0",
38
+ "typescript": "^5.6.0"
39
+ }
40
+ }