create-claude-code-visualizer 0.1.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/index.js +393 -0
- package/package.json +31 -0
- package/templates/CLAUDE.md +108 -0
- package/templates/app/.env.local.example +14 -0
- package/templates/app/ecosystem.config.js +29 -0
- package/templates/app/next-env.d.ts +6 -0
- package/templates/app/next.config.ts +16 -0
- package/templates/app/package-lock.json +4581 -0
- package/templates/app/package.json +38 -0
- package/templates/app/postcss.config.js +5 -0
- package/templates/app/src/app/agents/[slug]/chat/loading.tsx +26 -0
- package/templates/app/src/app/agents/[slug]/chat/page.tsx +579 -0
- package/templates/app/src/app/agents/[slug]/loading.tsx +19 -0
- package/templates/app/src/app/agents/page.tsx +8 -0
- package/templates/app/src/app/api/agents/[slug]/capabilities/route.ts +11 -0
- package/templates/app/src/app/api/agents/[slug]/route.ts +57 -0
- package/templates/app/src/app/api/agents/route.ts +28 -0
- package/templates/app/src/app/api/ai/generate-agent/route.ts +87 -0
- package/templates/app/src/app/api/ai/improve-claude-md/route.ts +78 -0
- package/templates/app/src/app/api/ai/suggestions/route.ts +64 -0
- package/templates/app/src/app/api/ai/title/route.ts +88 -0
- package/templates/app/src/app/api/auth/role/route.ts +17 -0
- package/templates/app/src/app/api/commands/[slug]/route.ts +61 -0
- package/templates/app/src/app/api/commands/route.ts +6 -0
- package/templates/app/src/app/api/governance/costs/route.ts +117 -0
- package/templates/app/src/app/api/governance/sessions/route.ts +335 -0
- package/templates/app/src/app/api/notifications/route.ts +62 -0
- package/templates/app/src/app/api/preferences/route.ts +44 -0
- package/templates/app/src/app/api/runs/[id]/approve/route.ts +38 -0
- package/templates/app/src/app/api/runs/[id]/events/route.ts +28 -0
- package/templates/app/src/app/api/runs/[id]/metadata/route.ts +30 -0
- package/templates/app/src/app/api/runs/[id]/route.ts +21 -0
- package/templates/app/src/app/api/runs/[id]/start/route.ts +61 -0
- package/templates/app/src/app/api/runs/[id]/stop/route.ts +16 -0
- package/templates/app/src/app/api/runs/[id]/stream/route.ts +201 -0
- package/templates/app/src/app/api/runs/route.ts +95 -0
- package/templates/app/src/app/api/schedules/[id]/route.ts +81 -0
- package/templates/app/src/app/api/schedules/route.ts +75 -0
- package/templates/app/src/app/api/settings/access-logs/route.ts +33 -0
- package/templates/app/src/app/api/settings/claude-md/route.ts +44 -0
- package/templates/app/src/app/api/settings/env-keys/route.ts +271 -0
- package/templates/app/src/app/api/settings/users/route.ts +108 -0
- package/templates/app/src/app/api/skills/[slug]/route.ts +43 -0
- package/templates/app/src/app/api/skills/route.ts +6 -0
- package/templates/app/src/app/api/tools/route.ts +65 -0
- package/templates/app/src/app/api/uploads/cleanup/route.ts +29 -0
- package/templates/app/src/app/api/uploads/route.ts +77 -0
- package/templates/app/src/app/auth/callback/route.ts +19 -0
- package/templates/app/src/app/globals.css +115 -0
- package/templates/app/src/app/layout.tsx +24 -0
- package/templates/app/src/app/loading.tsx +16 -0
- package/templates/app/src/app/login/page.tsx +64 -0
- package/templates/app/src/app/not-authorized/page.tsx +33 -0
- package/templates/app/src/app/runs/page.tsx +55 -0
- package/templates/app/src/app/schedules/page.tsx +110 -0
- package/templates/app/src/app/settings/page.tsx +1294 -0
- package/templates/app/src/app/skills/page.tsx +7 -0
- package/templates/app/src/components/agent-card.tsx +58 -0
- package/templates/app/src/components/agent-grid.tsx +90 -0
- package/templates/app/src/components/auth/auth-context.tsx +79 -0
- package/templates/app/src/components/chat-thread.tsx +50 -0
- package/templates/app/src/components/chat-view.tsx +670 -0
- package/templates/app/src/components/commands-browser.tsx +349 -0
- package/templates/app/src/components/create-agent-modal.tsx +388 -0
- package/templates/app/src/components/governance-dashboard.tsx +397 -0
- package/templates/app/src/components/icons.tsx +401 -0
- package/templates/app/src/components/layout/agent-sidebar.tsx +504 -0
- package/templates/app/src/components/layout/app-shell.tsx +29 -0
- package/templates/app/src/components/layout/nav.tsx +87 -0
- package/templates/app/src/components/layout/overview-inner.tsx +14 -0
- package/templates/app/src/components/layout/profile-menu.tsx +95 -0
- package/templates/app/src/components/layout/sidebar.tsx +30 -0
- package/templates/app/src/components/markdown.tsx +57 -0
- package/templates/app/src/components/message-bar.tsx +161 -0
- package/templates/app/src/components/notifications/notification-bell.tsx +104 -0
- package/templates/app/src/components/notifications/notification-panel.tsx +116 -0
- package/templates/app/src/components/overview/overview-content.tsx +287 -0
- package/templates/app/src/components/overview/overview-context.tsx +88 -0
- package/templates/app/src/components/preferences-modal.tsx +112 -0
- package/templates/app/src/components/run-form.tsx +73 -0
- package/templates/app/src/components/run-history-table.tsx +226 -0
- package/templates/app/src/components/run-output.tsx +187 -0
- package/templates/app/src/components/schedule-form.tsx +148 -0
- package/templates/app/src/components/skills-browser.tsx +338 -0
- package/templates/app/src/components/tool-tooltip.tsx +82 -0
- package/templates/app/src/hooks/use-sse.ts +115 -0
- package/templates/app/src/instrumentation.ts +9 -0
- package/templates/app/src/lib/agent-cache.ts +19 -0
- package/templates/app/src/lib/agent-runner.ts +411 -0
- package/templates/app/src/lib/agents.ts +168 -0
- package/templates/app/src/lib/ai.ts +40 -0
- package/templates/app/src/lib/approval-store.ts +70 -0
- package/templates/app/src/lib/auth-guard.ts +116 -0
- package/templates/app/src/lib/capabilities.ts +191 -0
- package/templates/app/src/lib/line-diff.ts +96 -0
- package/templates/app/src/lib/queue.ts +22 -0
- package/templates/app/src/lib/redis.ts +12 -0
- package/templates/app/src/lib/role-permissions.ts +166 -0
- package/templates/app/src/lib/run-agent.ts +442 -0
- package/templates/app/src/lib/supabase-browser.ts +8 -0
- package/templates/app/src/lib/supabase-middleware.ts +63 -0
- package/templates/app/src/lib/supabase-server.ts +28 -0
- package/templates/app/src/lib/supabase.ts +6 -0
- package/templates/app/src/lib/tool-descriptions.ts +29 -0
- package/templates/app/src/lib/types.ts +73 -0
- package/templates/app/src/lib/typewriter-animation.ts +159 -0
- package/templates/app/src/middleware.ts +13 -0
- package/templates/app/tsconfig.json +21 -0
- package/templates/app/uploads/.gitkeep +0 -0
- package/templates/app/worker/index.ts +342 -0
- package/templates/claude/agents/ai-trends-scout.md +66 -0
- package/templates/claude/commands/add-to-todos.md +56 -0
- package/templates/claude/commands/check-todos.md +56 -0
- package/templates/claude/hooks/auto-approve-safe.sh +34 -0
- package/templates/claude/hooks/auto-format.sh +25 -0
- package/templates/claude/hooks/block-destructive.sh +32 -0
- package/templates/claude/hooks/compaction-preserver.sh +16 -0
- package/templates/claude/hooks/notify.sh +26 -0
- package/templates/claude/settings.local.json +66 -0
- package/templates/claude/skills/frontend-design/SKILL.md +127 -0
- package/templates/claude/skills/frontend-design/reference/color-and-contrast.md +132 -0
- package/templates/claude/skills/frontend-design/reference/interaction-design.md +123 -0
- package/templates/claude/skills/frontend-design/reference/motion-design.md +99 -0
- package/templates/claude/skills/frontend-design/reference/responsive-design.md +114 -0
- package/templates/claude/skills/frontend-design/reference/spatial-design.md +100 -0
- package/templates/claude/skills/frontend-design/reference/typography.md +131 -0
- package/templates/claude/skills/frontend-design/reference/ux-writing.md +107 -0
- package/templates/claude/skills/gws-admin-reports/SKILL.md +57 -0
- package/templates/claude/skills/gws-calendar/SKILL.md +108 -0
- package/templates/claude/skills/gws-calendar-agenda/SKILL.md +52 -0
- package/templates/claude/skills/gws-calendar-insert/SKILL.md +55 -0
- package/templates/claude/skills/gws-chat/SKILL.md +73 -0
- package/templates/claude/skills/gws-chat-send/SKILL.md +49 -0
- package/templates/claude/skills/gws-classroom/SKILL.md +75 -0
- package/templates/claude/skills/gws-docs/SKILL.md +48 -0
- package/templates/claude/skills/gws-docs-write/SKILL.md +49 -0
- package/templates/claude/skills/gws-drive/SKILL.md +137 -0
- package/templates/claude/skills/gws-drive-upload/SKILL.md +52 -0
- package/templates/claude/skills/gws-events/SKILL.md +67 -0
- package/templates/claude/skills/gws-events-renew/SKILL.md +48 -0
- package/templates/claude/skills/gws-events-subscribe/SKILL.md +59 -0
- package/templates/claude/skills/gws-forms/SKILL.md +45 -0
- package/templates/claude/skills/gws-gmail/SKILL.md +59 -0
- package/templates/claude/skills/gws-gmail-forward/SKILL.md +53 -0
- package/templates/claude/skills/gws-gmail-reply/SKILL.md +56 -0
- package/templates/claude/skills/gws-gmail-reply-all/SKILL.md +60 -0
- package/templates/claude/skills/gws-gmail-send/SKILL.md +55 -0
- package/templates/claude/skills/gws-gmail-triage/SKILL.md +50 -0
- package/templates/claude/skills/gws-gmail-watch/SKILL.md +58 -0
- package/templates/claude/skills/gws-keep/SKILL.md +48 -0
- package/templates/claude/skills/gws-meet/SKILL.md +51 -0
- package/templates/claude/skills/gws-modelarmor/SKILL.md +42 -0
- package/templates/claude/skills/gws-modelarmor-create-template/SKILL.md +53 -0
- package/templates/claude/skills/gws-modelarmor-sanitize-prompt/SKILL.md +48 -0
- package/templates/claude/skills/gws-modelarmor-sanitize-response/SKILL.md +48 -0
- package/templates/claude/skills/gws-people/SKILL.md +67 -0
- package/templates/claude/skills/gws-shared/SKILL.md +66 -0
- package/templates/claude/skills/gws-sheets/SKILL.md +53 -0
- package/templates/claude/skills/gws-sheets-append/SKILL.md +51 -0
- package/templates/claude/skills/gws-sheets-read/SKILL.md +47 -0
- package/templates/claude/skills/gws-slides/SKILL.md +43 -0
- package/templates/claude/skills/gws-tasks/SKILL.md +56 -0
- package/templates/claude/skills/gws-workflow/SKILL.md +44 -0
- package/templates/claude/skills/gws-workflow-email-to-task/SKILL.md +47 -0
- package/templates/claude/skills/gws-workflow-file-announce/SKILL.md +50 -0
- package/templates/claude/skills/gws-workflow-meeting-prep/SKILL.md +47 -0
- package/templates/claude/skills/gws-workflow-standup-report/SKILL.md +46 -0
- package/templates/claude/skills/gws-workflow-weekly-digest/SKILL.md +46 -0
- package/templates/claude/skills/persona-content-creator/SKILL.md +33 -0
- package/templates/claude/skills/persona-customer-support/SKILL.md +34 -0
- package/templates/claude/skills/persona-event-coordinator/SKILL.md +35 -0
- package/templates/claude/skills/persona-exec-assistant/SKILL.md +35 -0
- package/templates/claude/skills/persona-hr-coordinator/SKILL.md +33 -0
- package/templates/claude/skills/persona-it-admin/SKILL.md +30 -0
- package/templates/claude/skills/persona-project-manager/SKILL.md +35 -0
- package/templates/claude/skills/persona-researcher/SKILL.md +33 -0
- package/templates/claude/skills/persona-sales-ops/SKILL.md +35 -0
- package/templates/claude/skills/persona-team-lead/SKILL.md +36 -0
- package/templates/claude/skills/recipe-backup-sheet-as-csv/SKILL.md +25 -0
- package/templates/claude/skills/recipe-batch-invite-to-event/SKILL.md +25 -0
- package/templates/claude/skills/recipe-block-focus-time/SKILL.md +24 -0
- package/templates/claude/skills/recipe-bulk-download-folder/SKILL.md +25 -0
- package/templates/claude/skills/recipe-collect-form-responses/SKILL.md +25 -0
- package/templates/claude/skills/recipe-compare-sheet-tabs/SKILL.md +25 -0
- package/templates/claude/skills/recipe-copy-sheet-for-new-month/SKILL.md +25 -0
- package/templates/claude/skills/recipe-create-classroom-course/SKILL.md +25 -0
- package/templates/claude/skills/recipe-create-doc-from-template/SKILL.md +29 -0
- package/templates/claude/skills/recipe-create-events-from-sheet/SKILL.md +24 -0
- package/templates/claude/skills/recipe-create-expense-tracker/SKILL.md +26 -0
- package/templates/claude/skills/recipe-create-feedback-form/SKILL.md +25 -0
- package/templates/claude/skills/recipe-create-gmail-filter/SKILL.md +26 -0
- package/templates/claude/skills/recipe-create-meet-space/SKILL.md +25 -0
- package/templates/claude/skills/recipe-create-presentation/SKILL.md +25 -0
- package/templates/claude/skills/recipe-create-shared-drive/SKILL.md +25 -0
- package/templates/claude/skills/recipe-create-task-list/SKILL.md +26 -0
- package/templates/claude/skills/recipe-create-vacation-responder/SKILL.md +25 -0
- package/templates/claude/skills/recipe-draft-email-from-doc/SKILL.md +25 -0
- package/templates/claude/skills/recipe-email-drive-link/SKILL.md +25 -0
- package/templates/claude/skills/recipe-find-free-time/SKILL.md +25 -0
- package/templates/claude/skills/recipe-find-large-files/SKILL.md +24 -0
- package/templates/claude/skills/recipe-forward-labeled-emails/SKILL.md +27 -0
- package/templates/claude/skills/recipe-generate-report-from-sheet/SKILL.md +34 -0
- package/templates/claude/skills/recipe-label-and-archive-emails/SKILL.md +25 -0
- package/templates/claude/skills/recipe-log-deal-update/SKILL.md +25 -0
- package/templates/claude/skills/recipe-organize-drive-folder/SKILL.md +26 -0
- package/templates/claude/skills/recipe-plan-weekly-schedule/SKILL.md +26 -0
- package/templates/claude/skills/recipe-post-mortem-setup/SKILL.md +25 -0
- package/templates/claude/skills/recipe-reschedule-meeting/SKILL.md +25 -0
- package/templates/claude/skills/recipe-review-meet-participants/SKILL.md +25 -0
- package/templates/claude/skills/recipe-review-overdue-tasks/SKILL.md +25 -0
- package/templates/claude/skills/recipe-save-email-attachments/SKILL.md +26 -0
- package/templates/claude/skills/recipe-save-email-to-doc/SKILL.md +29 -0
- package/templates/claude/skills/recipe-schedule-recurring-event/SKILL.md +24 -0
- package/templates/claude/skills/recipe-send-team-announcement/SKILL.md +24 -0
- package/templates/claude/skills/recipe-share-doc-and-notify/SKILL.md +25 -0
- package/templates/claude/skills/recipe-share-event-materials/SKILL.md +25 -0
- package/templates/claude/skills/recipe-share-folder-with-team/SKILL.md +26 -0
- package/templates/claude/skills/recipe-sync-contacts-to-sheet/SKILL.md +25 -0
- package/templates/claude/skills/recipe-watch-drive-changes/SKILL.md +25 -0
- package/templates/mcp.json +12 -0
package/index.js
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const { execSync, spawnSync } = require("child_process");
|
|
6
|
+
const prompts = require("prompts");
|
|
7
|
+
|
|
8
|
+
const BLUE = "\x1b[34m";
|
|
9
|
+
const GREEN = "\x1b[32m";
|
|
10
|
+
const YELLOW = "\x1b[33m";
|
|
11
|
+
const RED = "\x1b[31m";
|
|
12
|
+
const NC = "\x1b[0m";
|
|
13
|
+
|
|
14
|
+
const log = (msg) => console.log(`${GREEN}[✓]${NC} ${msg}`);
|
|
15
|
+
const info = (msg) => console.log(`${BLUE}[→]${NC} ${msg}`);
|
|
16
|
+
const warn = (msg) => console.log(`${YELLOW}[!]${NC} ${msg}`);
|
|
17
|
+
const err = (msg) => console.log(`${RED}[✗]${NC} ${msg}`);
|
|
18
|
+
|
|
19
|
+
const TEMPLATES_DIR = path.join(__dirname, "templates");
|
|
20
|
+
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Helpers
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
function copyDir(src, dest) {
|
|
26
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
27
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
28
|
+
const srcPath = path.join(src, entry.name);
|
|
29
|
+
const destPath = path.join(dest, entry.name);
|
|
30
|
+
if (entry.isDirectory()) {
|
|
31
|
+
copyDir(srcPath, destPath);
|
|
32
|
+
} else {
|
|
33
|
+
fs.copyFileSync(srcPath, destPath);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function copyIfNotExists(src, dest) {
|
|
39
|
+
if (!fs.existsSync(dest)) {
|
|
40
|
+
fs.copyFileSync(src, dest);
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function copyDirAdditive(src, dest) {
|
|
47
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
48
|
+
let added = 0;
|
|
49
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
50
|
+
const srcPath = path.join(src, entry.name);
|
|
51
|
+
const destPath = path.join(dest, entry.name);
|
|
52
|
+
if (entry.isDirectory()) {
|
|
53
|
+
if (!fs.existsSync(destPath)) {
|
|
54
|
+
copyDir(srcPath, destPath);
|
|
55
|
+
added++;
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
if (copyIfNotExists(srcPath, destPath)) added++;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return added;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function mergeJsonFile(srcPath, destPath, mergeFn) {
|
|
65
|
+
if (!fs.existsSync(destPath)) {
|
|
66
|
+
fs.copyFileSync(srcPath, destPath);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const existing = JSON.parse(fs.readFileSync(destPath, "utf8"));
|
|
70
|
+
const ours = JSON.parse(fs.readFileSync(srcPath, "utf8"));
|
|
71
|
+
const merged = mergeFn(existing, ours);
|
|
72
|
+
fs.writeFileSync(destPath, JSON.stringify(merged, null, 2) + "\n");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function run(cmd, opts = {}) {
|
|
76
|
+
try {
|
|
77
|
+
return execSync(cmd, { stdio: "inherit", ...opts });
|
|
78
|
+
} catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function runCapture(cmd) {
|
|
84
|
+
try {
|
|
85
|
+
return execSync(cmd, { encoding: "utf8" }).trim();
|
|
86
|
+
} catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
// Main
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
|
|
95
|
+
async function main() {
|
|
96
|
+
console.log("");
|
|
97
|
+
console.log(`${BLUE}╔══════════════════════════════════════════════════╗${NC}`);
|
|
98
|
+
console.log(`${BLUE}║ Claude Code Visualizer — Setup ║${NC}`);
|
|
99
|
+
console.log(`${BLUE}╚══════════════════════════════════════════════════╝${NC}`);
|
|
100
|
+
console.log("");
|
|
101
|
+
|
|
102
|
+
// Determine project directory from CLI arg or prompt
|
|
103
|
+
let projectDir = process.argv[2];
|
|
104
|
+
|
|
105
|
+
if (!projectDir) {
|
|
106
|
+
const res = await prompts({
|
|
107
|
+
type: "text",
|
|
108
|
+
name: "dir",
|
|
109
|
+
message: "Project directory",
|
|
110
|
+
initial: "my-claude-visualizer",
|
|
111
|
+
});
|
|
112
|
+
if (!res.dir) process.exit(0);
|
|
113
|
+
projectDir = res.dir;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const projectRoot = path.resolve(projectDir);
|
|
117
|
+
const isExisting = fs.existsSync(projectRoot) && fs.existsSync(path.join(projectRoot, ".claude"));
|
|
118
|
+
const appDir = path.join(projectRoot, "personal-assistant-app");
|
|
119
|
+
|
|
120
|
+
if (isExisting) {
|
|
121
|
+
info(`Detected existing .claude/ project at ${projectRoot}`);
|
|
122
|
+
info("Will merge additively — your existing files always win.");
|
|
123
|
+
} else {
|
|
124
|
+
info(`Creating new project at ${projectRoot}`);
|
|
125
|
+
}
|
|
126
|
+
console.log("");
|
|
127
|
+
|
|
128
|
+
// -----------------------------------------------------------------
|
|
129
|
+
// Credentials
|
|
130
|
+
// -----------------------------------------------------------------
|
|
131
|
+
|
|
132
|
+
const creds = await prompts([
|
|
133
|
+
{
|
|
134
|
+
type: "password",
|
|
135
|
+
name: "anthropicKey",
|
|
136
|
+
message: "Anthropic API key (sk-ant-...)",
|
|
137
|
+
validate: (v) => v.startsWith("sk-ant-") || "Key should start with sk-ant-",
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
type: "text",
|
|
141
|
+
name: "supabaseUrl",
|
|
142
|
+
message: "Supabase project URL (https://xyz.supabase.co)",
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
type: "password",
|
|
146
|
+
name: "supabaseAnonKey",
|
|
147
|
+
message: "Supabase anon key",
|
|
148
|
+
},
|
|
149
|
+
]);
|
|
150
|
+
|
|
151
|
+
if (!creds.anthropicKey) process.exit(0);
|
|
152
|
+
|
|
153
|
+
// -----------------------------------------------------------------
|
|
154
|
+
// Copy the app
|
|
155
|
+
// -----------------------------------------------------------------
|
|
156
|
+
|
|
157
|
+
info("Setting up project files...");
|
|
158
|
+
|
|
159
|
+
fs.mkdirSync(projectRoot, { recursive: true });
|
|
160
|
+
|
|
161
|
+
// Copy personal-assistant-app (the Next.js UI)
|
|
162
|
+
const appTemplate = path.join(TEMPLATES_DIR, "app");
|
|
163
|
+
if (fs.existsSync(appDir)) {
|
|
164
|
+
warn("personal-assistant-app/ already exists — updating...");
|
|
165
|
+
}
|
|
166
|
+
copyDir(appTemplate, appDir);
|
|
167
|
+
log("personal-assistant-app/ installed");
|
|
168
|
+
|
|
169
|
+
// -----------------------------------------------------------------
|
|
170
|
+
// Set up .claude/ (agents, commands, skills, hooks, settings)
|
|
171
|
+
// -----------------------------------------------------------------
|
|
172
|
+
|
|
173
|
+
const srcClaude = path.join(TEMPLATES_DIR, "claude");
|
|
174
|
+
const dstClaude = path.join(projectRoot, ".claude");
|
|
175
|
+
|
|
176
|
+
// Agents
|
|
177
|
+
const addedAgents = copyDirAdditive(
|
|
178
|
+
path.join(srcClaude, "agents"),
|
|
179
|
+
path.join(dstClaude, "agents")
|
|
180
|
+
);
|
|
181
|
+
log(`Agents: added ${addedAgents} new`);
|
|
182
|
+
|
|
183
|
+
// Commands
|
|
184
|
+
const addedCommands = copyDirAdditive(
|
|
185
|
+
path.join(srcClaude, "commands"),
|
|
186
|
+
path.join(dstClaude, "commands")
|
|
187
|
+
);
|
|
188
|
+
log(`Commands: added ${addedCommands} new`);
|
|
189
|
+
|
|
190
|
+
// Skills
|
|
191
|
+
const addedSkills = copyDirAdditive(
|
|
192
|
+
path.join(srcClaude, "skills"),
|
|
193
|
+
path.join(dstClaude, "skills")
|
|
194
|
+
);
|
|
195
|
+
log(`Skills: added ${addedSkills} new`);
|
|
196
|
+
|
|
197
|
+
// Hooks
|
|
198
|
+
fs.mkdirSync(path.join(dstClaude, "hooks"), { recursive: true });
|
|
199
|
+
let addedHooks = 0;
|
|
200
|
+
for (const hook of fs.readdirSync(path.join(srcClaude, "hooks"))) {
|
|
201
|
+
const src = path.join(srcClaude, "hooks", hook);
|
|
202
|
+
const dest = path.join(dstClaude, "hooks", hook);
|
|
203
|
+
if (copyIfNotExists(src, dest)) {
|
|
204
|
+
try { fs.chmodSync(dest, 0o755); } catch {}
|
|
205
|
+
addedHooks++;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
log(`Hooks: added ${addedHooks} new`);
|
|
209
|
+
|
|
210
|
+
// settings.local.json — merge hooks config
|
|
211
|
+
mergeJsonFile(
|
|
212
|
+
path.join(srcClaude, "settings.local.json"),
|
|
213
|
+
path.join(dstClaude, "settings.local.json"),
|
|
214
|
+
(existing, ours) => {
|
|
215
|
+
// Merge hooks: add our hook events if they don't already exist
|
|
216
|
+
const mergedHooks = { ...(ours.hooks || {}) };
|
|
217
|
+
for (const [event, hooks] of Object.entries(existing.hooks || {})) {
|
|
218
|
+
mergedHooks[event] = hooks; // existing wins
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
...existing,
|
|
222
|
+
enableAllProjectMcpServers:
|
|
223
|
+
existing.enableAllProjectMcpServers ?? ours.enableAllProjectMcpServers,
|
|
224
|
+
hooks: mergedHooks,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
);
|
|
228
|
+
log("settings.local.json configured");
|
|
229
|
+
|
|
230
|
+
// .mcp.json — merge servers
|
|
231
|
+
mergeJsonFile(
|
|
232
|
+
path.join(TEMPLATES_DIR, "mcp.json"),
|
|
233
|
+
path.join(projectRoot, ".mcp.json"),
|
|
234
|
+
(existing, ours) => ({
|
|
235
|
+
mcpServers: { ...(ours.mcpServers || {}), ...(existing.mcpServers || {}) },
|
|
236
|
+
})
|
|
237
|
+
);
|
|
238
|
+
log(".mcp.json configured");
|
|
239
|
+
|
|
240
|
+
// CLAUDE.md
|
|
241
|
+
const claudeMdDest = path.join(projectRoot, "CLAUDE.md");
|
|
242
|
+
if (copyIfNotExists(path.join(TEMPLATES_DIR, "CLAUDE.md"), claudeMdDest)) {
|
|
243
|
+
log("CLAUDE.md created");
|
|
244
|
+
} else {
|
|
245
|
+
log("CLAUDE.md exists — keeping yours");
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// -----------------------------------------------------------------
|
|
249
|
+
// Write .env.local
|
|
250
|
+
// -----------------------------------------------------------------
|
|
251
|
+
|
|
252
|
+
const envContent = `# Generated by create-personalai — ${new Date().toISOString()}
|
|
253
|
+
ANTHROPIC_API_KEY=${creds.anthropicKey}
|
|
254
|
+
NEXT_PUBLIC_SUPABASE_URL=${creds.supabaseUrl}
|
|
255
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=${creds.supabaseAnonKey}
|
|
256
|
+
SUPABASE_URL=${creds.supabaseUrl}
|
|
257
|
+
SUPABASE_ANON_KEY=${creds.supabaseAnonKey}
|
|
258
|
+
REDIS_URL=redis://localhost:6379
|
|
259
|
+
PROJECT_ROOT=${projectRoot}
|
|
260
|
+
`;
|
|
261
|
+
|
|
262
|
+
fs.writeFileSync(path.join(appDir, ".env.local"), envContent, { mode: 0o600 });
|
|
263
|
+
log(".env.local created");
|
|
264
|
+
|
|
265
|
+
// Add Supabase MCP server if we have a URL
|
|
266
|
+
const supabaseMatch = (creds.supabaseUrl || "").match(
|
|
267
|
+
/https:\/\/([^.]+)\.supabase\.co/
|
|
268
|
+
);
|
|
269
|
+
if (supabaseMatch) {
|
|
270
|
+
const ref = supabaseMatch[1];
|
|
271
|
+
const mcpPath = path.join(projectRoot, ".mcp.json");
|
|
272
|
+
const mcp = JSON.parse(fs.readFileSync(mcpPath, "utf8"));
|
|
273
|
+
mcp.mcpServers.supabase = {
|
|
274
|
+
type: "http",
|
|
275
|
+
url: `https://mcp.supabase.com/mcp?project_ref=${ref}`,
|
|
276
|
+
};
|
|
277
|
+
fs.writeFileSync(mcpPath, JSON.stringify(mcp, null, 2) + "\n");
|
|
278
|
+
log("Supabase MCP server added");
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// -----------------------------------------------------------------
|
|
282
|
+
// npm install
|
|
283
|
+
// -----------------------------------------------------------------
|
|
284
|
+
|
|
285
|
+
info("Installing dependencies...");
|
|
286
|
+
run("npm install", { cwd: appDir });
|
|
287
|
+
log("Dependencies installed");
|
|
288
|
+
|
|
289
|
+
// -----------------------------------------------------------------
|
|
290
|
+
// Google Workspace (optional)
|
|
291
|
+
// -----------------------------------------------------------------
|
|
292
|
+
|
|
293
|
+
console.log("");
|
|
294
|
+
const { setupGws } = await prompts({
|
|
295
|
+
type: "confirm",
|
|
296
|
+
name: "setupGws",
|
|
297
|
+
message: "Set up Google Workspace integration? (Gmail, Calendar, Drive, etc.)",
|
|
298
|
+
initial: false,
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
if (setupGws) {
|
|
302
|
+
console.log("");
|
|
303
|
+
info("Installing Google Workspace CLI...");
|
|
304
|
+
run("npm install @anthropic-ai/claude-code-google-workspace", { cwd: projectRoot });
|
|
305
|
+
|
|
306
|
+
// Check if gws auth is needed
|
|
307
|
+
const hasAuth = runCapture("npx gws auth status");
|
|
308
|
+
if (!hasAuth) {
|
|
309
|
+
console.log("");
|
|
310
|
+
const { gwsAuth } = await prompts({
|
|
311
|
+
type: "select",
|
|
312
|
+
name: "gwsAuth",
|
|
313
|
+
message: "Google Workspace authentication",
|
|
314
|
+
choices: [
|
|
315
|
+
{ title: "Full setup (creates GCP project + OAuth)", value: "setup" },
|
|
316
|
+
{ title: "Login only (you already have OAuth configured)", value: "login" },
|
|
317
|
+
{ title: "Skip for now", value: "skip" },
|
|
318
|
+
],
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
if (gwsAuth === "setup") {
|
|
322
|
+
run("npx gws auth setup --login", { cwd: projectRoot });
|
|
323
|
+
} else if (gwsAuth === "login") {
|
|
324
|
+
run("npx gws auth login", { cwd: projectRoot });
|
|
325
|
+
} else {
|
|
326
|
+
info("Skipping auth. Run later: npx gws auth setup --login");
|
|
327
|
+
}
|
|
328
|
+
} else {
|
|
329
|
+
log("Already authenticated with Google Workspace");
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Install GWS skills
|
|
333
|
+
console.log("");
|
|
334
|
+
const { installSkills } = await prompts({
|
|
335
|
+
type: "confirm",
|
|
336
|
+
name: "installSkills",
|
|
337
|
+
message: "Install Google Workspace skills? (lets agents use Gmail, Calendar, etc.)",
|
|
338
|
+
initial: true,
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
if (installSkills) {
|
|
342
|
+
run("npx skills add https://github.com/googleworkspace/cli", { cwd: projectRoot });
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Add gws permission to settings
|
|
346
|
+
const settingsPath = path.join(dstClaude, "settings.local.json");
|
|
347
|
+
const settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
|
|
348
|
+
if (!JSON.stringify(settings).includes("npx gws")) {
|
|
349
|
+
settings.permissions = settings.permissions || {};
|
|
350
|
+
settings.permissions.allow = settings.permissions.allow || [];
|
|
351
|
+
settings.permissions.allow.push("Bash(npx gws:*)");
|
|
352
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
353
|
+
log("Added gws permission to settings");
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
log("Google Workspace setup complete");
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// -----------------------------------------------------------------
|
|
360
|
+
// Done
|
|
361
|
+
// -----------------------------------------------------------------
|
|
362
|
+
|
|
363
|
+
console.log("");
|
|
364
|
+
console.log(`${GREEN}╔══════════════════════════════════════════════════╗${NC}`);
|
|
365
|
+
console.log(`${GREEN}║ Setup Complete! ║${NC}`);
|
|
366
|
+
console.log(`${GREEN}╚══════════════════════════════════════════════════╝${NC}`);
|
|
367
|
+
console.log("");
|
|
368
|
+
|
|
369
|
+
log(`Project created at: ${projectRoot}`);
|
|
370
|
+
console.log("");
|
|
371
|
+
info("To get started:");
|
|
372
|
+
console.log("");
|
|
373
|
+
console.log(` cd ${projectDir}/personal-assistant-app`);
|
|
374
|
+
console.log(" redis-server & # Start Redis (needed for job queue)");
|
|
375
|
+
console.log(" npm run dev:all # Start the app + worker");
|
|
376
|
+
console.log("");
|
|
377
|
+
info("Then open http://localhost:3000");
|
|
378
|
+
console.log("");
|
|
379
|
+
|
|
380
|
+
if (!setupGws) {
|
|
381
|
+
info("To add Google Workspace later:");
|
|
382
|
+
console.log(` cd ${projectDir}`);
|
|
383
|
+
console.log(" npm install @anthropic-ai/claude-code-google-workspace");
|
|
384
|
+
console.log(" npx gws auth setup --login");
|
|
385
|
+
console.log(" npx skills add https://github.com/googleworkspace/cli");
|
|
386
|
+
console.log("");
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
main().catch((e) => {
|
|
391
|
+
err(e.message);
|
|
392
|
+
process.exit(1);
|
|
393
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-claude-code-visualizer",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Run and manage Claude Code agents through a web UI",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-claude-code-visualizer": "./index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"index.js",
|
|
11
|
+
"templates/**"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"prepare-templates": "node prepare-templates.js",
|
|
15
|
+
"prepublishOnly": "node prepare-templates.js"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"prompts": "^2.4.2"
|
|
19
|
+
},
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=18"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"claude",
|
|
25
|
+
"ai",
|
|
26
|
+
"assistant",
|
|
27
|
+
"agents",
|
|
28
|
+
"claude-code",
|
|
29
|
+
"create"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# PersonalAIssistant
|
|
2
|
+
|
|
3
|
+
## Identity
|
|
4
|
+
|
|
5
|
+
You are the user's personal AI assistant. You have full access to every tool, MCP server, skill, and subagent in this workspace. Handle tasks directly when you can, delegate to specialized subagents when their expertise produces better results.
|
|
6
|
+
|
|
7
|
+
## Architecture
|
|
8
|
+
|
|
9
|
+
This project is a personal assistant platform built on Claude Code. It consists of:
|
|
10
|
+
|
|
11
|
+
- **personal-assistant-app/** — A Next.js 15 frontend for managing and running AI agents
|
|
12
|
+
- **.claude/** — Claude Code configuration (agents, skills, commands, hooks)
|
|
13
|
+
- **assets/** — Static assets (fonts, images, documents)
|
|
14
|
+
|
|
15
|
+
## MCP Servers (auto-loaded from .mcp.json)
|
|
16
|
+
|
|
17
|
+
- **Chrome DevTools** (`mcp__chrome-devtools__*`) — Browser debugging, screenshots, DOM inspection
|
|
18
|
+
|
|
19
|
+
Add more MCP servers by editing `.mcp.json` at the project root.
|
|
20
|
+
|
|
21
|
+
## Creating Agents
|
|
22
|
+
|
|
23
|
+
Agents live in `.claude/agents/*.md`. Each agent has YAML frontmatter + markdown instructions:
|
|
24
|
+
|
|
25
|
+
```yaml
|
|
26
|
+
---
|
|
27
|
+
name: Agent Name
|
|
28
|
+
description: What this agent does
|
|
29
|
+
tools: 'WebSearch, WebFetch, Read'
|
|
30
|
+
color: '#8B5CF6'
|
|
31
|
+
emoji: "\U0001F52E"
|
|
32
|
+
vibe: Short tagline
|
|
33
|
+
---
|
|
34
|
+
# Agent instructions here...
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The frontend auto-discovers agents from this directory.
|
|
38
|
+
|
|
39
|
+
## Creating Skills
|
|
40
|
+
|
|
41
|
+
Skills live in `.claude/skills/*/SKILL.md`. Each skill directory contains a `SKILL.md` with frontmatter:
|
|
42
|
+
|
|
43
|
+
```yaml
|
|
44
|
+
---
|
|
45
|
+
name: skill-name
|
|
46
|
+
description: What this skill does
|
|
47
|
+
---
|
|
48
|
+
Skill instructions here...
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Creating Commands
|
|
52
|
+
|
|
53
|
+
Commands live in `.claude/commands/*.md`. They become available as `/command-name` in Claude Code:
|
|
54
|
+
|
|
55
|
+
```yaml
|
|
56
|
+
---
|
|
57
|
+
description: What this command does
|
|
58
|
+
allowed-tools:
|
|
59
|
+
- Read
|
|
60
|
+
- Edit
|
|
61
|
+
---
|
|
62
|
+
Command instructions here...
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Hooks (automatic, no action needed)
|
|
66
|
+
|
|
67
|
+
Hooks fire automatically — do not invoke them manually:
|
|
68
|
+
- `block-destructive.sh` — Blocks dangerous bash commands (rm -rf, git reset --hard, etc.)
|
|
69
|
+
- `auto-approve-safe.sh` — Auto-approves safe read-only commands (ls, git status, etc.)
|
|
70
|
+
- `auto-format.sh` — Auto-formats code after edits (prettier for JS/TS, ruff for Python)
|
|
71
|
+
- `compaction-preserver.sh` — Preserves critical context during session compaction
|
|
72
|
+
- `notify.sh` — Desktop notifications when Claude needs attention
|
|
73
|
+
|
|
74
|
+
## Frontend Development
|
|
75
|
+
|
|
76
|
+
### Screenshot Feedback Loop
|
|
77
|
+
|
|
78
|
+
After generating frontend code, close the loop:
|
|
79
|
+
1. Take a screenshot with Chrome DevTools MCP (`take_screenshot`)
|
|
80
|
+
2. Check console for errors (`list_console_messages`)
|
|
81
|
+
3. If the design looks generic or has issues, fix and re-screenshot
|
|
82
|
+
4. Only report done after visual verification
|
|
83
|
+
|
|
84
|
+
## Running the App
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Prerequisites: Node.js 18+, Redis server
|
|
88
|
+
|
|
89
|
+
# 1. Install dependencies
|
|
90
|
+
cd personal-assistant-app && npm install
|
|
91
|
+
|
|
92
|
+
# 2. Copy and fill in environment variables
|
|
93
|
+
cp .env.local.example .env.local
|
|
94
|
+
# Edit .env.local with your Supabase + Anthropic keys
|
|
95
|
+
|
|
96
|
+
# 3. Start Redis (required for BullMQ job queue)
|
|
97
|
+
redis-server
|
|
98
|
+
|
|
99
|
+
# 4. Start the app + worker
|
|
100
|
+
npm run dev:all
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The app runs at http://localhost:3000.
|
|
104
|
+
|
|
105
|
+
## Session Continuity
|
|
106
|
+
|
|
107
|
+
- `/add-to-todos` — Capture tasks mid-work without breaking flow
|
|
108
|
+
- `/check-todos` — Review and pick up saved todos
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Supabase — create a project at https://supabase.com
|
|
2
|
+
NEXT_PUBLIC_SUPABASE_URL=https://YOUR_PROJECT.supabase.co
|
|
3
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
|
|
4
|
+
SUPABASE_URL=https://YOUR_PROJECT.supabase.co
|
|
5
|
+
SUPABASE_ANON_KEY=your-anon-key
|
|
6
|
+
|
|
7
|
+
# Anthropic — get your key at https://console.anthropic.com
|
|
8
|
+
ANTHROPIC_API_KEY=sk-ant-api03-...
|
|
9
|
+
|
|
10
|
+
# Redis — used by BullMQ for agent job queues
|
|
11
|
+
REDIS_URL=redis://localhost:6379
|
|
12
|
+
|
|
13
|
+
# Project root — absolute path to this repo on your machine
|
|
14
|
+
PROJECT_ROOT=/path/to/PersonalAIssistantBase
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
apps: [
|
|
3
|
+
{
|
|
4
|
+
name: "personalai-web",
|
|
5
|
+
script: "npm",
|
|
6
|
+
args: "start",
|
|
7
|
+
cwd: __dirname,
|
|
8
|
+
env: {
|
|
9
|
+
NODE_ENV: "production",
|
|
10
|
+
PORT: 3000,
|
|
11
|
+
},
|
|
12
|
+
max_memory_restart: "512M",
|
|
13
|
+
restart_delay: 5000,
|
|
14
|
+
max_restarts: 10,
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: "personalai-worker",
|
|
18
|
+
script: "npm",
|
|
19
|
+
args: "run start:worker",
|
|
20
|
+
cwd: __dirname,
|
|
21
|
+
env: {
|
|
22
|
+
NODE_ENV: "production",
|
|
23
|
+
},
|
|
24
|
+
max_memory_restart: "1G",
|
|
25
|
+
restart_delay: 5000,
|
|
26
|
+
max_restarts: 10,
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/// <reference types="next" />
|
|
2
|
+
/// <reference types="next/image-types/global" />
|
|
3
|
+
/// <reference path="./.next/types/routes.d.ts" />
|
|
4
|
+
|
|
5
|
+
// NOTE: This file should not be edited
|
|
6
|
+
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { NextConfig } from "next";
|
|
2
|
+
|
|
3
|
+
const nextConfig: NextConfig = {
|
|
4
|
+
devIndicators: false,
|
|
5
|
+
serverExternalPackages: ["@anthropic-ai/claude-agent-sdk", "ioredis", "bullmq"],
|
|
6
|
+
async rewrites() {
|
|
7
|
+
return [
|
|
8
|
+
{
|
|
9
|
+
source: "/",
|
|
10
|
+
destination: "/agents/main/chat",
|
|
11
|
+
},
|
|
12
|
+
];
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default nextConfig;
|