agor-live 0.3.7
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/LICENSE +94 -0
- package/README.md +163 -0
- package/bin/agor-daemon.js +20 -0
- package/bin/agor.js +14 -0
- package/dist/cli/base-command.d.ts +29 -0
- package/dist/cli/base-command.js +41 -0
- package/dist/cli/commands/board/add-session.d.ts +15 -0
- package/dist/cli/commands/board/add-session.js +102 -0
- package/dist/cli/commands/board/list.d.ts +14 -0
- package/dist/cli/commands/board/list.js +74 -0
- package/dist/cli/commands/config/clear.d.ts +13 -0
- package/dist/cli/commands/config/clear.js +21 -0
- package/dist/cli/commands/config/get.d.ts +13 -0
- package/dist/cli/commands/config/get.js +41 -0
- package/dist/cli/commands/config/index.d.ts +13 -0
- package/dist/cli/commands/config/index.js +118 -0
- package/dist/cli/commands/config/set.d.ts +14 -0
- package/dist/cli/commands/config/set.js +50 -0
- package/dist/cli/commands/config/unset.d.ts +13 -0
- package/dist/cli/commands/config/unset.js +35 -0
- package/dist/cli/commands/daemon/index.d.ts +13 -0
- package/dist/cli/commands/daemon/index.js +65 -0
- package/dist/cli/commands/daemon/logs.d.ts +13 -0
- package/dist/cli/commands/daemon/logs.js +78 -0
- package/dist/cli/commands/daemon/restart.d.ts +13 -0
- package/dist/cli/commands/daemon/restart.js +177 -0
- package/dist/cli/commands/daemon/start.d.ts +13 -0
- package/dist/cli/commands/daemon/start.js +193 -0
- package/dist/cli/commands/daemon/status.d.ts +13 -0
- package/dist/cli/commands/daemon/status.js +93 -0
- package/dist/cli/commands/daemon/stop.d.ts +13 -0
- package/dist/cli/commands/daemon/stop.js +108 -0
- package/dist/cli/commands/init.d.ts +44 -0
- package/dist/cli/commands/init.js +459 -0
- package/dist/cli/commands/mcp/add.d.ts +26 -0
- package/dist/cli/commands/mcp/add.js +162 -0
- package/dist/cli/commands/mcp/list.d.ts +16 -0
- package/dist/cli/commands/mcp/list.js +89 -0
- package/dist/cli/commands/mcp/remove.d.ts +17 -0
- package/dist/cli/commands/mcp/remove.js +86 -0
- package/dist/cli/commands/mcp/show.d.ts +14 -0
- package/dist/cli/commands/mcp/show.js +131 -0
- package/dist/cli/commands/repo/add.d.ts +16 -0
- package/dist/cli/commands/repo/add.js +105 -0
- package/dist/cli/commands/repo/list.d.ts +17 -0
- package/dist/cli/commands/repo/list.js +99 -0
- package/dist/cli/commands/repo/rm.d.ts +17 -0
- package/dist/cli/commands/repo/rm.js +126 -0
- package/dist/cli/commands/repo/worktree/add.d.ts +21 -0
- package/dist/cli/commands/repo/worktree/add.js +145 -0
- package/dist/cli/commands/repo/worktree/list.d.ts +21 -0
- package/dist/cli/commands/repo/worktree/list.js +136 -0
- package/dist/cli/commands/session/list.d.ts +30 -0
- package/dist/cli/commands/session/list.js +204 -0
- package/dist/cli/commands/session/load-claude.d.ts +16 -0
- package/dist/cli/commands/session/load-claude.js +211 -0
- package/dist/cli/commands/user/create-admin.d.ts +13 -0
- package/dist/cli/commands/user/create-admin.js +65 -0
- package/dist/cli/commands/user/create.d.ts +16 -0
- package/dist/cli/commands/user/create.js +126 -0
- package/dist/cli/commands/user/delete.d.ts +16 -0
- package/dist/cli/commands/user/delete.js +77 -0
- package/dist/cli/commands/user/list.d.ts +13 -0
- package/dist/cli/commands/user/list.js +78 -0
- package/dist/cli/commands/user/update.d.ts +19 -0
- package/dist/cli/commands/user/update.js +149 -0
- package/dist/cli/hooks/command-not-found.d.ts +9 -0
- package/dist/cli/hooks/command-not-found.js +14 -0
- package/dist/cli/lib/banner.d.ts +25 -0
- package/dist/cli/lib/banner.js +25 -0
- package/dist/cli/lib/context.d.ts +27 -0
- package/dist/cli/lib/context.js +32 -0
- package/dist/cli/lib/daemon-manager.d.ts +48 -0
- package/dist/cli/lib/daemon-manager.js +109 -0
- package/dist/cli/lib/help.d.ts +13 -0
- package/dist/cli/lib/help.js +46 -0
- package/dist/core/agentic-tool-B_gFNpk5.d.ts +33 -0
- package/dist/core/agentic-tool-DsyX8diw.d.cts +33 -0
- package/dist/core/api/index.cjs +98 -0
- package/dist/core/api/index.d.cts +174 -0
- package/dist/core/api/index.d.ts +174 -0
- package/dist/core/api/index.js +62 -0
- package/dist/core/board-comment-BUm0fpmD.d.cts +134 -0
- package/dist/core/board-comment-gC_-twPx.d.ts +134 -0
- package/dist/core/claude/index.cjs +673 -0
- package/dist/core/claude/index.d.cts +124 -0
- package/dist/core/claude/index.d.ts +124 -0
- package/dist/core/claude/index.js +629 -0
- package/dist/core/config/browser.cjs +165 -0
- package/dist/core/config/browser.d.cts +289 -0
- package/dist/core/config/browser.d.ts +289 -0
- package/dist/core/config/browser.js +131 -0
- package/dist/core/config/index.cjs +518 -0
- package/dist/core/config/index.d.cts +246 -0
- package/dist/core/config/index.d.ts +246 -0
- package/dist/core/config/index.js +451 -0
- package/dist/core/db/index.cjs +3726 -0
- package/dist/core/db/index.d.cts +631 -0
- package/dist/core/db/index.d.ts +631 -0
- package/dist/core/db/index.js +3649 -0
- package/dist/core/dist/agentic-tool-B_gFNpk5.d.ts +33 -0
- package/dist/core/dist/agentic-tool-DsyX8diw.d.cts +33 -0
- package/dist/core/dist/api/index.cjs +98 -0
- package/dist/core/dist/api/index.d.cts +174 -0
- package/dist/core/dist/api/index.d.ts +174 -0
- package/dist/core/dist/api/index.js +62 -0
- package/dist/core/dist/board-comment-BUm0fpmD.d.cts +134 -0
- package/dist/core/dist/board-comment-gC_-twPx.d.ts +134 -0
- package/dist/core/dist/claude/index.cjs +673 -0
- package/dist/core/dist/claude/index.d.cts +124 -0
- package/dist/core/dist/claude/index.d.ts +124 -0
- package/dist/core/dist/claude/index.js +629 -0
- package/dist/core/dist/config/browser.cjs +165 -0
- package/dist/core/dist/config/browser.d.cts +289 -0
- package/dist/core/dist/config/browser.d.ts +289 -0
- package/dist/core/dist/config/browser.js +131 -0
- package/dist/core/dist/config/index.cjs +518 -0
- package/dist/core/dist/config/index.d.cts +246 -0
- package/dist/core/dist/config/index.d.ts +246 -0
- package/dist/core/dist/config/index.js +451 -0
- package/dist/core/dist/db/index.cjs +3726 -0
- package/dist/core/dist/db/index.d.cts +631 -0
- package/dist/core/dist/db/index.d.ts +631 -0
- package/dist/core/dist/db/index.js +3649 -0
- package/dist/core/dist/environment/variable-resolver.cjs +92 -0
- package/dist/core/dist/environment/variable-resolver.d.cts +52 -0
- package/dist/core/dist/environment/variable-resolver.d.ts +52 -0
- package/dist/core/dist/environment/variable-resolver.js +53 -0
- package/dist/core/dist/feathers/index.cjs +66 -0
- package/dist/core/dist/feathers/index.d.cts +7 -0
- package/dist/core/dist/feathers/index.d.ts +7 -0
- package/dist/core/dist/feathers/index.js +25 -0
- package/dist/core/dist/feathers-BzHEPnpl.d.cts +228 -0
- package/dist/core/dist/feathers-BzHEPnpl.d.ts +228 -0
- package/dist/core/dist/git/index.cjs +302 -0
- package/dist/core/dist/git/index.d.cts +137 -0
- package/dist/core/dist/git/index.d.ts +137 -0
- package/dist/core/dist/git/index.js +260 -0
- package/dist/core/dist/id-DMqyogFB.d.cts +131 -0
- package/dist/core/dist/id-DMqyogFB.d.ts +131 -0
- package/dist/core/dist/index.cjs +4653 -0
- package/dist/core/dist/index.d.cts +23 -0
- package/dist/core/dist/index.d.ts +23 -0
- package/dist/core/dist/index.js +4509 -0
- package/dist/core/dist/message-BoxZISHg.d.cts +120 -0
- package/dist/core/dist/message-DvBzHu7V.d.ts +120 -0
- package/dist/core/dist/permissions/index.cjs +112 -0
- package/dist/core/dist/permissions/index.d.cts +81 -0
- package/dist/core/dist/permissions/index.d.ts +81 -0
- package/dist/core/dist/permissions/index.js +85 -0
- package/dist/core/dist/repo-3CUrCRbq.d.cts +405 -0
- package/dist/core/dist/repo-CnvJ0B6-.d.ts +405 -0
- package/dist/core/dist/session-BPjJlVdZ.d.cts +429 -0
- package/dist/core/dist/session-wAzjHatv.d.ts +429 -0
- package/dist/core/dist/task-BIEgT1DK.d.cts +163 -0
- package/dist/core/dist/task-DuIfiUbW.d.ts +163 -0
- package/dist/core/dist/templates/handlebars-helpers.cjs +156 -0
- package/dist/core/dist/templates/handlebars-helpers.d.cts +45 -0
- package/dist/core/dist/templates/handlebars-helpers.d.ts +45 -0
- package/dist/core/dist/templates/handlebars-helpers.js +119 -0
- package/dist/core/dist/tools/claude/models.cjs +70 -0
- package/dist/core/dist/tools/claude/models.d.cts +27 -0
- package/dist/core/dist/tools/claude/models.d.ts +27 -0
- package/dist/core/dist/tools/claude/models.js +44 -0
- package/dist/core/dist/tools/index.cjs +3367 -0
- package/dist/core/dist/tools/index.d.cts +967 -0
- package/dist/core/dist/tools/index.d.ts +967 -0
- package/dist/core/dist/tools/index.js +3314 -0
- package/dist/core/dist/tools/models.cjs +119 -0
- package/dist/core/dist/tools/models.d.cts +47 -0
- package/dist/core/dist/tools/models.d.ts +47 -0
- package/dist/core/dist/tools/models.js +86 -0
- package/dist/core/dist/types/index.cjs +152 -0
- package/dist/core/dist/types/index.d.cts +214 -0
- package/dist/core/dist/types/index.d.ts +214 -0
- package/dist/core/dist/types/index.js +112 -0
- package/dist/core/dist/user-BmL3kFol.d.ts +50 -0
- package/dist/core/dist/user-eUuKj7yM.d.cts +50 -0
- package/dist/core/dist/utils/pricing.cjs +102 -0
- package/dist/core/dist/utils/pricing.d.cts +43 -0
- package/dist/core/dist/utils/pricing.d.ts +43 -0
- package/dist/core/dist/utils/pricing.js +75 -0
- package/dist/core/dist/worktrees-BzIxB1U6.d.cts +2745 -0
- package/dist/core/dist/worktrees-CYem1ya2.d.ts +2745 -0
- package/dist/core/environment/variable-resolver.cjs +92 -0
- package/dist/core/environment/variable-resolver.d.cts +52 -0
- package/dist/core/environment/variable-resolver.d.ts +52 -0
- package/dist/core/environment/variable-resolver.js +53 -0
- package/dist/core/feathers/index.cjs +66 -0
- package/dist/core/feathers/index.d.cts +7 -0
- package/dist/core/feathers/index.d.ts +7 -0
- package/dist/core/feathers/index.js +25 -0
- package/dist/core/feathers-BzHEPnpl.d.cts +228 -0
- package/dist/core/feathers-BzHEPnpl.d.ts +228 -0
- package/dist/core/git/index.cjs +302 -0
- package/dist/core/git/index.d.cts +137 -0
- package/dist/core/git/index.d.ts +137 -0
- package/dist/core/git/index.js +260 -0
- package/dist/core/id-DMqyogFB.d.cts +131 -0
- package/dist/core/id-DMqyogFB.d.ts +131 -0
- package/dist/core/index.cjs +4653 -0
- package/dist/core/index.d.cts +23 -0
- package/dist/core/index.d.ts +23 -0
- package/dist/core/index.js +4509 -0
- package/dist/core/message-BoxZISHg.d.cts +120 -0
- package/dist/core/message-DvBzHu7V.d.ts +120 -0
- package/dist/core/package.json +133 -0
- package/dist/core/permissions/index.cjs +112 -0
- package/dist/core/permissions/index.d.cts +81 -0
- package/dist/core/permissions/index.d.ts +81 -0
- package/dist/core/permissions/index.js +85 -0
- package/dist/core/repo-3CUrCRbq.d.cts +405 -0
- package/dist/core/repo-CnvJ0B6-.d.ts +405 -0
- package/dist/core/session-BPjJlVdZ.d.cts +429 -0
- package/dist/core/session-wAzjHatv.d.ts +429 -0
- package/dist/core/task-BIEgT1DK.d.cts +163 -0
- package/dist/core/task-DuIfiUbW.d.ts +163 -0
- package/dist/core/templates/handlebars-helpers.cjs +156 -0
- package/dist/core/templates/handlebars-helpers.d.cts +45 -0
- package/dist/core/templates/handlebars-helpers.d.ts +45 -0
- package/dist/core/templates/handlebars-helpers.js +119 -0
- package/dist/core/tools/claude/models.cjs +70 -0
- package/dist/core/tools/claude/models.d.cts +27 -0
- package/dist/core/tools/claude/models.d.ts +27 -0
- package/dist/core/tools/claude/models.js +44 -0
- package/dist/core/tools/index.cjs +3367 -0
- package/dist/core/tools/index.d.cts +967 -0
- package/dist/core/tools/index.d.ts +967 -0
- package/dist/core/tools/index.js +3314 -0
- package/dist/core/tools/models.cjs +119 -0
- package/dist/core/tools/models.d.cts +47 -0
- package/dist/core/tools/models.d.ts +47 -0
- package/dist/core/tools/models.js +86 -0
- package/dist/core/types/index.cjs +152 -0
- package/dist/core/types/index.d.cts +214 -0
- package/dist/core/types/index.d.ts +214 -0
- package/dist/core/types/index.js +112 -0
- package/dist/core/user-BmL3kFol.d.ts +50 -0
- package/dist/core/user-eUuKj7yM.d.cts +50 -0
- package/dist/core/utils/pricing.cjs +102 -0
- package/dist/core/utils/pricing.d.cts +43 -0
- package/dist/core/utils/pricing.d.ts +43 -0
- package/dist/core/utils/pricing.js +75 -0
- package/dist/core/worktrees-BzIxB1U6.d.cts +2745 -0
- package/dist/core/worktrees-CYem1ya2.d.ts +2745 -0
- package/dist/daemon/adapters/drizzle.d.ts +114 -0
- package/dist/daemon/adapters/drizzle.js +219 -0
- package/dist/daemon/declarations.d.ts +101 -0
- package/dist/daemon/declarations.js +0 -0
- package/dist/daemon/index.d.ts +2 -0
- package/dist/daemon/index.js +4093 -0
- package/dist/daemon/mcp/routes.d.ts +15 -0
- package/dist/daemon/mcp/routes.js +641 -0
- package/dist/daemon/mcp/tokens.d.ts +50 -0
- package/dist/daemon/mcp/tokens.js +85 -0
- package/dist/daemon/services/board-comments.d.ts +97 -0
- package/dist/daemon/services/board-comments.js +326 -0
- package/dist/daemon/services/board-objects.d.ts +71 -0
- package/dist/daemon/services/board-objects.js +117 -0
- package/dist/daemon/services/boards.d.ts +64 -0
- package/dist/daemon/services/boards.js +286 -0
- package/dist/daemon/services/config.d.ts +35 -0
- package/dist/daemon/services/config.js +68 -0
- package/dist/daemon/services/context.d.ts +55 -0
- package/dist/daemon/services/context.js +113 -0
- package/dist/daemon/services/health-monitor.d.ts +58 -0
- package/dist/daemon/services/health-monitor.js +158 -0
- package/dist/daemon/services/mcp-servers.d.ts +42 -0
- package/dist/daemon/services/mcp-servers.js +275 -0
- package/dist/daemon/services/messages.d.ts +49 -0
- package/dist/daemon/services/messages.js +269 -0
- package/dist/daemon/services/repos.d.ts +61 -0
- package/dist/daemon/services/repos.js +350 -0
- package/dist/daemon/services/session-mcp-servers.d.ts +56 -0
- package/dist/daemon/services/session-mcp-servers.js +51 -0
- package/dist/daemon/services/sessions.d.ts +64 -0
- package/dist/daemon/services/sessions.js +398 -0
- package/dist/daemon/services/tasks.d.ts +55 -0
- package/dist/daemon/services/tasks.js +318 -0
- package/dist/daemon/services/terminals.d.ts +75 -0
- package/dist/daemon/services/terminals.js +110 -0
- package/dist/daemon/services/users.d.ts +98 -0
- package/dist/daemon/services/users.js +177 -0
- package/dist/daemon/services/worktrees.d.ts +98 -0
- package/dist/daemon/services/worktrees.js +719 -0
- package/dist/daemon/strategies/anonymous.d.ts +20 -0
- package/dist/daemon/strategies/anonymous.js +32 -0
- package/dist/ui/assets/cc-CYmbalCD.png +0 -0
- package/dist/ui/assets/codex-4sLD1mVS.png +0 -0
- package/dist/ui/assets/cursor-BUy5pFVL.png +0 -0
- package/dist/ui/assets/gemini-ajOb7iAl.png +0 -0
- package/dist/ui/assets/index-Dc4ELxry.css +32 -0
- package/dist/ui/assets/index-KfIu8v4V.js +578 -0
- package/dist/ui/favicon.png +0 -0
- package/dist/ui/index.html +26 -0
- package/dist/ui/vite.svg +1 -0
- package/package.json +90 -0
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
// src/commands/init.ts
|
|
2
|
+
import { access, constants, mkdir, readdir, rm } from "fs/promises";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
import { setConfigValue } from "@agor/core/config";
|
|
6
|
+
import { createDatabase, createUser, initializeDatabase, seedInitialData } from "@agor/core/db";
|
|
7
|
+
import { Command, Flags } from "@oclif/core";
|
|
8
|
+
import chalk from "chalk";
|
|
9
|
+
import inquirer from "inquirer";
|
|
10
|
+
var Init = class _Init extends Command {
|
|
11
|
+
static description = "Initialize Agor environment (creates ~/.agor/ and database)";
|
|
12
|
+
static examples = [
|
|
13
|
+
"<%= config.bin %> <%= command.id %>",
|
|
14
|
+
"<%= config.bin %> <%= command.id %> --local"
|
|
15
|
+
];
|
|
16
|
+
static flags = {
|
|
17
|
+
local: Flags.boolean({
|
|
18
|
+
char: "l",
|
|
19
|
+
description: "Initialize local .agor/ directory in current working directory",
|
|
20
|
+
default: false
|
|
21
|
+
}),
|
|
22
|
+
force: Flags.boolean({
|
|
23
|
+
char: "f",
|
|
24
|
+
description: "Force re-initialization without prompts (deletes database, repos, and worktrees)",
|
|
25
|
+
default: false
|
|
26
|
+
})
|
|
27
|
+
};
|
|
28
|
+
async pathExists(path) {
|
|
29
|
+
try {
|
|
30
|
+
await access(path, constants.F_OK);
|
|
31
|
+
return true;
|
|
32
|
+
} catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
expandHome(path) {
|
|
37
|
+
if (path.startsWith("~/")) {
|
|
38
|
+
return join(homedir(), path.slice(2));
|
|
39
|
+
}
|
|
40
|
+
return path;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Count rows in database tables for display
|
|
44
|
+
*/
|
|
45
|
+
async getDbStats(dbPath) {
|
|
46
|
+
try {
|
|
47
|
+
const { createDatabase: createDatabase2, sessions, tasks, messages, repos } = await import("@agor/core/db");
|
|
48
|
+
const db = createDatabase2({ url: `file:${dbPath}` });
|
|
49
|
+
const sessionRows = await db.select({ id: sessions.session_id }).from(sessions).all();
|
|
50
|
+
const taskRows = await db.select({ id: tasks.task_id }).from(tasks).all();
|
|
51
|
+
const messageRows = await db.select({ id: messages.message_id }).from(messages).all();
|
|
52
|
+
const repoRows = await db.select({ id: repos.repo_id }).from(repos).all();
|
|
53
|
+
return {
|
|
54
|
+
sessions: sessionRows.length,
|
|
55
|
+
tasks: taskRows.length,
|
|
56
|
+
messages: messageRows.length,
|
|
57
|
+
repos: repoRows.length
|
|
58
|
+
};
|
|
59
|
+
} catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* List directories in a path (repos, worktrees)
|
|
65
|
+
*/
|
|
66
|
+
async listDirs(path) {
|
|
67
|
+
try {
|
|
68
|
+
const entries = await readdir(path, { withFileTypes: true });
|
|
69
|
+
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
70
|
+
} catch {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Detect if running in GitHub Codespaces
|
|
76
|
+
*/
|
|
77
|
+
isCodespaces() {
|
|
78
|
+
return process.env.CODESPACES === "true" || process.env.CODESPACE_NAME !== void 0;
|
|
79
|
+
}
|
|
80
|
+
async run() {
|
|
81
|
+
const { flags } = await this.parse(_Init);
|
|
82
|
+
this.log("\u2728 Initializing Agor...\n");
|
|
83
|
+
if (this.isCodespaces() && !flags.force) {
|
|
84
|
+
this.log(chalk.cyan.bold("\u{1F680} GitHub Codespaces detected!\n"));
|
|
85
|
+
this.log(chalk.yellow("\u26A0\uFE0F Sandbox Mode:"));
|
|
86
|
+
this.log(" - Data persists only while Codespace is active");
|
|
87
|
+
this.log(" - Stopped Codespaces retain data for 30 days");
|
|
88
|
+
this.log(" - Rebuilt Codespaces lose all data\n");
|
|
89
|
+
this.log(chalk.dim("For production use, install Agor locally:"));
|
|
90
|
+
this.log(chalk.dim(" https://github.com/mistercrunch/agor#installation\n"));
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
const baseDir = flags.local ? join(process.cwd(), ".agor") : join(homedir(), ".agor");
|
|
94
|
+
const dbPath = join(baseDir, "agor.db");
|
|
95
|
+
const reposDir = join(baseDir, "repos");
|
|
96
|
+
const worktreesDir = join(baseDir, "worktrees");
|
|
97
|
+
const alreadyExists = await this.pathExists(baseDir);
|
|
98
|
+
const dbExists = await this.pathExists(dbPath);
|
|
99
|
+
const reposExist = await this.pathExists(reposDir);
|
|
100
|
+
const worktreesExist = await this.pathExists(worktreesDir);
|
|
101
|
+
if (!alreadyExists) {
|
|
102
|
+
await this.performInit(baseDir, dbPath, flags.force);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
this.log(chalk.yellow("\u26A0 Agor is already initialized at: ") + chalk.cyan(baseDir));
|
|
106
|
+
this.log("");
|
|
107
|
+
const dbStats = dbExists ? await this.getDbStats(dbPath) : null;
|
|
108
|
+
const repos = reposExist ? await this.listDirs(reposDir) : [];
|
|
109
|
+
const worktrees = worktreesExist ? await this.listDirs(worktreesDir) : [];
|
|
110
|
+
this.log(chalk.bold.red("\u26A0 Re-initialization will delete:"));
|
|
111
|
+
this.log("");
|
|
112
|
+
if (dbExists && dbStats) {
|
|
113
|
+
this.log(`${chalk.cyan(" Database:")} ${dbPath}`);
|
|
114
|
+
this.log(
|
|
115
|
+
chalk.dim(
|
|
116
|
+
` ${dbStats.sessions} sessions, ${dbStats.tasks} tasks, ${dbStats.messages} messages, ${dbStats.repos} repos`
|
|
117
|
+
)
|
|
118
|
+
);
|
|
119
|
+
} else if (dbExists) {
|
|
120
|
+
this.log(`${chalk.cyan(" Database:")} ${dbPath}`);
|
|
121
|
+
}
|
|
122
|
+
if (repos.length > 0) {
|
|
123
|
+
this.log(`${chalk.cyan(" Repos:")} ${reposDir}`);
|
|
124
|
+
for (const repo of repos.slice(0, 5)) {
|
|
125
|
+
this.log(chalk.dim(` - ${repo}`));
|
|
126
|
+
}
|
|
127
|
+
if (repos.length > 5) {
|
|
128
|
+
this.log(chalk.dim(` ... and ${repos.length - 5} more`));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (worktrees.length > 0) {
|
|
132
|
+
this.log(`${chalk.cyan(" Worktrees:")} ${worktreesDir}`);
|
|
133
|
+
for (const wt of worktrees.slice(0, 5)) {
|
|
134
|
+
this.log(chalk.dim(` - ${wt}`));
|
|
135
|
+
}
|
|
136
|
+
if (worktrees.length > 5) {
|
|
137
|
+
this.log(chalk.dim(` ... and ${worktrees.length - 5} more`));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
this.log("");
|
|
141
|
+
if (flags.force) {
|
|
142
|
+
this.log(chalk.yellow("\u{1F5D1}\uFE0F --force flag set: deleting everything without prompts..."));
|
|
143
|
+
await this.cleanupExisting(baseDir, dbPath, reposDir, worktreesDir);
|
|
144
|
+
await this.performInit(baseDir, dbPath, true);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const { confirmed } = await inquirer.prompt([
|
|
148
|
+
{
|
|
149
|
+
type: "confirm",
|
|
150
|
+
name: "confirmed",
|
|
151
|
+
message: "Delete all existing data and re-initialize?",
|
|
152
|
+
default: false
|
|
153
|
+
}
|
|
154
|
+
]);
|
|
155
|
+
if (!confirmed) {
|
|
156
|
+
this.log(chalk.dim("Cancelled. Use --force to skip this prompt."));
|
|
157
|
+
process.exit(0);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
await this.cleanupExisting(baseDir, dbPath, reposDir, worktreesDir);
|
|
161
|
+
await this.performInit(baseDir, dbPath, false);
|
|
162
|
+
} catch (error) {
|
|
163
|
+
this.error(
|
|
164
|
+
`Failed to initialize Agor: ${error instanceof Error ? error.message : String(error)}`
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Clean up existing installation
|
|
170
|
+
*/
|
|
171
|
+
async cleanupExisting(_baseDir, dbPath, reposDir, worktreesDir) {
|
|
172
|
+
this.log("");
|
|
173
|
+
this.log("\u{1F5D1}\uFE0F Cleaning up existing installation...");
|
|
174
|
+
if (await this.pathExists(dbPath)) {
|
|
175
|
+
await rm(dbPath, { force: true });
|
|
176
|
+
this.log(`${chalk.green(" \u2713")} Deleted database`);
|
|
177
|
+
}
|
|
178
|
+
if (await this.pathExists(reposDir)) {
|
|
179
|
+
await rm(reposDir, { recursive: true, force: true });
|
|
180
|
+
this.log(`${chalk.green(" \u2713")} Deleted repos`);
|
|
181
|
+
}
|
|
182
|
+
if (await this.pathExists(worktreesDir)) {
|
|
183
|
+
await rm(worktreesDir, { recursive: true, force: true });
|
|
184
|
+
this.log(`${chalk.green(" \u2713")} Deleted worktrees`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Perform fresh initialization
|
|
189
|
+
*/
|
|
190
|
+
async performInit(baseDir, dbPath, skipPrompts = false) {
|
|
191
|
+
this.log("");
|
|
192
|
+
this.log("\u{1F4C1} Creating directory structure...");
|
|
193
|
+
const dirs = [
|
|
194
|
+
baseDir,
|
|
195
|
+
join(baseDir, "repos"),
|
|
196
|
+
join(baseDir, "worktrees"),
|
|
197
|
+
join(baseDir, "concepts"),
|
|
198
|
+
join(baseDir, "logs")
|
|
199
|
+
];
|
|
200
|
+
for (const dir of dirs) {
|
|
201
|
+
await mkdir(dir, { recursive: true });
|
|
202
|
+
this.log(`${chalk.green(" \u2713")} ${dir}`);
|
|
203
|
+
}
|
|
204
|
+
this.log("");
|
|
205
|
+
this.log("\u{1F4BE} Setting up database...");
|
|
206
|
+
const db = createDatabase({ url: `file:${dbPath}` });
|
|
207
|
+
await initializeDatabase(db);
|
|
208
|
+
this.log(`${chalk.green(" \u2713")} Created ${dbPath}`);
|
|
209
|
+
this.log("");
|
|
210
|
+
this.log("\u{1F331} Seeding initial data...");
|
|
211
|
+
await seedInitialData(db);
|
|
212
|
+
this.log(`${chalk.green(" \u2713")} Created Main Board`);
|
|
213
|
+
if (!skipPrompts) {
|
|
214
|
+
await this.promptAuthSetup(dbPath);
|
|
215
|
+
await this.promptApiKeys();
|
|
216
|
+
}
|
|
217
|
+
this.log("");
|
|
218
|
+
this.log(chalk.green.bold("\u2705 Agor initialized successfully!"));
|
|
219
|
+
this.log("");
|
|
220
|
+
this.log(` Database: ${chalk.cyan(dbPath)}`);
|
|
221
|
+
this.log(` Repos: ${chalk.cyan(join(baseDir, "repos"))}`);
|
|
222
|
+
this.log(` Worktrees: ${chalk.cyan(join(baseDir, "worktrees"))}`);
|
|
223
|
+
this.log(` Concepts: ${chalk.cyan(join(baseDir, "concepts"))}`);
|
|
224
|
+
this.log(` Logs: ${chalk.cyan(join(baseDir, "logs"))}`);
|
|
225
|
+
this.log("");
|
|
226
|
+
if (this.isCodespaces()) {
|
|
227
|
+
this.log(chalk.bold("\u{1F4DD} API Key Setup (Optional):"));
|
|
228
|
+
this.log("");
|
|
229
|
+
this.log("To use AI agents (Claude, Gemini, etc.), set API keys:");
|
|
230
|
+
this.log("");
|
|
231
|
+
this.log(chalk.cyan("1. Environment variables (recommended for Codespaces):"));
|
|
232
|
+
this.log(' export ANTHROPIC_API_KEY="sk-ant-..."');
|
|
233
|
+
this.log(' export OPENAI_API_KEY="sk-..."');
|
|
234
|
+
this.log(' export GOOGLE_AI_API_KEY="..."');
|
|
235
|
+
this.log("");
|
|
236
|
+
this.log(chalk.cyan("2. Codespaces Secrets (persistent across rebuilds):"));
|
|
237
|
+
this.log(" GitHub \u2192 Settings \u2192 Codespaces \u2192 Secrets");
|
|
238
|
+
this.log(" Add keys there and rebuild Codespace");
|
|
239
|
+
this.log("");
|
|
240
|
+
this.log(chalk.yellow("\u{1F4A1} Tip: To preserve your work:"));
|
|
241
|
+
this.log(" - Keep Codespace active (auto-stops after 30 min idle)");
|
|
242
|
+
this.log(" - Export important sessions before stopping");
|
|
243
|
+
this.log(" - Use git to commit session transcripts");
|
|
244
|
+
this.log("");
|
|
245
|
+
}
|
|
246
|
+
this.log(chalk.bold("Next steps:"));
|
|
247
|
+
this.log(" - Run 'agor daemon' to start the daemon");
|
|
248
|
+
this.log(" - Run 'agor session list' to view all sessions");
|
|
249
|
+
this.log("");
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Prompt user for auth/multiplayer setup
|
|
253
|
+
*/
|
|
254
|
+
async promptAuthSetup(dbPath) {
|
|
255
|
+
this.log("");
|
|
256
|
+
const { enableAuth } = await inquirer.prompt([
|
|
257
|
+
{
|
|
258
|
+
type: "confirm",
|
|
259
|
+
name: "enableAuth",
|
|
260
|
+
message: "Enable authentication and multiplayer features?",
|
|
261
|
+
default: false
|
|
262
|
+
}
|
|
263
|
+
]);
|
|
264
|
+
if (!enableAuth) {
|
|
265
|
+
this.log(chalk.gray("Authentication disabled. Running in single-user mode."));
|
|
266
|
+
this.log("");
|
|
267
|
+
this.log(chalk.gray("You can enable auth later with:"));
|
|
268
|
+
this.log(chalk.gray(" agor config set daemon.requireAuth true"));
|
|
269
|
+
this.log(chalk.gray(" agor user create-admin"));
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
await setConfigValue("daemon.requireAuth", true);
|
|
273
|
+
await setConfigValue("daemon.allowAnonymous", false);
|
|
274
|
+
this.log(`${chalk.green(" \u2713")} Enabled authentication`);
|
|
275
|
+
this.log("");
|
|
276
|
+
const { createAdmin } = await inquirer.prompt([
|
|
277
|
+
{
|
|
278
|
+
type: "confirm",
|
|
279
|
+
name: "createAdmin",
|
|
280
|
+
message: "Create an admin user?",
|
|
281
|
+
default: true
|
|
282
|
+
}
|
|
283
|
+
]);
|
|
284
|
+
if (!createAdmin) {
|
|
285
|
+
this.log("");
|
|
286
|
+
this.log(chalk.yellow("\u26A0 You must create an admin user before starting the daemon:"));
|
|
287
|
+
this.log(chalk.gray(" agor user create-admin"));
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
const { email, username, password } = await inquirer.prompt([
|
|
291
|
+
{
|
|
292
|
+
type: "input",
|
|
293
|
+
name: "email",
|
|
294
|
+
message: "Email:",
|
|
295
|
+
validate: (input) => {
|
|
296
|
+
if (!input || !input.includes("@")) {
|
|
297
|
+
return "Please enter a valid email address";
|
|
298
|
+
}
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
type: "input",
|
|
304
|
+
name: "username",
|
|
305
|
+
message: "Username:",
|
|
306
|
+
validate: (input) => {
|
|
307
|
+
if (!input || input.length < 2) {
|
|
308
|
+
return "Username must be at least 2 characters";
|
|
309
|
+
}
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
type: "password",
|
|
315
|
+
name: "password",
|
|
316
|
+
message: "Password:",
|
|
317
|
+
mask: "*",
|
|
318
|
+
validate: (input) => {
|
|
319
|
+
if (!input || input.length < 4) {
|
|
320
|
+
return "Password must be at least 4 characters";
|
|
321
|
+
}
|
|
322
|
+
return true;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
]);
|
|
326
|
+
try {
|
|
327
|
+
const db = createDatabase({ url: `file:${dbPath}` });
|
|
328
|
+
const user = await createUser(db, {
|
|
329
|
+
email,
|
|
330
|
+
password,
|
|
331
|
+
name: username,
|
|
332
|
+
role: "admin"
|
|
333
|
+
});
|
|
334
|
+
this.log(
|
|
335
|
+
chalk.green(" \u2713") + ` Admin user created successfully (ID: ${chalk.gray(user.user_id.substring(0, 8))})`
|
|
336
|
+
);
|
|
337
|
+
} catch (error) {
|
|
338
|
+
this.log("");
|
|
339
|
+
this.log(chalk.red("\u2717 Failed to create admin user"));
|
|
340
|
+
if (error instanceof Error) {
|
|
341
|
+
this.log(chalk.red(` ${error.message}`));
|
|
342
|
+
}
|
|
343
|
+
this.log("");
|
|
344
|
+
this.log(chalk.gray("You can create an admin user later with:"));
|
|
345
|
+
this.log(chalk.gray(" agor user create-admin"));
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Prompt user for API key setup
|
|
350
|
+
*/
|
|
351
|
+
async promptApiKeys() {
|
|
352
|
+
this.log("");
|
|
353
|
+
this.log(chalk.bold("\u{1F511} API Key Setup"));
|
|
354
|
+
this.log("");
|
|
355
|
+
this.log(chalk.gray("Configure API keys for AI agents (optional, can be set later)"));
|
|
356
|
+
this.log("");
|
|
357
|
+
const { setupKeys } = await inquirer.prompt([
|
|
358
|
+
{
|
|
359
|
+
type: "confirm",
|
|
360
|
+
name: "setupKeys",
|
|
361
|
+
message: "Set up API keys now?",
|
|
362
|
+
default: false
|
|
363
|
+
}
|
|
364
|
+
]);
|
|
365
|
+
if (!setupKeys) {
|
|
366
|
+
this.log("");
|
|
367
|
+
this.log(chalk.gray("Skipped. You can set API keys later with:"));
|
|
368
|
+
this.log(chalk.gray(' agor config set credentials.ANTHROPIC_API_KEY "sk-ant-..."'));
|
|
369
|
+
this.log(chalk.gray(' agor config set credentials.OPENAI_API_KEY "sk-..."'));
|
|
370
|
+
this.log(chalk.gray(' agor config set credentials.GEMINI_API_KEY "..."'));
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
const { setupAnthropic } = await inquirer.prompt([
|
|
374
|
+
{
|
|
375
|
+
type: "confirm",
|
|
376
|
+
name: "setupAnthropic",
|
|
377
|
+
message: "Set up Anthropic API key (for Claude Code)?",
|
|
378
|
+
default: true
|
|
379
|
+
}
|
|
380
|
+
]);
|
|
381
|
+
if (setupAnthropic) {
|
|
382
|
+
const { anthropicKey } = await inquirer.prompt([
|
|
383
|
+
{
|
|
384
|
+
type: "password",
|
|
385
|
+
name: "anthropicKey",
|
|
386
|
+
message: "Anthropic API key (sk-ant-...):",
|
|
387
|
+
mask: "*",
|
|
388
|
+
validate: (input) => {
|
|
389
|
+
if (!input || input.length < 10) {
|
|
390
|
+
return "Please enter a valid API key";
|
|
391
|
+
}
|
|
392
|
+
return true;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
]);
|
|
396
|
+
await setConfigValue("credentials.ANTHROPIC_API_KEY", anthropicKey);
|
|
397
|
+
this.log(chalk.green(" \u2713") + " Anthropic API key saved");
|
|
398
|
+
}
|
|
399
|
+
const { setupOpenAI } = await inquirer.prompt([
|
|
400
|
+
{
|
|
401
|
+
type: "confirm",
|
|
402
|
+
name: "setupOpenAI",
|
|
403
|
+
message: "Set up OpenAI API key (for Codex)?",
|
|
404
|
+
default: false
|
|
405
|
+
}
|
|
406
|
+
]);
|
|
407
|
+
if (setupOpenAI) {
|
|
408
|
+
const { openaiKey } = await inquirer.prompt([
|
|
409
|
+
{
|
|
410
|
+
type: "password",
|
|
411
|
+
name: "openaiKey",
|
|
412
|
+
message: "OpenAI API key (sk-...):",
|
|
413
|
+
mask: "*",
|
|
414
|
+
validate: (input) => {
|
|
415
|
+
if (!input || input.length < 10) {
|
|
416
|
+
return "Please enter a valid API key";
|
|
417
|
+
}
|
|
418
|
+
return true;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
]);
|
|
422
|
+
await setConfigValue("credentials.OPENAI_API_KEY", openaiKey);
|
|
423
|
+
this.log(chalk.green(" \u2713") + " OpenAI API key saved");
|
|
424
|
+
}
|
|
425
|
+
const { setupGemini } = await inquirer.prompt([
|
|
426
|
+
{
|
|
427
|
+
type: "confirm",
|
|
428
|
+
name: "setupGemini",
|
|
429
|
+
message: "Set up Google Gemini API key?",
|
|
430
|
+
default: false
|
|
431
|
+
}
|
|
432
|
+
]);
|
|
433
|
+
if (setupGemini) {
|
|
434
|
+
const { geminiKey } = await inquirer.prompt([
|
|
435
|
+
{
|
|
436
|
+
type: "password",
|
|
437
|
+
name: "geminiKey",
|
|
438
|
+
message: "Google Gemini API key:",
|
|
439
|
+
mask: "*",
|
|
440
|
+
validate: (input) => {
|
|
441
|
+
if (!input || input.length < 10) {
|
|
442
|
+
return "Please enter a valid API key";
|
|
443
|
+
}
|
|
444
|
+
return true;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
]);
|
|
448
|
+
await setConfigValue("credentials.GEMINI_API_KEY", geminiKey);
|
|
449
|
+
this.log(chalk.green(" \u2713") + " Gemini API key saved");
|
|
450
|
+
}
|
|
451
|
+
this.log("");
|
|
452
|
+
this.log(
|
|
453
|
+
chalk.gray("Note: API keys are stored in ~/.agor/config.yaml (keep this file secure!)")
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
export {
|
|
458
|
+
Init as default
|
|
459
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as _oclif_core_interfaces from '@oclif/core/interfaces';
|
|
2
|
+
import { Command } from '@oclif/core';
|
|
3
|
+
|
|
4
|
+
declare class McpAdd extends Command {
|
|
5
|
+
static description: string;
|
|
6
|
+
static examples: string[];
|
|
7
|
+
static args: {
|
|
8
|
+
name: _oclif_core_interfaces.Arg<string, Record<string, unknown>>;
|
|
9
|
+
};
|
|
10
|
+
static flags: {
|
|
11
|
+
transport: _oclif_core_interfaces.OptionFlag<string, _oclif_core_interfaces.CustomOptions>;
|
|
12
|
+
command: _oclif_core_interfaces.OptionFlag<string | undefined, _oclif_core_interfaces.CustomOptions>;
|
|
13
|
+
args: _oclif_core_interfaces.OptionFlag<string | undefined, _oclif_core_interfaces.CustomOptions>;
|
|
14
|
+
url: _oclif_core_interfaces.OptionFlag<string | undefined, _oclif_core_interfaces.CustomOptions>;
|
|
15
|
+
scope: _oclif_core_interfaces.OptionFlag<string, _oclif_core_interfaces.CustomOptions>;
|
|
16
|
+
'session-id': _oclif_core_interfaces.OptionFlag<string | undefined, _oclif_core_interfaces.CustomOptions>;
|
|
17
|
+
'repo-id': _oclif_core_interfaces.OptionFlag<string | undefined, _oclif_core_interfaces.CustomOptions>;
|
|
18
|
+
'display-name': _oclif_core_interfaces.OptionFlag<string | undefined, _oclif_core_interfaces.CustomOptions>;
|
|
19
|
+
description: _oclif_core_interfaces.OptionFlag<string | undefined, _oclif_core_interfaces.CustomOptions>;
|
|
20
|
+
enabled: _oclif_core_interfaces.BooleanFlag<boolean>;
|
|
21
|
+
env: _oclif_core_interfaces.OptionFlag<string | undefined, _oclif_core_interfaces.CustomOptions>;
|
|
22
|
+
};
|
|
23
|
+
run(): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { McpAdd as default };
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// src/commands/mcp/add.ts
|
|
2
|
+
import { createClient, isDaemonRunning } from "@agor/core/api";
|
|
3
|
+
import { getDaemonUrl } from "@agor/core/config";
|
|
4
|
+
import { Args, Command, Flags } from "@oclif/core";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
var McpAdd = class _McpAdd extends Command {
|
|
7
|
+
static description = "Add a new MCP server";
|
|
8
|
+
static examples = [
|
|
9
|
+
'<%= config.bin %> <%= command.id %> filesystem --command npx --args "@modelcontextprotocol/server-filesystem,/path/to/allowed"',
|
|
10
|
+
"<%= config.bin %> <%= command.id %> sentry --transport http --url https://mcp.sentry.dev/mcp",
|
|
11
|
+
'<%= config.bin %> <%= command.id %> custom-tool --command node --args "dist/server.js" --scope session --session-id 0199b856'
|
|
12
|
+
];
|
|
13
|
+
static args = {
|
|
14
|
+
name: Args.string({
|
|
15
|
+
description: "MCP server name (e.g., filesystem, sentry, custom-tool)",
|
|
16
|
+
required: true
|
|
17
|
+
})
|
|
18
|
+
};
|
|
19
|
+
static flags = {
|
|
20
|
+
transport: Flags.string({
|
|
21
|
+
char: "t",
|
|
22
|
+
description: "Transport type",
|
|
23
|
+
options: ["stdio", "http", "sse"],
|
|
24
|
+
default: "stdio"
|
|
25
|
+
}),
|
|
26
|
+
command: Flags.string({
|
|
27
|
+
char: "c",
|
|
28
|
+
description: "Command to run (for stdio transport)"
|
|
29
|
+
}),
|
|
30
|
+
args: Flags.string({
|
|
31
|
+
char: "a",
|
|
32
|
+
description: "Command arguments (comma-separated)"
|
|
33
|
+
}),
|
|
34
|
+
url: Flags.string({
|
|
35
|
+
char: "u",
|
|
36
|
+
description: "Server URL (for http/sse transport)"
|
|
37
|
+
}),
|
|
38
|
+
scope: Flags.string({
|
|
39
|
+
char: "s",
|
|
40
|
+
description: "Server scope",
|
|
41
|
+
options: ["global", "team", "repo", "session"],
|
|
42
|
+
default: "global"
|
|
43
|
+
}),
|
|
44
|
+
"session-id": Flags.string({
|
|
45
|
+
description: "Session ID (required if scope=session)"
|
|
46
|
+
}),
|
|
47
|
+
"repo-id": Flags.string({
|
|
48
|
+
description: "Repo ID (required if scope=repo)"
|
|
49
|
+
}),
|
|
50
|
+
"display-name": Flags.string({
|
|
51
|
+
char: "d",
|
|
52
|
+
description: "Display name for the server"
|
|
53
|
+
}),
|
|
54
|
+
description: Flags.string({
|
|
55
|
+
description: "Server description"
|
|
56
|
+
}),
|
|
57
|
+
enabled: Flags.boolean({
|
|
58
|
+
description: "Enable server immediately",
|
|
59
|
+
default: true
|
|
60
|
+
}),
|
|
61
|
+
env: Flags.string({
|
|
62
|
+
char: "e",
|
|
63
|
+
description: "Environment variables (key=value pairs, comma-separated)"
|
|
64
|
+
})
|
|
65
|
+
};
|
|
66
|
+
async run() {
|
|
67
|
+
const { args, flags } = await this.parse(_McpAdd);
|
|
68
|
+
const daemonUrl = await getDaemonUrl();
|
|
69
|
+
const running = await isDaemonRunning(daemonUrl);
|
|
70
|
+
if (!running) {
|
|
71
|
+
this.error(
|
|
72
|
+
`Daemon not running. Start it with: ${chalk.cyan("cd apps/agor-daemon && pnpm dev")}`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
if (flags.transport === "stdio" && !flags.command) {
|
|
76
|
+
this.error("--command is required for stdio transport");
|
|
77
|
+
}
|
|
78
|
+
if ((flags.transport === "http" || flags.transport === "sse") && !flags.url) {
|
|
79
|
+
this.error("--url is required for http/sse transport");
|
|
80
|
+
}
|
|
81
|
+
if (flags.scope === "session" && !flags["session-id"]) {
|
|
82
|
+
this.error("--session-id is required when scope=session");
|
|
83
|
+
}
|
|
84
|
+
if (flags.scope === "repo" && !flags["repo-id"]) {
|
|
85
|
+
this.error("--repo-id is required when scope=repo");
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
this.log("");
|
|
89
|
+
this.log(chalk.bold(`Adding MCP server ${chalk.cyan(args.name)}...`));
|
|
90
|
+
const data = {
|
|
91
|
+
name: args.name,
|
|
92
|
+
display_name: flags["display-name"],
|
|
93
|
+
description: flags.description,
|
|
94
|
+
transport: flags.transport,
|
|
95
|
+
scope: flags.scope,
|
|
96
|
+
enabled: flags.enabled,
|
|
97
|
+
source: "user"
|
|
98
|
+
};
|
|
99
|
+
if (flags.command) data.command = flags.command;
|
|
100
|
+
if (flags.args) data.args = flags.args.split(",").map((arg) => arg.trim());
|
|
101
|
+
if (flags.url) data.url = flags.url;
|
|
102
|
+
if (flags.env) {
|
|
103
|
+
const envPairs = flags.env.split(",").map((pair) => pair.trim());
|
|
104
|
+
const envObject = {};
|
|
105
|
+
for (const pair of envPairs) {
|
|
106
|
+
const [key, value] = pair.split("=");
|
|
107
|
+
if (key && value) {
|
|
108
|
+
envObject[key.trim()] = value.trim();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (Object.keys(envObject).length > 0) {
|
|
112
|
+
data.env = envObject;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (flags["session-id"]) data.session_id = flags["session-id"];
|
|
116
|
+
if (flags["repo-id"]) data.repo_id = flags["repo-id"];
|
|
117
|
+
const client = createClient(daemonUrl);
|
|
118
|
+
const server = await client.service("mcp-servers").create(data);
|
|
119
|
+
this.log(`${chalk.green("\u2713")} MCP server added`);
|
|
120
|
+
this.log("");
|
|
121
|
+
this.log(chalk.bold("Server Details:"));
|
|
122
|
+
this.log(` ${chalk.cyan("ID")}: ${String(server.mcp_server_id).substring(0, 8)}`);
|
|
123
|
+
this.log(` ${chalk.cyan("Name")}: ${server.name}`);
|
|
124
|
+
this.log(` ${chalk.cyan("Transport")}: ${server.transport}`);
|
|
125
|
+
this.log(` ${chalk.cyan("Scope")}: ${server.scope}`);
|
|
126
|
+
this.log(
|
|
127
|
+
` ${chalk.cyan("Enabled")}: ${server.enabled ? chalk.green("\u2713") : chalk.gray("\u2717")}`
|
|
128
|
+
);
|
|
129
|
+
if (server.command) {
|
|
130
|
+
this.log(` ${chalk.cyan("Command")}: ${server.command}`);
|
|
131
|
+
}
|
|
132
|
+
if (server.args) {
|
|
133
|
+
this.log(` ${chalk.cyan("Args")}: ${server.args.join(", ")}`);
|
|
134
|
+
}
|
|
135
|
+
if (server.url) {
|
|
136
|
+
this.log(` ${chalk.cyan("URL")}: ${server.url}`);
|
|
137
|
+
}
|
|
138
|
+
if (server.env) {
|
|
139
|
+
const envKeys = Object.keys(server.env);
|
|
140
|
+
this.log(` ${chalk.cyan("Environment")}: ${envKeys.join(", ")}`);
|
|
141
|
+
}
|
|
142
|
+
this.log("");
|
|
143
|
+
await new Promise((resolve) => {
|
|
144
|
+
client.io.once("disconnect", () => resolve());
|
|
145
|
+
client.io.close();
|
|
146
|
+
setTimeout(() => resolve(), 1e3);
|
|
147
|
+
});
|
|
148
|
+
process.exit(0);
|
|
149
|
+
} catch (error) {
|
|
150
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
151
|
+
this.log("");
|
|
152
|
+
this.log(chalk.red("\u2717 Failed to add MCP server"));
|
|
153
|
+
this.log("");
|
|
154
|
+
this.log(chalk.dim(message));
|
|
155
|
+
this.log("");
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
export {
|
|
161
|
+
McpAdd as default
|
|
162
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as _oclif_core_interfaces from '@oclif/core/interfaces';
|
|
2
|
+
import { Command } from '@oclif/core';
|
|
3
|
+
|
|
4
|
+
declare class McpList extends Command {
|
|
5
|
+
static description: string;
|
|
6
|
+
static examples: string[];
|
|
7
|
+
static flags: {
|
|
8
|
+
scope: _oclif_core_interfaces.OptionFlag<string | undefined, _oclif_core_interfaces.CustomOptions>;
|
|
9
|
+
transport: _oclif_core_interfaces.OptionFlag<string | undefined, _oclif_core_interfaces.CustomOptions>;
|
|
10
|
+
enabled: _oclif_core_interfaces.BooleanFlag<boolean>;
|
|
11
|
+
};
|
|
12
|
+
run(): Promise<void>;
|
|
13
|
+
private cleanup;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { McpList as default };
|