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
package/src/config.ts
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { resolve, join } from "node:path";
|
|
4
|
+
import type { LogLevel } from "./logger.js";
|
|
5
|
+
|
|
6
|
+
export interface RouteMatch {
|
|
7
|
+
type: "chat_id" | "chat_guid" | "chat_identifier" | "channel_id" | "jid";
|
|
8
|
+
value: string | number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface RoutePermissions {
|
|
12
|
+
allowFrom: string[];
|
|
13
|
+
requireMention: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface RouteConfig {
|
|
17
|
+
channel: string;
|
|
18
|
+
match: RouteMatch;
|
|
19
|
+
permissions: RoutePermissions;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// ─── MCP Server definitions ──────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
export interface McpServerStdio {
|
|
25
|
+
type: "stdio";
|
|
26
|
+
command: string;
|
|
27
|
+
args?: string[];
|
|
28
|
+
env?: Record<string, string>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface McpServerHttp {
|
|
32
|
+
type: "http" | "sse";
|
|
33
|
+
url: string;
|
|
34
|
+
headers?: Record<string, string>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type McpServerConfig = McpServerStdio | McpServerHttp;
|
|
38
|
+
|
|
39
|
+
// ─── Cron job config ─────────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
export interface CronJobConfig {
|
|
42
|
+
schedule: string; // cron expression (e.g., "0 9 * * *")
|
|
43
|
+
message: string; // message to send to the agent
|
|
44
|
+
channel: string; // which channel to reply on
|
|
45
|
+
chatId: string; // which chat to reply in
|
|
46
|
+
enabled?: boolean; // default true — set false to pause
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ─── Goals config ───────────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
export interface GoalConfig {
|
|
52
|
+
id: string;
|
|
53
|
+
enabled: boolean;
|
|
54
|
+
description: string;
|
|
55
|
+
successCriteria?: string;
|
|
56
|
+
instructions?: string;
|
|
57
|
+
heartbeat: string; // cron expression
|
|
58
|
+
budget?: { maxDailyUsd: number };
|
|
59
|
+
reportTo?: string | string[]; // "channel:chatId" or array of them e.g. ["telegram:-5112439418", "slack:C0ALHTDD6JF"]
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ─── Agent config ────────────────────────────────────────────────────
|
|
63
|
+
|
|
64
|
+
export interface AgentConfig {
|
|
65
|
+
name: string;
|
|
66
|
+
description: string;
|
|
67
|
+
agentHome?: string; // agent's own folder (memory, skills, keys, storage)
|
|
68
|
+
workspace: string; // project/codebase the agent works on
|
|
69
|
+
claudeMd: string;
|
|
70
|
+
memoryDir: string;
|
|
71
|
+
skills?: string[]; // shared skills from ~/.claude/commands/
|
|
72
|
+
agentSkills?: string[]; // agent-specific skills from agent's skills/ folder
|
|
73
|
+
mcps?: string[];
|
|
74
|
+
prompts?: string[]; // prompt templates available to this agent
|
|
75
|
+
persistent?: boolean;
|
|
76
|
+
perSenderSessions?: boolean;
|
|
77
|
+
streaming?: boolean;
|
|
78
|
+
advancedMemory?: boolean;
|
|
79
|
+
org?: Array<{
|
|
80
|
+
organization: string;
|
|
81
|
+
function: string;
|
|
82
|
+
title: string;
|
|
83
|
+
reportsTo?: string;
|
|
84
|
+
}>;
|
|
85
|
+
autonomousCapable?: boolean;
|
|
86
|
+
autoCommit: boolean;
|
|
87
|
+
autoCommitBranch: string;
|
|
88
|
+
allowedTools: string[];
|
|
89
|
+
claudeAccount?: string; // which account this agent uses (key from service.claudeAccounts)
|
|
90
|
+
mentionAliases?: string[];
|
|
91
|
+
routes: RouteConfig[];
|
|
92
|
+
timeout?: number;
|
|
93
|
+
cron?: CronJobConfig[];
|
|
94
|
+
goals?: GoalConfig[];
|
|
95
|
+
wiki?: boolean; // Enable wiki learning — agent saves learned facts to learned.md
|
|
96
|
+
wikiSync?: {
|
|
97
|
+
enabled: boolean;
|
|
98
|
+
schedule: string; // cron expression (e.g., "0 0 * * *" = daily midnight)
|
|
99
|
+
};
|
|
100
|
+
subAgents?: string[] | "*"; // Group agent: list of agent IDs to delegate to, or "*" for all
|
|
101
|
+
platformAgent?: boolean; // DEPRECATED — use agentClass instead
|
|
102
|
+
agentClass?: "standard" | "platform" | "builder" | "gym"; // standard (default), platform (Lab creators), builder (app developer agents), gym (AI Gym agents)
|
|
103
|
+
executor?: string; // "claude" (default) or "ollama:modelname" (e.g., "ollama:gemma2")
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface ChannelConfig {
|
|
107
|
+
enabled: boolean;
|
|
108
|
+
driver: string;
|
|
109
|
+
config: Record<string, unknown>;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ─── Web UI config ───────────────────────────────────────────────────
|
|
113
|
+
|
|
114
|
+
export interface WebUIConfig {
|
|
115
|
+
enabled: boolean;
|
|
116
|
+
port: number;
|
|
117
|
+
webhookSecret?: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface ServiceConfig {
|
|
121
|
+
logLevel: LogLevel;
|
|
122
|
+
logFile?: string;
|
|
123
|
+
pairingCode?: string;
|
|
124
|
+
personalAgentsDir?: string; // Override path to PersonalAgents dir (default: ~/Desktop/MyAIforOne Drive/PersonalAgents)
|
|
125
|
+
personalRegistryDir?: string; // Override path to PersonalRegistry dir (default: ~/Desktop/MyAIforOne Drive/PersonalRegistry)
|
|
126
|
+
webUI?: WebUIConfig;
|
|
127
|
+
claudeAccounts?: Record<string, string>; // name → config dir path, e.g. {"main": "~/.claude"}
|
|
128
|
+
defaultClaudeAccount?: string; // account name to use when agent has no claudeAccount set (e.g. "main")
|
|
129
|
+
multiModelEnabled?: boolean; // false = claude only, true = enables alternative models
|
|
130
|
+
platformDefaultExecutor?: string; // "claude" (default) or "ollama:gemma2" etc.
|
|
131
|
+
ollamaBaseUrl?: string; // default: "http://localhost:11434"
|
|
132
|
+
providerKeys?: Record<string, string>; // provider API keys: { openai: "sk-...", xai: "xai-...", google: "AIza...", groq: "gsk_...", together: "...", mistral: "..." }
|
|
133
|
+
gymEnabled?: boolean; // false = gym hidden, true = gym active
|
|
134
|
+
aibriefingEnabled?: boolean; // false = no AI briefing feed, true = weekly AI news via web search
|
|
135
|
+
gymOnlyMode?: boolean;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface AppConfig {
|
|
139
|
+
service: ServiceConfig;
|
|
140
|
+
channels: Record<string, ChannelConfig>;
|
|
141
|
+
agents: Record<string, AgentConfig>;
|
|
142
|
+
mcps?: Record<string, McpServerConfig>;
|
|
143
|
+
defaultAgent: string | null;
|
|
144
|
+
defaultSkills?: string[]; // skills given to every agent automatically
|
|
145
|
+
defaultMcps?: string[]; // MCPs given to every agent automatically
|
|
146
|
+
defaultPrompts?: string[]; // prompt templates given to every agent automatically
|
|
147
|
+
promptTrigger?: string; // character used to invoke prompt templates (default: "!")
|
|
148
|
+
saas?: {
|
|
149
|
+
baseUrl: string;
|
|
150
|
+
apiKey: string;
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function loadConfig(configPath: string): AppConfig {
|
|
155
|
+
const fullPath = resolve(configPath);
|
|
156
|
+
const raw = readFileSync(fullPath, "utf-8");
|
|
157
|
+
const config = JSON.parse(raw) as AppConfig;
|
|
158
|
+
|
|
159
|
+
// Ensure required top-level keys exist (default to empty — app can start for setup)
|
|
160
|
+
if (!config.agents) config.agents = {};
|
|
161
|
+
if (!config.channels) config.channels = {};
|
|
162
|
+
|
|
163
|
+
// Normalize each agent's paths and ensure routes is always an array
|
|
164
|
+
const agentIds = Object.keys(config.agents);
|
|
165
|
+
for (const id of agentIds) {
|
|
166
|
+
const agent = config.agents[id];
|
|
167
|
+
// Routes are optional — agents without channel routes are still reachable via web UI
|
|
168
|
+
if (!agent.routes) agent.routes = [];
|
|
169
|
+
if (!agent.workspace) {
|
|
170
|
+
throw new Error(`Agent "${id}" must have a workspace path`);
|
|
171
|
+
}
|
|
172
|
+
if (!agent.claudeMd) {
|
|
173
|
+
throw new Error(`Agent "${id}" must have a claudeMd path`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Resolve ~ in paths (works on macOS and Windows)
|
|
177
|
+
const home = homedir();
|
|
178
|
+
const resolveTilde = (p: string) =>
|
|
179
|
+
p.startsWith("~") ? p.replace("~", home) : p;
|
|
180
|
+
agent.workspace = resolveTilde(agent.workspace);
|
|
181
|
+
if (agent.agentHome) {
|
|
182
|
+
agent.agentHome = resolveTilde(agent.agentHome);
|
|
183
|
+
// Auto-derive claudeMd and memoryDir from agentHome only if not explicitly set
|
|
184
|
+
if (!agent.claudeMd) {
|
|
185
|
+
agent.claudeMd = join(agent.agentHome, "CLAUDE.md");
|
|
186
|
+
}
|
|
187
|
+
if (!agent.memoryDir) {
|
|
188
|
+
agent.memoryDir = join(agent.agentHome, "memory");
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
agent.claudeMd = resolveTilde(agent.claudeMd);
|
|
192
|
+
agent.memoryDir = resolveTilde(agent.memoryDir);
|
|
193
|
+
// Derive agentHome from memoryDir if not set
|
|
194
|
+
if (!agent.agentHome) {
|
|
195
|
+
agent.agentHome = resolve(resolveTilde(agent.memoryDir), "..");
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Validate MCP references
|
|
199
|
+
if (agent.mcps && agent.mcps.length > 0) {
|
|
200
|
+
if (!config.mcps || Object.keys(config.mcps).length === 0) {
|
|
201
|
+
throw new Error(`Agent "${id}" references MCPs but no "mcps" registry is defined in config`);
|
|
202
|
+
}
|
|
203
|
+
for (const mcpName of agent.mcps) {
|
|
204
|
+
if (!config.mcps[mcpName]) {
|
|
205
|
+
throw new Error(`Agent "${id}" references MCP "${mcpName}" which is not defined in config.mcps`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Set defaults
|
|
211
|
+
agent.autoCommit = agent.autoCommit ?? false;
|
|
212
|
+
agent.autoCommitBranch = agent.autoCommitBranch ?? "main";
|
|
213
|
+
agent.allowedTools = agent.allowedTools ?? ["Read", "Edit", "Write", "Glob", "Grep", "Bash"];
|
|
214
|
+
agent.timeout = agent.timeout ?? 14_400_000;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Validate MCP definitions
|
|
218
|
+
if (config.mcps) {
|
|
219
|
+
for (const [mcpId, mcp] of Object.entries(config.mcps)) {
|
|
220
|
+
if (mcp.type === "stdio") {
|
|
221
|
+
if (!mcp.command) throw new Error(`MCP "${mcpId}" (stdio) must have a "command" field`);
|
|
222
|
+
} else if (mcp.type === "http" || mcp.type === "sse") {
|
|
223
|
+
if (!(mcp as McpServerHttp).url) throw new Error(`MCP "${mcpId}" (${mcp.type}) must have a "url" field`);
|
|
224
|
+
} else {
|
|
225
|
+
throw new Error(`MCP "${mcpId}" has unknown type "${(mcp as any).type}" — must be "stdio", "http", or "sse"`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Defaults
|
|
231
|
+
config.service = config.service ?? { logLevel: "info" };
|
|
232
|
+
config.service.logLevel = config.service.logLevel ?? "info";
|
|
233
|
+
config.defaultAgent = config.defaultAgent ?? null;
|
|
234
|
+
|
|
235
|
+
const home = homedir();
|
|
236
|
+
const driveRoot = resolve(home, "Desktop", "MyAIforOne Drive");
|
|
237
|
+
|
|
238
|
+
// Resolve personalAgentsDir (expand ~)
|
|
239
|
+
if (config.service.personalAgentsDir) {
|
|
240
|
+
config.service.personalAgentsDir = config.service.personalAgentsDir.startsWith("~")
|
|
241
|
+
? config.service.personalAgentsDir.replace("~", home)
|
|
242
|
+
: config.service.personalAgentsDir;
|
|
243
|
+
}
|
|
244
|
+
_personalAgentsDir = config.service.personalAgentsDir || resolve(driveRoot, "PersonalAgents");
|
|
245
|
+
|
|
246
|
+
// Resolve personalRegistryDir (expand ~)
|
|
247
|
+
if (config.service.personalRegistryDir) {
|
|
248
|
+
config.service.personalRegistryDir = config.service.personalRegistryDir.startsWith("~")
|
|
249
|
+
? config.service.personalRegistryDir.replace("~", home)
|
|
250
|
+
: config.service.personalRegistryDir;
|
|
251
|
+
}
|
|
252
|
+
_personalRegistryDir = config.service.personalRegistryDir || resolve(driveRoot, "PersonalRegistry");
|
|
253
|
+
|
|
254
|
+
// Inject default account hint into claudeAccounts map so executor can pick it up
|
|
255
|
+
if (config.service.defaultClaudeAccount && config.service.claudeAccounts) {
|
|
256
|
+
(config.service.claudeAccounts as any)._defaultAccount = config.service.defaultClaudeAccount;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return config;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** Resolved PersonalAgents directory — set during config loading, used by executor and keystore */
|
|
263
|
+
let _personalAgentsDir: string | null = null;
|
|
264
|
+
/** Resolved PersonalRegistry directory — set during config loading, used by web-ui */
|
|
265
|
+
let _personalRegistryDir: string | null = null;
|
|
266
|
+
|
|
267
|
+
/** Resolve the PersonalAgents directory from config, falling back to ~/Desktop/MyAIforOne Drive/PersonalAgents */
|
|
268
|
+
export function getPersonalAgentsDir(config?: AppConfig): string {
|
|
269
|
+
if (_personalAgentsDir) return _personalAgentsDir;
|
|
270
|
+
const driveRoot = resolve(homedir(), "Desktop", "MyAIforOne Drive");
|
|
271
|
+
if (config) return config.service.personalAgentsDir || resolve(driveRoot, "PersonalAgents");
|
|
272
|
+
return resolve(driveRoot, "PersonalAgents");
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/** Resolve the PersonalRegistry directory from config, falling back to ~/Desktop/MyAIforOne Drive/PersonalRegistry */
|
|
276
|
+
export function getPersonalRegistryDir(config?: AppConfig): string {
|
|
277
|
+
if (_personalRegistryDir) return _personalRegistryDir;
|
|
278
|
+
const driveRoot = resolve(homedir(), "Desktop", "MyAIforOne Drive");
|
|
279
|
+
if (config) return config.service.personalRegistryDir || resolve(driveRoot, "PersonalRegistry");
|
|
280
|
+
return resolve(driveRoot, "PersonalRegistry");
|
|
281
|
+
}
|
package/src/cron.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import cron from "node-cron";
|
|
2
|
+
import type { AppConfig, CronJobConfig } from "./config.js";
|
|
3
|
+
import { log } from "./logger.js";
|
|
4
|
+
|
|
5
|
+
interface CronHandler {
|
|
6
|
+
(agentId: string, message: string, channel: string, chatId: string): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const activeTasks: cron.ScheduledTask[] = [];
|
|
10
|
+
|
|
11
|
+
export function startCronJobs(config: AppConfig, handler: CronHandler): void {
|
|
12
|
+
for (const [agentId, agent] of Object.entries(config.agents)) {
|
|
13
|
+
if (!agent.cron?.length) continue;
|
|
14
|
+
|
|
15
|
+
for (const job of agent.cron) {
|
|
16
|
+
if (job.enabled === false) continue;
|
|
17
|
+
|
|
18
|
+
if (!cron.validate(job.schedule)) {
|
|
19
|
+
log.error(`Invalid cron schedule for ${agentId}: "${job.schedule}"`);
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const task = cron.schedule(job.schedule, async () => {
|
|
24
|
+
log.info(`Cron fired for ${agentId}: "${job.message.slice(0, 60)}"`);
|
|
25
|
+
try {
|
|
26
|
+
await handler(agentId, job.message, job.channel, job.chatId);
|
|
27
|
+
} catch (err) {
|
|
28
|
+
log.error(`Cron job failed for ${agentId}: ${err}`);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
activeTasks.push(task);
|
|
33
|
+
log.info(`Cron scheduled for ${agentId}: "${job.schedule}" → "${job.message.slice(0, 60)}"`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function stopCronJobs(): void {
|
|
39
|
+
for (const task of activeTasks) {
|
|
40
|
+
task.stop();
|
|
41
|
+
}
|
|
42
|
+
activeTasks.length = 0;
|
|
43
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Decrypt all MCP key .env.enc files back to .env.
|
|
4
|
+
* Usage: npm run decrypt-keys
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { resolve, dirname, join } from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { readdirSync, existsSync } from "node:fs";
|
|
10
|
+
import { createInterface } from "node:readline";
|
|
11
|
+
import { decryptDir } from "./keystore.js";
|
|
12
|
+
|
|
13
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const baseDir = resolve(__dirname, "..");
|
|
15
|
+
|
|
16
|
+
async function main() {
|
|
17
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
18
|
+
const ask = (q: string): Promise<string> => new Promise(r => rl.question(q, r));
|
|
19
|
+
|
|
20
|
+
const password = await ask("Master password: ");
|
|
21
|
+
if (!password) {
|
|
22
|
+
console.log("No password provided. Aborting.");
|
|
23
|
+
rl.close();
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let total = 0;
|
|
28
|
+
|
|
29
|
+
// Decrypt shared keys
|
|
30
|
+
const sharedDir = join(baseDir, "data", "mcp-keys");
|
|
31
|
+
if (existsSync(sharedDir)) {
|
|
32
|
+
const count = decryptDir(sharedDir, password);
|
|
33
|
+
total += count;
|
|
34
|
+
console.log(`Shared keys: ${count} files decrypted`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Decrypt agent-level keys
|
|
38
|
+
const personalBase = join(process.env.HOME || process.env.USERPROFILE || "", "Desktop", "MyAIforOne Drive", "PersonalAgents");
|
|
39
|
+
if (existsSync(personalBase)) {
|
|
40
|
+
const walkDirs = (dir: string) => {
|
|
41
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
42
|
+
if (entry.isDirectory()) {
|
|
43
|
+
const mcpKeysDir = join(dir, entry.name, "mcp-keys");
|
|
44
|
+
if (existsSync(mcpKeysDir)) {
|
|
45
|
+
const count = decryptDir(mcpKeysDir, password);
|
|
46
|
+
total += count;
|
|
47
|
+
if (count > 0) console.log(`${entry.name}: ${count} files decrypted`);
|
|
48
|
+
}
|
|
49
|
+
walkDirs(join(dir, entry.name));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
walkDirs(personalBase);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
console.log(`\nDone. ${total} key files decrypted.`);
|
|
57
|
+
rl.close();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Encrypt all MCP key .env files.
|
|
4
|
+
* Usage: npm run encrypt-keys
|
|
5
|
+
* Prompts for master password, encrypts all .env → .env.enc
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { resolve, dirname, join } from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
import { readdirSync, existsSync } from "node:fs";
|
|
11
|
+
import { createInterface } from "node:readline";
|
|
12
|
+
import { encryptDir } from "./keystore.js";
|
|
13
|
+
|
|
14
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const baseDir = resolve(__dirname, "..");
|
|
16
|
+
|
|
17
|
+
async function main() {
|
|
18
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
19
|
+
const ask = (q: string): Promise<string> => new Promise(r => rl.question(q, r));
|
|
20
|
+
|
|
21
|
+
const password = await ask("Master password: ");
|
|
22
|
+
if (!password) {
|
|
23
|
+
console.log("No password provided. Aborting.");
|
|
24
|
+
rl.close();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const confirm = await ask("Confirm password: ");
|
|
29
|
+
if (password !== confirm) {
|
|
30
|
+
console.log("Passwords don't match. Aborting.");
|
|
31
|
+
rl.close();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let total = 0;
|
|
36
|
+
|
|
37
|
+
// Encrypt shared keys
|
|
38
|
+
const sharedDir = join(baseDir, "data", "mcp-keys");
|
|
39
|
+
if (existsSync(sharedDir)) {
|
|
40
|
+
const count = encryptDir(sharedDir, password);
|
|
41
|
+
total += count;
|
|
42
|
+
console.log(`Shared keys: ${count} files encrypted`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Encrypt agent-level keys
|
|
46
|
+
const personalBase = join(process.env.HOME || process.env.USERPROFILE || "", "Desktop", "MyAIforOne Drive", "PersonalAgents");
|
|
47
|
+
if (existsSync(personalBase)) {
|
|
48
|
+
const walkDirs = (dir: string) => {
|
|
49
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
50
|
+
if (entry.isDirectory()) {
|
|
51
|
+
const mcpKeysDir = join(dir, entry.name, "mcp-keys");
|
|
52
|
+
if (existsSync(mcpKeysDir)) {
|
|
53
|
+
const count = encryptDir(mcpKeysDir, password);
|
|
54
|
+
total += count;
|
|
55
|
+
if (count > 0) console.log(`${entry.name}: ${count} files encrypted`);
|
|
56
|
+
}
|
|
57
|
+
// Recurse into org folders
|
|
58
|
+
walkDirs(join(dir, entry.name));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
walkDirs(personalBase);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.log(`\nDone. ${total} key files encrypted.`);
|
|
66
|
+
console.log("Original .env files replaced with stubs. Encrypted data in .env.enc files.");
|
|
67
|
+
rl.close();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
main().catch(console.error);
|