myaiforone 1.0.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 +113 -0
- package/agents/_template/CLAUDE.md +18 -0
- package/agents/_template/agent.json +7 -0
- package/agents/platform/agentcreator/CLAUDE.md +300 -0
- package/agents/platform/appcreator/CLAUDE.md +158 -0
- package/agents/platform/gym/CLAUDE.md +486 -0
- package/agents/platform/gym/agent.json +40 -0
- package/agents/platform/gym/programs/agent-building/program.json +160 -0
- package/agents/platform/gym/programs/automations-mastery/program.json +129 -0
- package/agents/platform/gym/programs/getting-started/program.json +124 -0
- package/agents/platform/gym/programs/mcp-integrations/program.json +116 -0
- package/agents/platform/gym/programs/multi-model-strategy/program.json +115 -0
- package/agents/platform/gym/programs/prompt-engineering/program.json +136 -0
- package/agents/platform/gym/souls/alex.md +12 -0
- package/agents/platform/gym/souls/jordan.md +12 -0
- package/agents/platform/gym/souls/morgan.md +12 -0
- package/agents/platform/gym/souls/riley.md +12 -0
- package/agents/platform/gym/souls/sam.md +12 -0
- package/agents/platform/hub/CLAUDE.md +372 -0
- package/agents/platform/promptcreator/CLAUDE.md +130 -0
- package/agents/platform/skillcreator/CLAUDE.md +163 -0
- package/bin/cli.js +566 -0
- package/config.example.json +310 -0
- package/dist/agent-registry.d.ts +32 -0
- package/dist/agent-registry.d.ts.map +1 -0
- package/dist/agent-registry.js +144 -0
- package/dist/agent-registry.js.map +1 -0
- package/dist/channels/discord.d.ts +17 -0
- package/dist/channels/discord.d.ts.map +1 -0
- package/dist/channels/discord.js +114 -0
- package/dist/channels/discord.js.map +1 -0
- package/dist/channels/imessage.d.ts +23 -0
- package/dist/channels/imessage.d.ts.map +1 -0
- package/dist/channels/imessage.js +214 -0
- package/dist/channels/imessage.js.map +1 -0
- package/dist/channels/slack.d.ts +19 -0
- package/dist/channels/slack.d.ts.map +1 -0
- package/dist/channels/slack.js +167 -0
- package/dist/channels/slack.js.map +1 -0
- package/dist/channels/telegram.d.ts +19 -0
- package/dist/channels/telegram.d.ts.map +1 -0
- package/dist/channels/telegram.js +274 -0
- package/dist/channels/telegram.js.map +1 -0
- package/dist/channels/types.d.ts +44 -0
- package/dist/channels/types.d.ts.map +1 -0
- package/dist/channels/types.js +18 -0
- package/dist/channels/types.js.map +1 -0
- package/dist/channels/whatsapp.d.ts +23 -0
- package/dist/channels/whatsapp.d.ts.map +1 -0
- package/dist/channels/whatsapp.js +189 -0
- package/dist/channels/whatsapp.js.map +1 -0
- package/dist/config.d.ts +134 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +127 -0
- package/dist/config.js.map +1 -0
- package/dist/cron.d.ts +8 -0
- package/dist/cron.d.ts.map +1 -0
- package/dist/cron.js +35 -0
- package/dist/cron.js.map +1 -0
- package/dist/decrypt-keys.d.ts +7 -0
- package/dist/decrypt-keys.d.ts.map +1 -0
- package/dist/decrypt-keys.js +53 -0
- package/dist/decrypt-keys.js.map +1 -0
- package/dist/encrypt-keys.d.ts +8 -0
- package/dist/encrypt-keys.d.ts.map +1 -0
- package/dist/encrypt-keys.js +62 -0
- package/dist/encrypt-keys.js.map +1 -0
- package/dist/executor.d.ts +31 -0
- package/dist/executor.d.ts.map +1 -0
- package/dist/executor.js +2009 -0
- package/dist/executor.js.map +1 -0
- package/dist/gemini-executor.d.ts +27 -0
- package/dist/gemini-executor.d.ts.map +1 -0
- package/dist/gemini-executor.js +160 -0
- package/dist/gemini-executor.js.map +1 -0
- package/dist/goals.d.ts +24 -0
- package/dist/goals.d.ts.map +1 -0
- package/dist/goals.js +189 -0
- package/dist/goals.js.map +1 -0
- package/dist/gym/activity-digest.d.ts +30 -0
- package/dist/gym/activity-digest.d.ts.map +1 -0
- package/dist/gym/activity-digest.js +506 -0
- package/dist/gym/activity-digest.js.map +1 -0
- package/dist/gym/dimension-scorer.d.ts +76 -0
- package/dist/gym/dimension-scorer.d.ts.map +1 -0
- package/dist/gym/dimension-scorer.js +236 -0
- package/dist/gym/dimension-scorer.js.map +1 -0
- package/dist/gym/gym-router.d.ts +7 -0
- package/dist/gym/gym-router.d.ts.map +1 -0
- package/dist/gym/gym-router.js +718 -0
- package/dist/gym/gym-router.js.map +1 -0
- package/dist/gym/index.d.ts +11 -0
- package/dist/gym/index.d.ts.map +1 -0
- package/dist/gym/index.js +11 -0
- package/dist/gym/index.js.map +1 -0
- package/dist/heartbeat.d.ts +21 -0
- package/dist/heartbeat.d.ts.map +1 -0
- package/dist/heartbeat.js +163 -0
- package/dist/heartbeat.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +254 -0
- package/dist/index.js.map +1 -0
- package/dist/keystore.d.ts +22 -0
- package/dist/keystore.d.ts.map +1 -0
- package/dist/keystore.js +178 -0
- package/dist/keystore.js.map +1 -0
- package/dist/logger.d.ts +9 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +45 -0
- package/dist/logger.js.map +1 -0
- package/dist/memory/daily.d.ts +22 -0
- package/dist/memory/daily.d.ts.map +1 -0
- package/dist/memory/daily.js +82 -0
- package/dist/memory/daily.js.map +1 -0
- package/dist/memory/embeddings.d.ts +15 -0
- package/dist/memory/embeddings.d.ts.map +1 -0
- package/dist/memory/embeddings.js +154 -0
- package/dist/memory/embeddings.js.map +1 -0
- package/dist/memory/index.d.ts +32 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +159 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/search.d.ts +21 -0
- package/dist/memory/search.d.ts.map +1 -0
- package/dist/memory/search.js +77 -0
- package/dist/memory/search.js.map +1 -0
- package/dist/memory/store.d.ts +23 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +144 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/ollama-executor.d.ts +17 -0
- package/dist/ollama-executor.d.ts.map +1 -0
- package/dist/ollama-executor.js +112 -0
- package/dist/ollama-executor.js.map +1 -0
- package/dist/openai-executor.d.ts +38 -0
- package/dist/openai-executor.d.ts.map +1 -0
- package/dist/openai-executor.js +197 -0
- package/dist/openai-executor.js.map +1 -0
- package/dist/router.d.ts +11 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +185 -0
- package/dist/router.js.map +1 -0
- package/dist/test-message.d.ts +2 -0
- package/dist/test-message.d.ts.map +1 -0
- package/dist/test-message.js +60 -0
- package/dist/test-message.js.map +1 -0
- package/dist/utils/imsg-db-reader.d.ts +24 -0
- package/dist/utils/imsg-db-reader.d.ts.map +1 -0
- package/dist/utils/imsg-db-reader.js +92 -0
- package/dist/utils/imsg-db-reader.js.map +1 -0
- package/dist/utils/imsg-rpc.d.ts +25 -0
- package/dist/utils/imsg-rpc.d.ts.map +1 -0
- package/dist/utils/imsg-rpc.js +149 -0
- package/dist/utils/imsg-rpc.js.map +1 -0
- package/dist/utils/message-formatter.d.ts +3 -0
- package/dist/utils/message-formatter.d.ts.map +1 -0
- package/dist/utils/message-formatter.js +69 -0
- package/dist/utils/message-formatter.js.map +1 -0
- package/dist/web-ui.d.ts +12 -0
- package/dist/web-ui.d.ts.map +1 -0
- package/dist/web-ui.js +5784 -0
- package/dist/web-ui.js.map +1 -0
- package/dist/whatsapp-chats.d.ts +2 -0
- package/dist/whatsapp-chats.d.ts.map +1 -0
- package/dist/whatsapp-chats.js +76 -0
- package/dist/whatsapp-chats.js.map +1 -0
- package/dist/whatsapp-login.d.ts +2 -0
- package/dist/whatsapp-login.d.ts.map +1 -0
- package/dist/whatsapp-login.js +90 -0
- package/dist/whatsapp-login.js.map +1 -0
- package/dist/wiki-sync.d.ts +21 -0
- package/dist/wiki-sync.d.ts.map +1 -0
- package/dist/wiki-sync.js +147 -0
- package/dist/wiki-sync.js.map +1 -0
- package/docs/AddNewAgentGuide.md +100 -0
- package/docs/AddNewMcpGuide.md +72 -0
- package/docs/Architecture.md +795 -0
- package/docs/CLAUDE-AI-SETUP.md +166 -0
- package/docs/Setup.md +297 -0
- package/docs/ai-gym-architecture.md +1040 -0
- package/docs/ai-gym-build-plan.md +343 -0
- package/docs/ai-gym-onboarding.md +122 -0
- package/docs/appcreator_plan.md +348 -0
- package/docs/platform-mcp-audit.md +320 -0
- package/docs/server-deployment-plan.md +503 -0
- package/docs/superpowers/plans/2026-03-25-marketplace.md +1281 -0
- package/docs/superpowers/specs/2026-03-25-marketplace-design.md +287 -0
- package/docs/user-guide.md +2016 -0
- package/mcp-catalog.json +628 -0
- package/package.json +63 -0
- package/public/MyAIforOne-logomark-512.svg +16 -0
- package/public/MyAIforOne-logomark-transparent.svg +15 -0
- package/public/activity.html +314 -0
- package/public/admin.html +1674 -0
- package/public/agent-dashboard.html +670 -0
- package/public/api-docs.html +1106 -0
- package/public/automations.html +722 -0
- package/public/canvas.css +223 -0
- package/public/canvas.js +588 -0
- package/public/changelog.html +231 -0
- package/public/gym.html +2766 -0
- package/public/home.html +1930 -0
- package/public/index.html +2809 -0
- package/public/lab.html +1643 -0
- package/public/library.html +1442 -0
- package/public/marketplace.html +1101 -0
- package/public/mcp-docs.html +441 -0
- package/public/mini.html +390 -0
- package/public/monitor.html +584 -0
- package/public/org.html +4304 -0
- package/public/projects.html +734 -0
- package/public/settings.html +645 -0
- package/public/tasks.html +932 -0
- package/public/trainers/alex.svg +12 -0
- package/public/trainers/jordan.svg +12 -0
- package/public/trainers/morgan.svg +12 -0
- package/public/trainers/riley.svg +12 -0
- package/public/trainers/sam.svg +12 -0
- package/public/user-guide.html +218 -0
- package/registry/agents.json +3 -0
- package/registry/apps.json +20 -0
- package/registry/installed-drafts.json +3 -0
- package/registry/mcps.json +1084 -0
- package/registry/prompts/personal/mcp-test-prompt.md +6 -0
- package/registry/prompts/personal/memory-recall.md +6 -0
- package/registry/prompts/platform/brainstorm.md +15 -0
- package/registry/prompts/platform/code-review.md +16 -0
- package/registry/prompts/platform/explain.md +16 -0
- package/registry/prompts.json +58 -0
- package/registry/skills/external/brainstorming.md +5 -0
- package/registry/skills/external/code-review.md +40 -0
- package/registry/skills/external/frontend-patterns.md +642 -0
- package/registry/skills/external/frontend-slides.md +184 -0
- package/registry/skills/external/systematic-debugging.md +5 -0
- package/registry/skills/external/tdd.md +328 -0
- package/registry/skills/external/verification-before-completion.md +5 -0
- package/registry/skills/external/writing-plans.md +5 -0
- package/registry/skills/platform/ai41_app_build.md +930 -0
- package/registry/skills/platform/ai41_app_deploy.md +168 -0
- package/registry/skills/platform/ai41_app_orchestrator.md +239 -0
- package/registry/skills/platform/ai41_app_patterns.md +359 -0
- package/registry/skills/platform/ai41_app_register.md +85 -0
- package/registry/skills/platform/ai41_app_scaffold.md +421 -0
- package/registry/skills/platform/ai41_app_verify.md +107 -0
- package/registry/skills/platform/opProjectCreate.md +239 -0
- package/registry/skills/platform/op_devbrowser.md +136 -0
- package/registry/skills/platform/sop_brandguidelines.md +103 -0
- package/registry/skills/platform/sop_docx.md +117 -0
- package/registry/skills/platform/sop_frontenddesign.md +44 -0
- package/registry/skills/platform/sop_frontenddesign_v2.md +659 -0
- package/registry/skills/platform/sop_mcpbuilder.md +133 -0
- package/registry/skills/platform/sop_pdf.md +172 -0
- package/registry/skills/platform/sop_pptx.md +133 -0
- package/registry/skills/platform/sop_skillcreator.md +104 -0
- package/registry/skills/platform/sop_themefactory.md +128 -0
- package/registry/skills/platform/sop_webapptesting.md +75 -0
- package/registry/skills/platform/sop_webartifactsbuilder.md +97 -0
- package/registry/skills/platform/sop_xlsx.md +134 -0
- package/registry/skills.json +1055 -0
- package/scripts/discover-chats.sh +11 -0
- package/scripts/install-service-windows.ps1 +87 -0
- package/scripts/install-service.sh +52 -0
- package/scripts/seed-registry.ts +195 -0
- package/scripts/test-send.sh +5 -0
- package/scripts/tray-indicator.ps1 +35 -0
- package/scripts/uninstall-service-windows.ps1 +23 -0
- package/scripts/uninstall-service.sh +15 -0
- package/scripts/xbar-myagent.5s.sh +32 -0
- package/server/mcp-server/dist/index.d.ts +11 -0
- package/server/mcp-server/dist/index.js +1332 -0
- package/server/mcp-server/dist/lib/api-client.d.ts +165 -0
- package/server/mcp-server/dist/lib/api-client.js +241 -0
- package/server/mcp-server/index.ts +1545 -0
- package/server/mcp-server/lib/api-client.ts +366 -0
- package/server/mcp-server/tsconfig.json +14 -0
- package/src/agent-registry.ts +180 -0
- package/src/channels/discord.ts +129 -0
- package/src/channels/imessage.ts +261 -0
- package/src/channels/slack.ts +208 -0
- package/src/channels/telegram.ts +307 -0
- package/src/channels/types.ts +62 -0
- package/src/channels/whatsapp.ts +227 -0
- package/src/config.ts +281 -0
- package/src/cron.ts +43 -0
- package/src/decrypt-keys.ts +60 -0
- package/src/encrypt-keys.ts +70 -0
- package/src/executor.ts +2190 -0
- package/src/gemini-executor.ts +212 -0
- package/src/goals.ts +240 -0
- package/src/gym/activity-digest.ts +546 -0
- package/src/gym/dimension-scorer.ts +297 -0
- package/src/gym/gym-router.ts +801 -0
- package/src/gym/index.ts +19 -0
- package/src/heartbeat.ts +220 -0
- package/src/index.ts +275 -0
- package/src/keystore.ts +190 -0
- package/src/logger.ts +51 -0
- package/src/memory/daily.ts +101 -0
- package/src/memory/embeddings.ts +185 -0
- package/src/memory/index.ts +218 -0
- package/src/memory/search.ts +124 -0
- package/src/memory/store.ts +189 -0
- package/src/ollama-executor.ts +126 -0
- package/src/openai-executor.ts +259 -0
- package/src/router.ts +230 -0
- package/src/test-message.ts +72 -0
- package/src/utils/imsg-db-reader.ts +109 -0
- package/src/utils/imsg-rpc.ts +178 -0
- package/src/utils/message-formatter.ts +90 -0
- package/src/web-ui.ts +5778 -0
- package/src/whatsapp-chats.ts +91 -0
- package/src/whatsapp-login.ts +110 -0
- package/src/wiki-sync.ts +199 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,645 @@
|
|
|
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>MyAIforOne — Settings</title>
|
|
7
|
+
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&family=Syne:wght@600;700;800&display=swap" rel="stylesheet">
|
|
8
|
+
<style>
|
|
9
|
+
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
|
10
|
+
:root{
|
|
11
|
+
--bg-deep:#060a13;--bg-surface:rgba(12,18,33,0.92);--bg-card:rgba(16,22,40,0.85);
|
|
12
|
+
--bg-input:rgba(0,0,0,0.35);--border-dim:rgba(56,189,248,0.08);
|
|
13
|
+
--border-glow:rgba(56,189,248,0.18);--border-active:rgba(56,189,248,0.45);
|
|
14
|
+
--text-primary:rgba(255,255,255,0.92);--text-secondary:rgba(255,255,255,0.68);
|
|
15
|
+
--text-muted:rgba(148,163,184,0.55);--accent:#22d3ee;--accent-bg:rgba(6,182,212,0.15);
|
|
16
|
+
--purple:rgba(139,92,246,0.7);--purple-bg:rgba(139,92,246,0.12);
|
|
17
|
+
--green:#4ade80;--green-bg:rgba(74,222,128,0.1);
|
|
18
|
+
--red:#f87171;--red-bg:rgba(248,113,113,0.1);--amber:#fbbf24;--amber-bg:rgba(251,191,36,0.1);
|
|
19
|
+
--shadow:0 2px 12px rgba(0,0,0,0.3);--radius:12px;
|
|
20
|
+
--font-sans:'DM Sans',system-ui,sans-serif;--font-mono:'IBM Plex Mono',monospace;
|
|
21
|
+
--font-display:'Syne',sans-serif;
|
|
22
|
+
}
|
|
23
|
+
[data-theme="light"]{
|
|
24
|
+
--bg-deep:#f4f6f9;--bg-surface:rgba(255,255,255,0.95);--bg-card:rgba(255,255,255,0.9);
|
|
25
|
+
--bg-input:rgba(0,0,0,0.04);--border-dim:rgba(0,0,0,0.08);
|
|
26
|
+
--border-glow:rgba(14,116,144,0.18);--border-active:rgba(14,116,144,0.45);
|
|
27
|
+
--text-primary:rgba(15,23,42,0.92);--text-secondary:rgba(51,65,85,0.8);
|
|
28
|
+
--text-muted:rgba(100,116,139,0.6);--accent:#0891b2;--accent-bg:rgba(14,116,144,0.08);
|
|
29
|
+
--purple:rgba(109,40,217,0.75);--purple-bg:rgba(139,92,246,0.08);
|
|
30
|
+
--green:#16a34a;--green-bg:rgba(22,163,74,0.08);--red:#dc2626;--red-bg:rgba(220,38,38,0.08);
|
|
31
|
+
--amber:#d97706;--amber-bg:rgba(217,119,6,0.08);--shadow:0 1px 8px rgba(0,0,0,0.06);
|
|
32
|
+
}
|
|
33
|
+
html,body{width:100%;min-height:100%;max-width:100vw;background:var(--bg-deep);font-family:var(--font-sans);color:var(--text-primary);transition:background .3s,color .3s}
|
|
34
|
+
|
|
35
|
+
.topbar{height:56px;display:flex;align-items:center;padding:0 24px;background:var(--bg-surface);border-bottom:1px solid var(--border-dim);backdrop-filter:blur(20px);position:fixed;top:0;left:0;right:0;z-index:100;overflow:hidden;max-width:100vw}
|
|
36
|
+
.topbar-logo{display:flex;align-items:center;gap:10px;margin-right:32px;flex-shrink:0}
|
|
37
|
+
.logo-mark{width:28px;height:28px;border-radius:8px;object-fit:contain}
|
|
38
|
+
.logo-text{font-family:var(--font-display);font-size:15px;font-weight:700;color:var(--accent)}
|
|
39
|
+
.tab-group{display:flex;gap:0;flex-shrink:1;min-width:0;overflow-x:auto}
|
|
40
|
+
.tab-btn{font-family:var(--font-sans);font-size:13px;font-weight:500;color:var(--text-muted);text-decoration:none;padding:8px 14px;border-radius:8px;transition:color .2s;white-space:nowrap;flex-shrink:0}
|
|
41
|
+
.tab-btn:hover{color:var(--text-secondary)}
|
|
42
|
+
.tab-btn.active{color:var(--accent)}
|
|
43
|
+
.topbar-right{margin-left:auto;display:flex;align-items:center;gap:8px;flex-shrink:0}
|
|
44
|
+
.gym-nav-btn{font-family:var(--font-sans);font-size:12px;font-weight:700;color:#fff;background:var(--accent);border:none;border-radius:8px;padding:6px 14px;cursor:pointer;text-decoration:none;letter-spacing:.02em;transition:opacity .2s,transform .2s;white-space:nowrap}
|
|
45
|
+
.gym-nav-btn:hover{opacity:.88;transform:translateY(-1px)}
|
|
46
|
+
.theme-toggle{width:34px;height:34px;border-radius:8px;border:1px solid var(--border-dim);background:transparent;color:var(--text-muted);cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:16px;transition:all .2s}
|
|
47
|
+
.theme-toggle:hover{border-color:var(--border-glow);color:var(--text-secondary)}
|
|
48
|
+
.gear-btn{width:34px;height:34px;border-radius:8px;border:1px solid var(--border-dim);background:transparent;color:var(--text-muted);cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:16px;transition:all .2s;text-decoration:none}
|
|
49
|
+
.gear-btn:hover{border-color:var(--border-glow);color:var(--text-secondary)}
|
|
50
|
+
.docs-dropdown{position:relative;display:inline-block}
|
|
51
|
+
.docs-menu{display:none;position:absolute;top:40px;right:0;min-width:160px;background:var(--bg-surface);border:1px solid var(--border-glow);border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,0.4);z-index:200;padding:4px;backdrop-filter:blur(20px)}
|
|
52
|
+
.docs-menu.open{display:block}
|
|
53
|
+
.docs-menu a{display:flex;align-items:center;gap:8px;padding:7px 12px;font-size:12px;font-weight:500;color:var(--text-secondary);text-decoration:none;border-radius:6px;transition:all .15s}
|
|
54
|
+
.docs-menu a:hover{background:var(--accent-bg);color:var(--accent)}
|
|
55
|
+
.docs-menu a .dm-icon{font-size:14px;width:18px;text-align:center}
|
|
56
|
+
|
|
57
|
+
.sub-nav{position:fixed;top:56px;left:0;right:0;z-index:99;height:36px;display:flex;align-items:center;gap:2px;padding:0 24px;background:var(--bg-surface);border-bottom:1px solid var(--border-dim);backdrop-filter:blur(20px)}
|
|
58
|
+
.sub-nav-link{font-family:var(--font-sans);font-size:12px;font-weight:500;color:var(--text-muted);text-decoration:none;padding:4px 10px;border-radius:5px;transition:color .2s}
|
|
59
|
+
.sub-nav-link:hover{color:var(--text-secondary)}
|
|
60
|
+
.sub-nav-link.active{color:var(--accent)}
|
|
61
|
+
|
|
62
|
+
.page{padding:116px 24px 60px;max-width:780px;margin:0 auto}
|
|
63
|
+
.page-title{font-family:var(--font-display);font-size:22px;font-weight:800;margin-bottom:4px}
|
|
64
|
+
.page-subtitle{font-size:13px;color:var(--text-muted);margin-bottom:36px}
|
|
65
|
+
|
|
66
|
+
.section{background:var(--bg-card);border:1px solid var(--border-glow);border-radius:var(--radius);margin-bottom:24px;overflow:hidden}
|
|
67
|
+
.section-header{padding:16px 20px;border-bottom:1px solid var(--border-dim);display:flex;align-items:center;gap:10px}
|
|
68
|
+
.section-icon{width:28px;height:28px;border-radius:7px;background:var(--accent-bg);border:1px solid var(--accent);display:flex;align-items:center;justify-content:center;font-size:13px;color:var(--accent);flex-shrink:0}
|
|
69
|
+
.section-title{font-family:var(--font-display);font-size:14px;font-weight:700;color:var(--accent)}
|
|
70
|
+
.section-body{padding:16px 20px}
|
|
71
|
+
|
|
72
|
+
/* Account rows */
|
|
73
|
+
.account-row{display:flex;align-items:center;gap:10px;padding:11px 0;border-bottom:1px solid var(--border-dim)}
|
|
74
|
+
.account-row:last-of-type{border-bottom:none}
|
|
75
|
+
.account-name{font-family:var(--font-mono);font-size:12px;font-weight:600;color:var(--accent);min-width:90px}
|
|
76
|
+
.account-path{font-family:var(--font-mono);font-size:11px;color:var(--text-secondary);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
77
|
+
.status-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
|
|
78
|
+
.status-dot.ok{background:var(--green);box-shadow:0 0 6px rgba(74,222,128,0.5)}
|
|
79
|
+
.status-dot.unknown{background:var(--text-muted)}
|
|
80
|
+
.status-dot.err{background:var(--red)}
|
|
81
|
+
.btn-icon{width:26px;height:26px;border-radius:6px;border:1px solid var(--border-dim);background:transparent;color:var(--text-muted);cursor:pointer;font-size:13px;display:flex;align-items:center;justify-content:center;transition:all .2s;flex-shrink:0}
|
|
82
|
+
.btn-icon:hover{border-color:var(--red);color:var(--red);background:var(--red-bg)}
|
|
83
|
+
.btn-icon.relogin:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-bg)}
|
|
84
|
+
|
|
85
|
+
/* Add account form */
|
|
86
|
+
.divider{border:none;border-top:1px solid var(--border-dim);margin:16px 0}
|
|
87
|
+
.form-label{font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--text-muted);margin-bottom:12px}
|
|
88
|
+
.field-row{display:flex;gap:8px;align-items:flex-end;flex-wrap:wrap}
|
|
89
|
+
.field{display:flex;flex-direction:column;gap:4px;flex:1;min-width:120px}
|
|
90
|
+
.field label{font-size:10px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--text-muted)}
|
|
91
|
+
.field input{padding:8px 10px;border-radius:8px;border:1px solid var(--border-dim);background:var(--bg-input);color:var(--text-primary);font-family:var(--font-mono);font-size:12px;outline:none;transition:border-color .2s;width:100%}
|
|
92
|
+
.field input:focus{border-color:var(--border-active)}
|
|
93
|
+
.field input::placeholder{color:var(--text-muted)}
|
|
94
|
+
.btn-primary{padding:8px 18px;border-radius:8px;border:1px solid var(--accent);background:var(--accent-bg);color:var(--accent);font-family:var(--font-sans);font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap;transition:all .2s;align-self:flex-end;flex-shrink:0}
|
|
95
|
+
.btn-primary:hover{background:var(--accent);color:#000}
|
|
96
|
+
.btn-primary:disabled{opacity:.45;cursor:not-allowed}
|
|
97
|
+
.hint{font-size:11px;color:var(--text-muted);margin-top:10px;line-height:1.6}
|
|
98
|
+
.hint code{font-family:var(--font-mono);font-size:10px;background:var(--bg-input);padding:1px 5px;border-radius:4px}
|
|
99
|
+
|
|
100
|
+
/* Login flow panel */
|
|
101
|
+
.login-panel{margin-top:14px;padding:16px;border-radius:10px;border:1px solid var(--border-dim);background:var(--bg-input);display:none}
|
|
102
|
+
.login-panel.visible{display:block}
|
|
103
|
+
.login-panel-title{font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--text-muted);margin-bottom:8px}
|
|
104
|
+
.login-url-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:4px}
|
|
105
|
+
.login-url{font-family:var(--font-mono);font-size:11px;color:var(--accent);word-break:break-all;flex:1;min-width:0;user-select:all}
|
|
106
|
+
.btn-copy{padding:5px 12px;border-radius:7px;border:1px solid var(--border-glow);background:transparent;color:var(--text-muted);font-size:11px;font-weight:600;cursor:pointer;white-space:nowrap;transition:all .2s;flex-shrink:0}
|
|
107
|
+
.btn-copy:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-bg)}
|
|
108
|
+
.btn-open{padding:5px 12px;border-radius:7px;border:1px solid var(--accent);background:var(--accent-bg);color:var(--accent);font-size:11px;font-weight:600;cursor:pointer;text-decoration:none;white-space:nowrap;transition:all .2s;flex-shrink:0}
|
|
109
|
+
.btn-open:hover{background:var(--accent);color:#000}
|
|
110
|
+
.code-input-row{display:flex;gap:8px;align-items:center;margin-bottom:8px;flex-wrap:wrap}
|
|
111
|
+
.code-input-row input{flex:1;min-width:160px;padding:8px 10px;border-radius:8px;border:1px solid var(--border-dim);background:var(--bg-deep);color:var(--text-primary);font-family:var(--font-mono);font-size:12px;outline:none;transition:border-color .2s}
|
|
112
|
+
.code-input-row input:focus{border-color:var(--border-active)}
|
|
113
|
+
.code-input-row input::placeholder{color:var(--text-muted)}
|
|
114
|
+
.login-status-msg{font-size:12px;color:var(--text-muted);min-height:16px}
|
|
115
|
+
.btn-verify{padding:7px 16px;border-radius:7px;border:1px solid var(--green);background:var(--green-bg);color:var(--green);font-size:12px;font-weight:600;cursor:pointer;transition:all .2s;white-space:nowrap}
|
|
116
|
+
.btn-verify:hover{background:var(--green);color:#000}
|
|
117
|
+
.btn-verify:disabled{opacity:.45;cursor:not-allowed}
|
|
118
|
+
|
|
119
|
+
/* Service settings */
|
|
120
|
+
.service-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px}
|
|
121
|
+
@media(max-width:560px){.service-grid{grid-template-columns:1fr}}
|
|
122
|
+
.btn-save{padding:8px 20px;border-radius:8px;border:1px solid var(--accent);background:var(--accent-bg);color:var(--accent);font-family:var(--font-sans);font-size:12px;font-weight:600;cursor:pointer;transition:all .2s;margin-top:14px}
|
|
123
|
+
.btn-save:hover{background:var(--accent);color:#000}
|
|
124
|
+
|
|
125
|
+
/* Empty */
|
|
126
|
+
.empty{padding:20px 0;text-align:center;color:var(--text-muted);font-size:12px}
|
|
127
|
+
|
|
128
|
+
/* Toast */
|
|
129
|
+
.toast{position:fixed;bottom:24px;right:24px;padding:10px 18px;border-radius:8px;font-size:12px;font-weight:600;z-index:9999;opacity:0;transform:translateY(8px);transition:all .25s;pointer-events:none}
|
|
130
|
+
.toast.show{opacity:1;transform:translateY(0)}
|
|
131
|
+
.toast.ok{background:var(--green-bg);border:1px solid var(--green);color:var(--green)}
|
|
132
|
+
.toast.err{background:var(--red-bg);border:1px solid var(--red);color:var(--red)}
|
|
133
|
+
.toast.info{background:var(--accent-bg);border:1px solid var(--accent);color:var(--accent)}
|
|
134
|
+
</style>
|
|
135
|
+
</head>
|
|
136
|
+
<body>
|
|
137
|
+
|
|
138
|
+
<div class="topbar">
|
|
139
|
+
<a href="/" style="display:flex;align-items:center;gap:10px;margin-right:28px;text-decoration:none">
|
|
140
|
+
<img class="logo-mark" src="/MyAIforOne-logomark-transparent.svg" alt="MyAIforOne">
|
|
141
|
+
<span class="logo-text">MyAIforOne</span>
|
|
142
|
+
</a>
|
|
143
|
+
<div class="tab-group">
|
|
144
|
+
<a class="tab-btn" href="/">Home</a>
|
|
145
|
+
<a class="tab-btn" href="/ui">Chat</a>
|
|
146
|
+
<a class="tab-btn active" href="/org">Agents</a>
|
|
147
|
+
<a class="tab-btn" href="/library">Library</a>
|
|
148
|
+
<a class="tab-btn" href="/lab">Lab</a>
|
|
149
|
+
</div>
|
|
150
|
+
<div class="topbar-right">
|
|
151
|
+
<a class="gym-nav-btn gym-tab-link" href="/gym" style="display:none">Gym</a>
|
|
152
|
+
<a href="/marketplace" class="gear-btn" title="Marketplace" style="font-size:11px;font-weight:700;letter-spacing:.03em;padding:0 10px;width:auto">Marketplace</a>
|
|
153
|
+
<a href="/monitor" class="gear-btn" title="Monitor" style="font-size:11px;font-weight:700;letter-spacing:.03em;padding:0 10px;width:auto">Monitor</a>
|
|
154
|
+
<a href="/admin" class="gear-btn" title="Admin" style="font-size:11px;font-weight:700;letter-spacing:.03em;padding:0 10px;width:auto">Admin</a>
|
|
155
|
+
<a href="/user-guide" class="gear-btn" title="User Guide" style="font-size:11px;font-weight:700;letter-spacing:.03em;padding:0 10px;width:auto">User Guide</a>
|
|
156
|
+
<button onclick="window.open('/mini','minibar','width=440,height=460,resizable=yes,scrollbars=no')" title="Open Mini Bar" style="display:flex;align-items:center;justify-content:center;width:34px;height:34px;border-radius:8px;border:1px solid var(--border-dim);background:transparent;color:var(--text-muted);cursor:pointer;font-size:15px;transition:all .2s" onmouseover="this.style.borderColor='var(--border-glow)'" onmouseout="this.style.borderColor='var(--border-dim)'">⊡</button>
|
|
157
|
+
<button class="theme-toggle" onclick="toggleTheme()" title="Toggle theme">☀</button>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
<div class="sub-nav">
|
|
162
|
+
<a class="sub-nav-link" href="/org">Teams</a>
|
|
163
|
+
<a class="sub-nav-link" href="/tasks">Tasks</a>
|
|
164
|
+
<a class="sub-nav-link" href="/automations">Automations</a>
|
|
165
|
+
</div>
|
|
166
|
+
|
|
167
|
+
<div class="page">
|
|
168
|
+
<div class="page-title">Settings</div>
|
|
169
|
+
<div class="page-subtitle">Manage Claude accounts, service options, and global defaults.</div>
|
|
170
|
+
|
|
171
|
+
<!-- ── Claude Accounts ────────────────────────────────────── -->
|
|
172
|
+
<div class="section">
|
|
173
|
+
<div class="section-header">
|
|
174
|
+
<div class="section-icon">⚙</div>
|
|
175
|
+
<div>
|
|
176
|
+
<div class="section-title">Claude Accounts</div>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
<div class="section-body">
|
|
180
|
+
|
|
181
|
+
<!-- Existing accounts list -->
|
|
182
|
+
<div id="accountsList"><div class="empty">Loading...</div></div>
|
|
183
|
+
|
|
184
|
+
<hr class="divider">
|
|
185
|
+
|
|
186
|
+
<!-- Add + Login flow -->
|
|
187
|
+
<div class="form-label">Add Account</div>
|
|
188
|
+
<div class="field-row">
|
|
189
|
+
<div class="field" style="max-width:200px">
|
|
190
|
+
<label>Account Name</label>
|
|
191
|
+
<input id="newAccName" placeholder="main, work, personal…" />
|
|
192
|
+
</div>
|
|
193
|
+
<button class="btn-primary" id="startLoginBtn" onclick="startLogin()">→ Login & Add</button>
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
<!-- Login flow panel — shown after clicking Login & Add -->
|
|
197
|
+
<div class="login-panel" id="loginPanel">
|
|
198
|
+
<div class="login-panel-title">Authorize Claude Account</div>
|
|
199
|
+
<div id="loginPanelBody"></div>
|
|
200
|
+
</div>
|
|
201
|
+
|
|
202
|
+
<div class="hint">
|
|
203
|
+
The config directory is derived automatically from the account name — <code>main</code> uses <code>~/.claude</code>, any other name uses <code>~/.claude-{name}</code>.
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
|
|
208
|
+
<!-- ── Service ────────────────────────────────────────────── -->
|
|
209
|
+
<div class="section">
|
|
210
|
+
<div class="section-header">
|
|
211
|
+
<div class="section-icon" style="background:var(--purple-bg);border-color:var(--purple);color:var(--purple)">◆</div>
|
|
212
|
+
<div><div class="section-title" style="color:var(--purple)">Service</div></div>
|
|
213
|
+
<span style="margin-left:auto;font-size:11px;color:var(--text-muted)">Restart required for most changes</span>
|
|
214
|
+
</div>
|
|
215
|
+
<div class="section-body">
|
|
216
|
+
<div class="service-grid">
|
|
217
|
+
<div class="field">
|
|
218
|
+
<label>Personal Agents Directory</label>
|
|
219
|
+
<input id="svcAgentsDir" placeholder="~/Desktop/MyAIforOne Drive/PersonalAgents" />
|
|
220
|
+
</div>
|
|
221
|
+
<div class="field">
|
|
222
|
+
<label>Personal Registry Directory</label>
|
|
223
|
+
<input id="svcRegistryDir" placeholder="~/Desktop/MyAIforOne Drive/PersonalRegistry" />
|
|
224
|
+
</div>
|
|
225
|
+
<div class="field">
|
|
226
|
+
<label>Web UI Port</label>
|
|
227
|
+
<input id="svcPort" type="number" placeholder="4888" />
|
|
228
|
+
</div>
|
|
229
|
+
<div class="field">
|
|
230
|
+
<label>Log Level</label>
|
|
231
|
+
<input id="svcLogLevel" placeholder="info" />
|
|
232
|
+
</div>
|
|
233
|
+
</div>
|
|
234
|
+
<button class="btn-save" onclick="saveService()">Save</button>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
|
|
238
|
+
<!-- ── Deployment ─────────────────────────────────────────────── -->
|
|
239
|
+
<div class="section">
|
|
240
|
+
<div class="section-header">
|
|
241
|
+
<div class="section-icon" style="background:var(--green-bg);border-color:var(--green);color:var(--green)">▴</div>
|
|
242
|
+
<div><div class="section-title" style="color:var(--green)">Deployment</div></div>
|
|
243
|
+
</div>
|
|
244
|
+
<div class="section-body">
|
|
245
|
+
<div class="service-grid">
|
|
246
|
+
<div class="field">
|
|
247
|
+
<label>Provider</label>
|
|
248
|
+
<input id="depProvider" placeholder="railway" />
|
|
249
|
+
</div>
|
|
250
|
+
<div class="field">
|
|
251
|
+
<label>Deploy Token <span id="depTokenReveal" onclick="toggleReveal('depToken','depTokenReveal')" style="cursor:pointer;font-size:10px;color:var(--accent);margin-left:4px">show</span></label>
|
|
252
|
+
<input id="depToken" type="password" placeholder="••••••••" autocomplete="off" />
|
|
253
|
+
</div>
|
|
254
|
+
<div class="field">
|
|
255
|
+
<label>GitHub Org / User</label>
|
|
256
|
+
<input id="depGithubOrg" placeholder="myorg" />
|
|
257
|
+
</div>
|
|
258
|
+
<div class="field">
|
|
259
|
+
<label>GitHub Token <span id="depGithubTokenReveal" onclick="toggleReveal('depGithubToken','depGithubTokenReveal')" style="cursor:pointer;font-size:10px;color:var(--accent);margin-left:4px">show</span></label>
|
|
260
|
+
<input id="depGithubToken" type="password" placeholder="••••••••" autocomplete="off" />
|
|
261
|
+
</div>
|
|
262
|
+
</div>
|
|
263
|
+
<button class="btn-save" onclick="saveDeployment()">Save</button>
|
|
264
|
+
</div>
|
|
265
|
+
</div>
|
|
266
|
+
|
|
267
|
+
<!-- ── Status Indicator ──────────────────────────────────────── -->
|
|
268
|
+
<div class="section">
|
|
269
|
+
<div class="section-header">
|
|
270
|
+
<div class="section-icon" style="background:rgba(168,85,247,0.15);border-color:#a855f7;color:#a855f7">●</div>
|
|
271
|
+
<div>
|
|
272
|
+
<div class="section-title">Status Indicator</div>
|
|
273
|
+
<div class="section-sub">Show a live status dot in your menu bar (Mac) or system tray (Windows)</div>
|
|
274
|
+
</div>
|
|
275
|
+
</div>
|
|
276
|
+
<div class="section-body">
|
|
277
|
+
<p style="font-size:13px;color:var(--text-dim);margin:0 0 16px;line-height:1.5">
|
|
278
|
+
Adds a small green/red indicator that shows if MyAgent is running. Click it to see agent count, uptime, and quick links. You can restart or stop the service from the menu.
|
|
279
|
+
</p>
|
|
280
|
+
<div id="indicatorInstallArea"></div>
|
|
281
|
+
</div>
|
|
282
|
+
</div>
|
|
283
|
+
</div>
|
|
284
|
+
|
|
285
|
+
<div class="toast" id="toast"></div>
|
|
286
|
+
|
|
287
|
+
<script>
|
|
288
|
+
// ── Theme ──────────────────────────────────────────────────────────
|
|
289
|
+
function applyTheme(t){document.documentElement.setAttribute('data-theme',t);localStorage.setItem('theme',t)}
|
|
290
|
+
function toggleTheme(){applyTheme(document.documentElement.getAttribute('data-theme')==='light'?'dark':'light')}
|
|
291
|
+
applyTheme(localStorage.getItem('theme')||'dark');
|
|
292
|
+
|
|
293
|
+
// ── Toast ──────────────────────────────────────────────────────────
|
|
294
|
+
let toastTimer;
|
|
295
|
+
function showToast(msg, type='ok', html=false) {
|
|
296
|
+
const t = document.getElementById('toast');
|
|
297
|
+
if (html) { t.innerHTML = msg; } else { t.textContent = msg; }
|
|
298
|
+
t.className = `toast ${type} show`;
|
|
299
|
+
clearTimeout(toastTimer);
|
|
300
|
+
toastTimer = setTimeout(() => t.classList.remove('show'), html ? 10000 : 3500);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// ── Accounts ───────────────────────────────────────────────────────
|
|
304
|
+
let accounts = {};
|
|
305
|
+
|
|
306
|
+
async function loadAccounts() {
|
|
307
|
+
const res = await fetch('/api/config/accounts');
|
|
308
|
+
accounts = await res.json();
|
|
309
|
+
renderAccounts();
|
|
310
|
+
// Check status for each
|
|
311
|
+
for (const name of Object.keys(accounts)) checkStatus(name);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function renderAccounts() {
|
|
315
|
+
const el = document.getElementById('accountsList');
|
|
316
|
+
const keys = Object.keys(accounts);
|
|
317
|
+
if (!keys.length) { el.innerHTML = '<div class="empty">No accounts yet. Add one below.</div>'; return; }
|
|
318
|
+
el.innerHTML = keys.map(name => `
|
|
319
|
+
<div class="account-row" id="acc-${escId(name)}">
|
|
320
|
+
<span class="status-dot unknown" id="dot-${escId(name)}" title="Checking..."></span>
|
|
321
|
+
<span class="account-name">${escHtml(name)}</span>
|
|
322
|
+
<span class="account-email" id="email-${escId(name)}" style="font-size:12px;color:var(--text-dim);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap"></span>
|
|
323
|
+
<span class="account-path" title="${escHtml(accounts[name])}">${escHtml(accounts[name])}</span>
|
|
324
|
+
<button class="btn-icon relogin" onclick="reloginAccount('${escHtml(name)}')" title="Re-authorize">↺</button>
|
|
325
|
+
<button class="btn-icon" onclick="deleteAccount('${escHtml(name)}')" title="Remove">✕</button>
|
|
326
|
+
</div>
|
|
327
|
+
`).join('');
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
async function checkStatus(name) {
|
|
331
|
+
const dot = document.getElementById(`dot-${escId(name)}`);
|
|
332
|
+
if (!dot) return;
|
|
333
|
+
try {
|
|
334
|
+
const res = await fetch(`/api/config/accounts/${encodeURIComponent(name)}/status`);
|
|
335
|
+
const d = await res.json();
|
|
336
|
+
dot.className = `status-dot ${d.loggedIn ? 'ok' : 'err'}`;
|
|
337
|
+
dot.title = d.loggedIn ? 'Logged in' : 'Not logged in';
|
|
338
|
+
const emailEl = document.getElementById(`email-${escId(name)}`);
|
|
339
|
+
if (emailEl && d.email) emailEl.textContent = d.email;
|
|
340
|
+
} catch { dot.className = 'status-dot unknown'; }
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
async function deleteAccount(name) {
|
|
344
|
+
if (!confirm(`Remove account "${name}"?`)) return;
|
|
345
|
+
const res = await fetch(`/api/config/accounts/${encodeURIComponent(name)}`, { method: 'DELETE' });
|
|
346
|
+
if (!res.ok) { const e = await res.json(); showToast(e.error, 'err'); return; }
|
|
347
|
+
delete accounts[name];
|
|
348
|
+
renderAccounts();
|
|
349
|
+
showToast(`Account "${name}" removed`);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// ── Login flow ─────────────────────────────────────────────────────
|
|
353
|
+
let pendingLogin = null; // { name, path, sessionId }
|
|
354
|
+
|
|
355
|
+
async function startLogin() {
|
|
356
|
+
const name = document.getElementById('newAccName').value.trim();
|
|
357
|
+
if (!name) { showToast('Account name required', 'err'); return; }
|
|
358
|
+
const path = (name === 'main' || name === 'default') ? '~/.claude' : `~/.claude-${name}`;
|
|
359
|
+
|
|
360
|
+
const btn = document.getElementById('startLoginBtn');
|
|
361
|
+
btn.disabled = true; btn.textContent = 'Connecting…';
|
|
362
|
+
|
|
363
|
+
const panel = document.getElementById('loginPanel');
|
|
364
|
+
const body = document.getElementById('loginPanelBody');
|
|
365
|
+
panel.classList.remove('visible');
|
|
366
|
+
body.innerHTML = `<div style="color:var(--text-muted);font-size:12px">Starting login process…</div>`;
|
|
367
|
+
panel.classList.add('visible');
|
|
368
|
+
|
|
369
|
+
try {
|
|
370
|
+
const res = await fetch('/api/config/accounts/login', {
|
|
371
|
+
method: 'POST', headers: {'Content-Type':'application/json'},
|
|
372
|
+
body: JSON.stringify({ name, path })
|
|
373
|
+
});
|
|
374
|
+
const data = await res.json();
|
|
375
|
+
|
|
376
|
+
if (data.alreadyLoggedIn) {
|
|
377
|
+
await saveAccount(name, path);
|
|
378
|
+
panel.classList.remove('visible');
|
|
379
|
+
showToast(`Account "${name}" added (already logged in)`);
|
|
380
|
+
clearAddForm();
|
|
381
|
+
} else if (data.url) {
|
|
382
|
+
pendingLogin = { name, path, sessionId: data.sessionId };
|
|
383
|
+
showLoginPanel(data.url, data.sessionId);
|
|
384
|
+
showToast('Authorization URL ready', 'info');
|
|
385
|
+
} else {
|
|
386
|
+
body.innerHTML = `<div style="color:var(--red);font-size:12px">${escHtml(data.error || 'Could not start login')}</div>`;
|
|
387
|
+
}
|
|
388
|
+
} catch (e) {
|
|
389
|
+
body.innerHTML = `<div style="color:var(--red);font-size:12px">${escHtml(e.message)}</div>`;
|
|
390
|
+
} finally {
|
|
391
|
+
btn.disabled = false; btn.textContent = '→ Login & Add';
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function showLoginPanel(url, sessionId) {
|
|
396
|
+
const body = document.getElementById('loginPanelBody');
|
|
397
|
+
body.innerHTML = `
|
|
398
|
+
<div class="login-panel-title">Step 1 — Open this URL in your browser</div>
|
|
399
|
+
<div class="login-url-row">
|
|
400
|
+
<span class="login-url" id="loginUrlText">${escHtml(url)}</span>
|
|
401
|
+
<button class="btn-copy" onclick="copyUrl('${escHtml(url)}')" title="Copy URL">⎘ Copy</button>
|
|
402
|
+
<a class="btn-open" href="${escHtml(url)}" target="_blank">Open ↗</a>
|
|
403
|
+
</div>
|
|
404
|
+
<div class="login-panel-title" style="margin-top:14px">Step 2 — Paste the code Anthropic gives you</div>
|
|
405
|
+
<div class="code-input-row">
|
|
406
|
+
<input id="authCodeInput" placeholder="Paste code here…" autocomplete="off" spellcheck="false" />
|
|
407
|
+
<button class="btn-verify" id="submitCodeBtn" onclick="submitCode()">Submit Code</button>
|
|
408
|
+
</div>
|
|
409
|
+
<div id="codeStatus" class="login-status-msg"></div>
|
|
410
|
+
<div style="margin-top:12px;font-size:11px;color:var(--text-muted)">
|
|
411
|
+
If the browser flow completes automatically (no code shown), just click
|
|
412
|
+
<button class="btn-verify" style="padding:4px 12px;font-size:11px" onclick="verifyLogin()">Verify & Save</button>
|
|
413
|
+
</div>
|
|
414
|
+
`;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
async function copyUrl(url) {
|
|
418
|
+
try {
|
|
419
|
+
await navigator.clipboard.writeText(url);
|
|
420
|
+
showToast('URL copied to clipboard', 'info');
|
|
421
|
+
} catch {
|
|
422
|
+
// Fallback: select the text
|
|
423
|
+
const el = document.getElementById('loginUrlText');
|
|
424
|
+
if (el) { const r = document.createRange(); r.selectNode(el); window.getSelection().removeAllRanges(); window.getSelection().addRange(r); }
|
|
425
|
+
showToast('Select + copy the URL above', 'info');
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
async function submitCode() {
|
|
430
|
+
if (!pendingLogin?.sessionId) return;
|
|
431
|
+
const code = document.getElementById('authCodeInput')?.value.trim();
|
|
432
|
+
if (!code) { showToast('Paste the code first', 'err'); return; }
|
|
433
|
+
|
|
434
|
+
const btn = document.getElementById('submitCodeBtn');
|
|
435
|
+
if (btn) btn.disabled = true;
|
|
436
|
+
document.getElementById('codeStatus').textContent = 'Submitting code…';
|
|
437
|
+
|
|
438
|
+
try {
|
|
439
|
+
const res = await fetch('/api/config/accounts/login/code', {
|
|
440
|
+
method: 'POST', headers: {'Content-Type':'application/json'},
|
|
441
|
+
body: JSON.stringify({ sessionId: pendingLogin.sessionId, code })
|
|
442
|
+
});
|
|
443
|
+
const d = await res.json();
|
|
444
|
+
if (!res.ok) throw new Error(d.error);
|
|
445
|
+
document.getElementById('codeStatus').textContent = 'Code submitted — verifying…';
|
|
446
|
+
// Give the process a moment to complete auth
|
|
447
|
+
setTimeout(() => verifyLogin(), 2000);
|
|
448
|
+
} catch (e) {
|
|
449
|
+
document.getElementById('codeStatus').textContent = `Error: ${e.message}`;
|
|
450
|
+
if (btn) btn.disabled = false;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
async function verifyLogin() {
|
|
455
|
+
if (!pendingLogin) return;
|
|
456
|
+
const { name, path } = pendingLogin;
|
|
457
|
+
|
|
458
|
+
try {
|
|
459
|
+
// Save account first (needed for status endpoint to resolve the path)
|
|
460
|
+
await saveAccount(name, path);
|
|
461
|
+
const res = await fetch(`/api/config/accounts/${encodeURIComponent(name)}/status`);
|
|
462
|
+
const d = await res.json();
|
|
463
|
+
if (d.loggedIn) {
|
|
464
|
+
showToast(`Account "${name}" added and verified ✓`);
|
|
465
|
+
pendingLogin = null;
|
|
466
|
+
document.getElementById('loginPanel').classList.remove('visible');
|
|
467
|
+
clearAddForm();
|
|
468
|
+
} else {
|
|
469
|
+
const status = document.getElementById('codeStatus');
|
|
470
|
+
if (status) status.textContent = 'Not authorized yet — finish the browser flow then try again.';
|
|
471
|
+
showToast('Not authorized yet', 'info');
|
|
472
|
+
}
|
|
473
|
+
} catch (e) {
|
|
474
|
+
showToast(e.message, 'err');
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function clearAddForm() {
|
|
479
|
+
document.getElementById('newAccName').value = '';
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
async function reloginAccount(name) {
|
|
483
|
+
const path = accounts[name];
|
|
484
|
+
if (!path) return;
|
|
485
|
+
const btn = event.target;
|
|
486
|
+
btn.disabled = true;
|
|
487
|
+
try {
|
|
488
|
+
const res = await fetch('/api/config/accounts/login', {
|
|
489
|
+
method: 'POST', headers: {'Content-Type':'application/json'},
|
|
490
|
+
body: JSON.stringify({ name, path })
|
|
491
|
+
});
|
|
492
|
+
const data = await res.json();
|
|
493
|
+
if (data.alreadyLoggedIn) {
|
|
494
|
+
showToast(`"${name}" is already logged in`);
|
|
495
|
+
checkStatus(name);
|
|
496
|
+
} else if (data.url) {
|
|
497
|
+
const w = window.open(data.url, '_blank');
|
|
498
|
+
if (!w || w.closed) {
|
|
499
|
+
showToast(`<a href="${data.url}" target="_blank" style="color:var(--accent);text-decoration:underline">Click here to authorize</a> (popup was blocked)`, 'info', true);
|
|
500
|
+
} else {
|
|
501
|
+
showToast('Opened auth URL — authorize then refresh status', 'info');
|
|
502
|
+
}
|
|
503
|
+
setTimeout(() => checkStatus(name), 8000);
|
|
504
|
+
} else {
|
|
505
|
+
showToast(data.error || 'Could not get login URL', 'err');
|
|
506
|
+
}
|
|
507
|
+
} finally {
|
|
508
|
+
btn.disabled = false;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
async function saveAccount(name, path) {
|
|
513
|
+
const res = await fetch('/api/config/accounts', {
|
|
514
|
+
method: 'POST', headers: {'Content-Type':'application/json'},
|
|
515
|
+
body: JSON.stringify({ name, path })
|
|
516
|
+
});
|
|
517
|
+
if (!res.ok) { const e = await res.json(); throw new Error(e.error); }
|
|
518
|
+
accounts[name] = path;
|
|
519
|
+
renderAccounts();
|
|
520
|
+
checkStatus(name);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// ── Service settings ───────────────────────────────────────────────
|
|
524
|
+
async function loadService() {
|
|
525
|
+
const res = await fetch('/api/config/service');
|
|
526
|
+
const s = await res.json();
|
|
527
|
+
document.getElementById('svcAgentsDir').value = s.personalAgentsDir || '';
|
|
528
|
+
document.getElementById('svcRegistryDir').value = s.personalRegistryDir || '';
|
|
529
|
+
document.getElementById('svcPort').value = s.webUIPort || '';
|
|
530
|
+
document.getElementById('svcLogLevel').value = s.logLevel || '';
|
|
531
|
+
// Deployment
|
|
532
|
+
const d = s.deployment || {};
|
|
533
|
+
document.getElementById('depProvider').value = d.provider || '';
|
|
534
|
+
document.getElementById('depToken').value = d.deployToken || '';
|
|
535
|
+
document.getElementById('depGithubOrg').value = d.githubOrg || '';
|
|
536
|
+
document.getElementById('depGithubToken').value = d.githubToken || '';
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
async function saveService() {
|
|
540
|
+
const personalAgentsDir = document.getElementById('svcAgentsDir').value.trim();
|
|
541
|
+
const personalRegistryDir = document.getElementById('svcRegistryDir').value.trim();
|
|
542
|
+
const webUIPort = document.getElementById('svcPort').value.trim();
|
|
543
|
+
const logLevel = document.getElementById('svcLogLevel').value.trim();
|
|
544
|
+
const res = await fetch('/api/config/service', {
|
|
545
|
+
method: 'PUT', headers: {'Content-Type':'application/json'},
|
|
546
|
+
body: JSON.stringify({ personalAgentsDir, personalRegistryDir, webUIPort: webUIPort ? Number(webUIPort) : undefined, logLevel })
|
|
547
|
+
});
|
|
548
|
+
const data = await res.json();
|
|
549
|
+
if (!res.ok) { showToast(data.error, 'err'); return; }
|
|
550
|
+
showToast(data.note || 'Saved');
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// ── Deployment settings ────────────────────────────────────────────
|
|
554
|
+
async function saveDeployment() {
|
|
555
|
+
const deployment = {
|
|
556
|
+
provider: document.getElementById('depProvider').value.trim(),
|
|
557
|
+
deployToken: document.getElementById('depToken').value,
|
|
558
|
+
githubOrg: document.getElementById('depGithubOrg').value.trim(),
|
|
559
|
+
githubToken: document.getElementById('depGithubToken').value,
|
|
560
|
+
};
|
|
561
|
+
const res = await fetch('/api/config/service', {
|
|
562
|
+
method: 'PUT', headers: {'Content-Type':'application/json'},
|
|
563
|
+
body: JSON.stringify({ deployment })
|
|
564
|
+
});
|
|
565
|
+
const data = await res.json();
|
|
566
|
+
if (!res.ok) { showToast(data.error, 'err'); return; }
|
|
567
|
+
showToast('Deployment settings saved');
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
function toggleReveal(inputId, labelId) {
|
|
571
|
+
const inp = document.getElementById(inputId);
|
|
572
|
+
const lbl = document.getElementById(labelId);
|
|
573
|
+
if (inp.type === 'password') { inp.type = 'text'; lbl.textContent = 'hide'; }
|
|
574
|
+
else { inp.type = 'password'; lbl.textContent = 'show'; }
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// ── Utils ──────────────────────────────────────────────────────────
|
|
578
|
+
function escHtml(s){ return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"') }
|
|
579
|
+
function escId(s){ return s.replace(/[^a-z0-9]/gi,'_') }
|
|
580
|
+
|
|
581
|
+
loadAccounts();
|
|
582
|
+
loadService();
|
|
583
|
+
|
|
584
|
+
// ── Status indicator install ───────────────────────────────────────
|
|
585
|
+
(function(){
|
|
586
|
+
const area = document.getElementById('indicatorInstallArea');
|
|
587
|
+
const isMac = navigator.platform.toUpperCase().includes('MAC');
|
|
588
|
+
const isWin = navigator.platform.toUpperCase().includes('WIN');
|
|
589
|
+
if (isMac) {
|
|
590
|
+
area.innerHTML = `
|
|
591
|
+
<div style="font-size:13px;line-height:1.6">
|
|
592
|
+
<strong>macOS — xbar menu bar plugin</strong>
|
|
593
|
+
<ol style="margin:8px 0;padding-left:20px;color:var(--text-dim)">
|
|
594
|
+
<li>Install xbar: <code style="background:var(--bg-card);padding:2px 6px;border-radius:4px">brew install --cask xbar</code></li>
|
|
595
|
+
<li>Click the button below to copy the plugin into place</li>
|
|
596
|
+
<li>Open xbar — a green dot with agent count appears in your menu bar</li>
|
|
597
|
+
</ol>
|
|
598
|
+
<button class="btn-save" onclick="installXbar()" id="xbarInstallBtn" style="margin-top:4px">Install xbar Plugin</button>
|
|
599
|
+
<span id="xbarStatus" style="margin-left:12px;font-size:12px;color:var(--text-dim)"></span>
|
|
600
|
+
</div>`;
|
|
601
|
+
} else if (isWin) {
|
|
602
|
+
area.innerHTML = `
|
|
603
|
+
<div style="font-size:13px;line-height:1.6">
|
|
604
|
+
<strong>Windows — System Tray indicator</strong>
|
|
605
|
+
<ol style="margin:8px 0;padding-left:20px;color:var(--text-dim)">
|
|
606
|
+
<li>The tray indicator script is at <code style="background:var(--bg-card);padding:2px 6px;border-radius:4px">scripts/tray-indicator.ps1</code></li>
|
|
607
|
+
<li>Run it: <code style="background:var(--bg-card);padding:2px 6px;border-radius:4px">powershell -WindowStyle Hidden -File scripts\\tray-indicator.ps1</code></li>
|
|
608
|
+
<li>A tray icon appears — right-click for Web UI, Restart, and Exit</li>
|
|
609
|
+
</ol>
|
|
610
|
+
<p style="color:var(--text-dim);font-size:11px;margin-top:8px">To auto-start: add the script to your Windows Startup folder or Task Scheduler.</p>
|
|
611
|
+
</div>`;
|
|
612
|
+
} else {
|
|
613
|
+
area.innerHTML = '<p style="font-size:12px;color:var(--text-dim)">Status indicator is available for macOS (xbar) and Windows (system tray).</p>';
|
|
614
|
+
}
|
|
615
|
+
})();
|
|
616
|
+
|
|
617
|
+
async function installXbar() {
|
|
618
|
+
const btn = document.getElementById('xbarInstallBtn');
|
|
619
|
+
const status = document.getElementById('xbarStatus');
|
|
620
|
+
btn.disabled = true; btn.textContent = 'Installing...';
|
|
621
|
+
try {
|
|
622
|
+
const res = await fetch('/api/install-xbar', { method: 'POST' });
|
|
623
|
+
const data = await res.json();
|
|
624
|
+
if (data.ok) {
|
|
625
|
+
status.textContent = 'Installed! Open xbar to see the status dot.';
|
|
626
|
+
status.style.color = '#22c55e';
|
|
627
|
+
btn.textContent = 'Installed';
|
|
628
|
+
} else {
|
|
629
|
+
status.textContent = data.error || 'Install failed';
|
|
630
|
+
status.style.color = '#f87171';
|
|
631
|
+
btn.textContent = 'Install xbar Plugin'; btn.disabled = false;
|
|
632
|
+
}
|
|
633
|
+
} catch(e) {
|
|
634
|
+
status.textContent = e.message; status.style.color = '#f87171';
|
|
635
|
+
btn.textContent = 'Install xbar Plugin'; btn.disabled = false;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
document.addEventListener('click', function(e){
|
|
639
|
+
const dd = document.getElementById('docsDropdown');
|
|
640
|
+
if(dd && !dd.contains(e.target)) document.getElementById('docsMenu')?.classList.remove('open');
|
|
641
|
+
});
|
|
642
|
+
</script>
|
|
643
|
+
<script>(function(){fetch("/api/config/service").then(function(r){return r.json()}).then(function(d){if(d.gymEnabled)document.querySelectorAll(".gym-tab-link").forEach(function(el){el.style.display=""});if(d.gymOnlyMode){var keep=["/gym","/org","/admin"];document.querySelectorAll(".tab-group .tab-btn").forEach(function(el){var h=el.getAttribute("href");if(h&&keep.indexOf(h)===-1&&!el.classList.contains("gym-tab-link"))el.style.display="none"});document.querySelectorAll(".topbar-right .gear-btn").forEach(function(el){var h=el.getAttribute("href");if(h&&["/marketplace","/monitor","/user-guide"].indexOf(h)!==-1)el.style.display="none"})}}).catch(function(){})})()</script>
|
|
644
|
+
</body>
|
|
645
|
+
</html>
|