@astroanywhere/agent 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +76 -0
- package/README.md +178 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +401 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/index.d.ts +9 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +9 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/mcp.d.ts +16 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +19 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/setup.d.ts +20 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +585 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/start.d.ts +16 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +638 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/status.d.ts +5 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +63 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/stop.d.ts +5 -0
- package/dist/commands/stop.d.ts.map +1 -0
- package/dist/commands/stop.js +85 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/execution/direct-strategy.d.ts +18 -0
- package/dist/execution/direct-strategy.d.ts.map +1 -0
- package/dist/execution/direct-strategy.js +156 -0
- package/dist/execution/direct-strategy.js.map +1 -0
- package/dist/execution/docker-strategy.d.ts +26 -0
- package/dist/execution/docker-strategy.d.ts.map +1 -0
- package/dist/execution/docker-strategy.js +222 -0
- package/dist/execution/docker-strategy.js.map +1 -0
- package/dist/execution/index.d.ts +14 -0
- package/dist/execution/index.d.ts.map +1 -0
- package/dist/execution/index.js +13 -0
- package/dist/execution/index.js.map +1 -0
- package/dist/execution/kubernetes-exec-strategy.d.ts +23 -0
- package/dist/execution/kubernetes-exec-strategy.d.ts.map +1 -0
- package/dist/execution/kubernetes-exec-strategy.js +232 -0
- package/dist/execution/kubernetes-exec-strategy.js.map +1 -0
- package/dist/execution/registry.d.ts +41 -0
- package/dist/execution/registry.d.ts.map +1 -0
- package/dist/execution/registry.js +84 -0
- package/dist/execution/registry.js.map +1 -0
- package/dist/execution/slurm-strategy.d.ts +22 -0
- package/dist/execution/slurm-strategy.d.ts.map +1 -0
- package/dist/execution/slurm-strategy.js +219 -0
- package/dist/execution/slurm-strategy.js.map +1 -0
- package/dist/execution/types.d.ts +72 -0
- package/dist/execution/types.d.ts.map +1 -0
- package/dist/execution/types.js +10 -0
- package/dist/execution/types.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api-client.d.ts +35 -0
- package/dist/lib/api-client.d.ts.map +1 -0
- package/dist/lib/api-client.js +126 -0
- package/dist/lib/api-client.js.map +1 -0
- package/dist/lib/config.d.ts +174 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +399 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/copy-worktree.d.ts +73 -0
- package/dist/lib/copy-worktree.d.ts.map +1 -0
- package/dist/lib/copy-worktree.js +374 -0
- package/dist/lib/copy-worktree.js.map +1 -0
- package/dist/lib/git-pr.d.ts +63 -0
- package/dist/lib/git-pr.d.ts.map +1 -0
- package/dist/lib/git-pr.js +224 -0
- package/dist/lib/git-pr.js.map +1 -0
- package/dist/lib/hardware-id.d.ts +25 -0
- package/dist/lib/hardware-id.d.ts.map +1 -0
- package/dist/lib/hardware-id.js +186 -0
- package/dist/lib/hardware-id.js.map +1 -0
- package/dist/lib/hpc-context.d.ts +35 -0
- package/dist/lib/hpc-context.d.ts.map +1 -0
- package/dist/lib/hpc-context.js +167 -0
- package/dist/lib/hpc-context.js.map +1 -0
- package/dist/lib/prompt-templates.d.ts +195 -0
- package/dist/lib/prompt-templates.d.ts.map +1 -0
- package/dist/lib/prompt-templates.js +353 -0
- package/dist/lib/prompt-templates.js.map +1 -0
- package/dist/lib/providers.d.ts +27 -0
- package/dist/lib/providers.d.ts.map +1 -0
- package/dist/lib/providers.js +372 -0
- package/dist/lib/providers.js.map +1 -0
- package/dist/lib/repo-context.d.ts +18 -0
- package/dist/lib/repo-context.d.ts.map +1 -0
- package/dist/lib/repo-context.js +61 -0
- package/dist/lib/repo-context.js.map +1 -0
- package/dist/lib/repo-utils.d.ts +35 -0
- package/dist/lib/repo-utils.d.ts.map +1 -0
- package/dist/lib/repo-utils.js +222 -0
- package/dist/lib/repo-utils.js.map +1 -0
- package/dist/lib/resources.d.ts +17 -0
- package/dist/lib/resources.d.ts.map +1 -0
- package/dist/lib/resources.js +227 -0
- package/dist/lib/resources.js.map +1 -0
- package/dist/lib/slurm-detect.d.ts +15 -0
- package/dist/lib/slurm-detect.d.ts.map +1 -0
- package/dist/lib/slurm-detect.js +148 -0
- package/dist/lib/slurm-detect.js.map +1 -0
- package/dist/lib/slurm-executor.d.ts +70 -0
- package/dist/lib/slurm-executor.d.ts.map +1 -0
- package/dist/lib/slurm-executor.js +402 -0
- package/dist/lib/slurm-executor.js.map +1 -0
- package/dist/lib/slurm-job-monitor.d.ts +52 -0
- package/dist/lib/slurm-job-monitor.d.ts.map +1 -0
- package/dist/lib/slurm-job-monitor.js +212 -0
- package/dist/lib/slurm-job-monitor.js.map +1 -0
- package/dist/lib/ssh-discovery.d.ts +17 -0
- package/dist/lib/ssh-discovery.d.ts.map +1 -0
- package/dist/lib/ssh-discovery.js +287 -0
- package/dist/lib/ssh-discovery.js.map +1 -0
- package/dist/lib/ssh-installer.d.ts +69 -0
- package/dist/lib/ssh-installer.d.ts.map +1 -0
- package/dist/lib/ssh-installer.js +230 -0
- package/dist/lib/ssh-installer.js.map +1 -0
- package/dist/lib/streaming-prompt.d.ts +48 -0
- package/dist/lib/streaming-prompt.d.ts.map +1 -0
- package/dist/lib/streaming-prompt.js +91 -0
- package/dist/lib/streaming-prompt.js.map +1 -0
- package/dist/lib/task-executor.d.ts +114 -0
- package/dist/lib/task-executor.d.ts.map +1 -0
- package/dist/lib/task-executor.js +753 -0
- package/dist/lib/task-executor.js.map +1 -0
- package/dist/lib/websocket-client.d.ts +200 -0
- package/dist/lib/websocket-client.d.ts.map +1 -0
- package/dist/lib/websocket-client.js +781 -0
- package/dist/lib/websocket-client.js.map +1 -0
- package/dist/lib/workdir-safety.d.ts +63 -0
- package/dist/lib/workdir-safety.d.ts.map +1 -0
- package/dist/lib/workdir-safety.js +247 -0
- package/dist/lib/workdir-safety.js.map +1 -0
- package/dist/lib/worktree-include.d.ts +14 -0
- package/dist/lib/worktree-include.d.ts.map +1 -0
- package/dist/lib/worktree-include.js +68 -0
- package/dist/lib/worktree-include.js.map +1 -0
- package/dist/lib/worktree-setup.d.ts +18 -0
- package/dist/lib/worktree-setup.d.ts.map +1 -0
- package/dist/lib/worktree-setup.js +60 -0
- package/dist/lib/worktree-setup.js.map +1 -0
- package/dist/lib/worktree.d.ts +37 -0
- package/dist/lib/worktree.d.ts.map +1 -0
- package/dist/lib/worktree.js +411 -0
- package/dist/lib/worktree.js.map +1 -0
- package/dist/mcp/index.d.ts +8 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +8 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +45 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +153 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/session-bridge.d.ts +87 -0
- package/dist/mcp/session-bridge.d.ts.map +1 -0
- package/dist/mcp/session-bridge.js +317 -0
- package/dist/mcp/session-bridge.js.map +1 -0
- package/dist/mcp/tools.d.ts +70 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +234 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/mcp/types.d.ts +197 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +16 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/providers/base-adapter.d.ts +56 -0
- package/dist/providers/base-adapter.d.ts.map +1 -0
- package/dist/providers/base-adapter.js +5 -0
- package/dist/providers/base-adapter.js.map +1 -0
- package/dist/providers/claude-code-adapter.d.ts +27 -0
- package/dist/providers/claude-code-adapter.d.ts.map +1 -0
- package/dist/providers/claude-code-adapter.js +298 -0
- package/dist/providers/claude-code-adapter.js.map +1 -0
- package/dist/providers/claude-sdk-adapter.d.ts +60 -0
- package/dist/providers/claude-sdk-adapter.d.ts.map +1 -0
- package/dist/providers/claude-sdk-adapter.js +632 -0
- package/dist/providers/claude-sdk-adapter.js.map +1 -0
- package/dist/providers/codex-adapter.d.ts +21 -0
- package/dist/providers/codex-adapter.d.ts.map +1 -0
- package/dist/providers/codex-adapter.js +197 -0
- package/dist/providers/codex-adapter.js.map +1 -0
- package/dist/providers/index.d.ts +26 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +58 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/slurm-adapter.d.ts +26 -0
- package/dist/providers/slurm-adapter.d.ts.map +1 -0
- package/dist/providers/slurm-adapter.js +146 -0
- package/dist/providers/slurm-adapter.js.map +1 -0
- package/dist/types.d.ts +592 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +77 -0
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import { mkdir, readFile, appendFile, rm, copyFile } from 'node:fs/promises';
|
|
4
|
+
import { existsSync } from 'node:fs';
|
|
5
|
+
import { homedir } from 'node:os';
|
|
6
|
+
import { basename, isAbsolute, join, relative, resolve } from 'node:path';
|
|
7
|
+
import { applyWorktreeInclude } from './worktree-include.js';
|
|
8
|
+
import { runSetupScript } from './worktree-setup.js';
|
|
9
|
+
const execFileAsync = promisify(execFile);
|
|
10
|
+
export async function createWorktree(options) {
|
|
11
|
+
const { workingDirectory, taskId, rootOverride, projectId, nodeId, agentDir, stdout, stderr, } = options;
|
|
12
|
+
// Validate taskId format to prevent command injection
|
|
13
|
+
validateTaskId(taskId);
|
|
14
|
+
const resolvedWorkingDirectory = resolve(workingDirectory);
|
|
15
|
+
const gitRoot = await getGitRoot(resolvedWorkingDirectory);
|
|
16
|
+
// Require git repository to exist
|
|
17
|
+
// Safety checks in task-executor.ts ensure git is initialized before reaching here
|
|
18
|
+
if (!gitRoot) {
|
|
19
|
+
throw new Error(`Not a git repository: ${resolvedWorkingDirectory}. Initialize git first.`);
|
|
20
|
+
}
|
|
21
|
+
const hasHead = await hasCommits(gitRoot);
|
|
22
|
+
if (!hasHead) {
|
|
23
|
+
throw new Error(`Git repository has no commits: ${gitRoot}. Create an initial commit first.`);
|
|
24
|
+
}
|
|
25
|
+
const agentDirName = agentDir ?? '.astro';
|
|
26
|
+
const baseRoot = rootOverride ?? await resolveWorktreeRoot(gitRoot, agentDirName);
|
|
27
|
+
const branchPrefix = await readBranchPrefix(gitRoot, agentDirName);
|
|
28
|
+
const branchName = `${branchPrefix}${sanitize(taskId)}`;
|
|
29
|
+
const worktreePath = join(baseRoot, sanitize(taskId));
|
|
30
|
+
await rm(worktreePath, { recursive: true, force: true });
|
|
31
|
+
await pruneWorktrees(gitRoot);
|
|
32
|
+
// Find and remove any existing worktree that uses this branch (porcelain parsing).
|
|
33
|
+
// Without this, `git branch -D` fails because the branch is checked out
|
|
34
|
+
// by a lingering worktree from a previous execution.
|
|
35
|
+
await removeLingeringWorktrees(gitRoot, branchName);
|
|
36
|
+
await ensureBranchAvailable(gitRoot, branchName);
|
|
37
|
+
// Delete remote branch if it exists — prevents non-fast-forward push
|
|
38
|
+
// failures when re-executing a task whose previous branch was already pushed
|
|
39
|
+
await deleteRemoteBranch(gitRoot, branchName);
|
|
40
|
+
// Fetch latest so we branch from up-to-date origin
|
|
41
|
+
try {
|
|
42
|
+
await execFileAsync('git', ['-C', gitRoot, '-c', 'core.hooksPath=/dev/null', 'fetch', 'origin'], { env: withGitEnv(), timeout: 30_000 });
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// Non-fatal: proceed with potentially stale refs
|
|
46
|
+
}
|
|
47
|
+
// Detect the default branch to use as start point
|
|
48
|
+
const defaultBranch = await getDefaultBranch(gitRoot);
|
|
49
|
+
// Create worktree from origin/<defaultBranch> — NOT from HEAD.
|
|
50
|
+
// Using HEAD is dangerous because it could be on a stale task branch
|
|
51
|
+
// (from a previous execution that fell back to the repo directly),
|
|
52
|
+
// which would cause cross-task commit contamination.
|
|
53
|
+
await execFileAsync('git', ['-C', gitRoot, 'worktree', 'add', '-b', branchName, worktreePath, `origin/${defaultBranch}`], { env: withGitEnv(), timeout: 30_000 });
|
|
54
|
+
// Initialize submodules if the repo uses them (non-fatal)
|
|
55
|
+
try {
|
|
56
|
+
await initSubmodules(worktreePath, stderr);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
60
|
+
stderr?.(`submodule init failed: ${msg}`);
|
|
61
|
+
}
|
|
62
|
+
// Orchestration: include files + setup script (both non-fatal)
|
|
63
|
+
const log = stdout;
|
|
64
|
+
try {
|
|
65
|
+
await applyWorktreeInclude({ gitRoot, worktreePath, log });
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
69
|
+
stderr?.(`worktree-include failed: ${msg}`);
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
await runSetupScript({
|
|
73
|
+
gitRoot,
|
|
74
|
+
worktreePath,
|
|
75
|
+
taskId,
|
|
76
|
+
projectId,
|
|
77
|
+
nodeId,
|
|
78
|
+
stdout,
|
|
79
|
+
stderr,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
84
|
+
stderr?.(`setup script failed: ${msg}`);
|
|
85
|
+
}
|
|
86
|
+
// Copy CLAUDE.md if it exists in the git root but isn't tracked (non-fatal)
|
|
87
|
+
try {
|
|
88
|
+
await ensureClaudeMdInWorktree(gitRoot, worktreePath);
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
92
|
+
stderr?.(`CLAUDE.md copy failed: ${msg}`);
|
|
93
|
+
}
|
|
94
|
+
const relativePath = relative(gitRoot, resolvedWorkingDirectory);
|
|
95
|
+
const useRelativePath = relativePath && !relativePath.startsWith('..') && !isAbsolute(relativePath) && relativePath !== '.';
|
|
96
|
+
const worktreeWorkingDirectory = useRelativePath
|
|
97
|
+
? join(worktreePath, relativePath)
|
|
98
|
+
: worktreePath;
|
|
99
|
+
return {
|
|
100
|
+
workingDirectory: worktreeWorkingDirectory,
|
|
101
|
+
branchName,
|
|
102
|
+
cleanup: async (options) => {
|
|
103
|
+
await cleanupWorktree(gitRoot, worktreePath, branchName, options?.keepBranch);
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Parse `git worktree list --porcelain` and remove any worktree
|
|
109
|
+
* that has the target branch checked out. This prevents
|
|
110
|
+
* "branch already checked out" errors on re-execution.
|
|
111
|
+
*/
|
|
112
|
+
export async function removeLingeringWorktrees(gitRoot, branchName) {
|
|
113
|
+
let wtList;
|
|
114
|
+
try {
|
|
115
|
+
const result = await execFileAsync('git', ['-C', gitRoot, 'worktree', 'list', '--porcelain'], { env: withGitEnv(), timeout: 10_000 });
|
|
116
|
+
wtList = result.stdout;
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return; // Can't list — nothing to clean
|
|
120
|
+
}
|
|
121
|
+
// Parse porcelain output: blocks separated by blank lines,
|
|
122
|
+
// each block has "worktree <path>" and "branch refs/heads/<name>"
|
|
123
|
+
let currentWorktreePath = null;
|
|
124
|
+
for (const line of wtList.split('\n')) {
|
|
125
|
+
if (line.startsWith('worktree ')) {
|
|
126
|
+
currentWorktreePath = line.slice('worktree '.length);
|
|
127
|
+
}
|
|
128
|
+
else if (line.startsWith('branch ') && currentWorktreePath) {
|
|
129
|
+
const ref = line.slice('branch '.length);
|
|
130
|
+
if (ref === `refs/heads/${branchName}`) {
|
|
131
|
+
console.log(`[worktree] Removing lingering worktree at ${currentWorktreePath} (branch: ${branchName})`);
|
|
132
|
+
// Try git worktree remove first, fall back to force-removing the directory + prune
|
|
133
|
+
try {
|
|
134
|
+
await execFileAsync('git', ['-C', gitRoot, 'worktree', 'remove', '--force', currentWorktreePath], { env: withGitEnv(), timeout: 30_000 });
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
// Fallback: force-remove the directory and prune to deregister
|
|
138
|
+
await rm(currentWorktreePath, { recursive: true, force: true });
|
|
139
|
+
await execFileAsync('git', ['-C', gitRoot, 'worktree', 'prune'], {
|
|
140
|
+
env: withGitEnv(),
|
|
141
|
+
timeout: 30_000,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
// Clean up directory if it still exists after either path
|
|
145
|
+
if (existsSync(currentWorktreePath)) {
|
|
146
|
+
await rm(currentWorktreePath, { recursive: true, force: true });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else if (line.trim() === '') {
|
|
151
|
+
currentWorktreePath = null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Delete remote branch if it exists.
|
|
157
|
+
* Prevents non-fast-forward push failures when re-executing a task
|
|
158
|
+
* whose previous branch was already pushed.
|
|
159
|
+
*/
|
|
160
|
+
async function deleteRemoteBranch(gitRoot, branchName) {
|
|
161
|
+
try {
|
|
162
|
+
await execFileAsync('git', ['-C', gitRoot, 'push', 'origin', '--delete', branchName], { env: withGitEnv(), timeout: 15_000 });
|
|
163
|
+
console.log(`[worktree] Deleted remote branch ${branchName}`);
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
// Remote branch didn't exist — that's fine
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Detect the default branch (main/master) for the repo.
|
|
171
|
+
*/
|
|
172
|
+
async function getDefaultBranch(gitRoot) {
|
|
173
|
+
try {
|
|
174
|
+
const { stdout } = await execFileAsync('git', ['-C', gitRoot, 'symbolic-ref', 'refs/remotes/origin/HEAD'], { env: withGitEnv(), timeout: 5_000 });
|
|
175
|
+
const parts = stdout.trim().split('/');
|
|
176
|
+
return parts[parts.length - 1];
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
// Fallback
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
const { stdout } = await execFileAsync('git', ['-C', gitRoot, 'branch', '-r', '--list', 'origin/main', 'origin/master'], { env: withGitEnv(), timeout: 5_000 });
|
|
183
|
+
const branches = stdout.trim().split('\n').map((b) => b.trim());
|
|
184
|
+
if (branches.includes('origin/main'))
|
|
185
|
+
return 'main';
|
|
186
|
+
if (branches.includes('origin/master'))
|
|
187
|
+
return 'master';
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
// Fallback
|
|
191
|
+
}
|
|
192
|
+
return 'main';
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Read the branch prefix from the agent directory config.
|
|
196
|
+
* Falls back to 'astro/' if config doesn't exist or is invalid.
|
|
197
|
+
*/
|
|
198
|
+
async function readBranchPrefix(gitRoot, agentDirName) {
|
|
199
|
+
try {
|
|
200
|
+
const configPath = join(gitRoot, agentDirName, 'config.json');
|
|
201
|
+
const content = await readFile(configPath, 'utf-8');
|
|
202
|
+
const config = JSON.parse(content);
|
|
203
|
+
if (config.branchPrefix && typeof config.branchPrefix === 'string') {
|
|
204
|
+
return config.branchPrefix;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
// Config doesn't exist or is invalid — use default
|
|
209
|
+
}
|
|
210
|
+
return 'astro/';
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Resolve the worktree root directory.
|
|
214
|
+
*
|
|
215
|
+
* Creates `{agentDirName}/worktrees/` inside the git root so worktrees live
|
|
216
|
+
* alongside the project (easy access to untracked data files, no bloat in ~/.astro/).
|
|
217
|
+
*
|
|
218
|
+
* Automatically adds `{agentDirName}/worktrees/` and `{agentDirName}/cache/`
|
|
219
|
+
* to the repo's `.gitignore` if missing.
|
|
220
|
+
*
|
|
221
|
+
* Falls back to `~/.astro/worktrees/{repoName}/` if the git root is read-only.
|
|
222
|
+
*/
|
|
223
|
+
async function resolveWorktreeRoot(gitRoot, agentDirName) {
|
|
224
|
+
const worktreesDir = join(gitRoot, agentDirName, 'worktrees');
|
|
225
|
+
try {
|
|
226
|
+
await mkdir(worktreesDir, { recursive: true });
|
|
227
|
+
await ensureGitignoreEntry(gitRoot, `${agentDirName}/worktrees/`);
|
|
228
|
+
await ensureGitignoreEntry(gitRoot, `${agentDirName}/cache/`);
|
|
229
|
+
return worktreesDir;
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
// Git root is read-only — fall back to home dir
|
|
233
|
+
const repoName = sanitize(basename(gitRoot));
|
|
234
|
+
const fallback = join(homedir(), '.astro', 'worktrees', repoName);
|
|
235
|
+
await mkdir(fallback, { recursive: true });
|
|
236
|
+
console.log(`[worktree] Git root read-only, using fallback: ${fallback}`);
|
|
237
|
+
return fallback;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Ensure a pattern is present in the repo's .gitignore.
|
|
242
|
+
* Appends if missing; creates the file if it doesn't exist.
|
|
243
|
+
*/
|
|
244
|
+
async function ensureGitignoreEntry(gitRoot, pattern) {
|
|
245
|
+
const gitignorePath = join(gitRoot, '.gitignore');
|
|
246
|
+
try {
|
|
247
|
+
if (existsSync(gitignorePath)) {
|
|
248
|
+
const content = await readFile(gitignorePath, 'utf-8');
|
|
249
|
+
// Check if already present (exact line match)
|
|
250
|
+
const lines = content.split('\n').map((l) => l.trim());
|
|
251
|
+
if (lines.includes(pattern))
|
|
252
|
+
return;
|
|
253
|
+
// Append with a preceding newline if the file doesn't end with one
|
|
254
|
+
// Only add comment header if not already present in the file
|
|
255
|
+
const prefix = content.endsWith('\n') ? '' : '\n';
|
|
256
|
+
const hasComment = lines.includes('# Astro agent directory');
|
|
257
|
+
const entry = hasComment ? `${prefix}${pattern}\n` : `${prefix}\n# Astro agent directory\n${pattern}\n`;
|
|
258
|
+
await appendFile(gitignorePath, entry);
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
await appendFile(gitignorePath, `# Astro agent directory\n${pattern}\n`);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
// Non-fatal: .gitignore update failed (e.g., permissions)
|
|
266
|
+
console.log(`[worktree] Could not update .gitignore at ${gitignorePath}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Ensure CLAUDE.md is available in the worktree.
|
|
271
|
+
*
|
|
272
|
+
* If CLAUDE.md is tracked by git it will already appear in the worktree
|
|
273
|
+
* automatically. But if it is untracked or gitignored in the source repo
|
|
274
|
+
* we need to copy it explicitly so the agent has access to project
|
|
275
|
+
* instructions inside the isolated worktree.
|
|
276
|
+
*
|
|
277
|
+
* This is intentionally non-fatal: a missing CLAUDE.md should never block
|
|
278
|
+
* task execution.
|
|
279
|
+
*/
|
|
280
|
+
export async function ensureClaudeMdInWorktree(gitRoot, worktreePath) {
|
|
281
|
+
try {
|
|
282
|
+
const sourcePath = join(gitRoot, 'CLAUDE.md');
|
|
283
|
+
const destPath = join(worktreePath, 'CLAUDE.md');
|
|
284
|
+
// Nothing to copy if the source repo doesn't have a CLAUDE.md
|
|
285
|
+
if (!existsSync(sourcePath)) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
// If it already exists in the worktree (i.e. it's tracked by git),
|
|
289
|
+
// there's nothing to do
|
|
290
|
+
if (existsSync(destPath)) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
await copyFile(sourcePath, destPath);
|
|
294
|
+
console.log(`[worktree] Copied CLAUDE.md from ${gitRoot} to ${worktreePath}`);
|
|
295
|
+
}
|
|
296
|
+
catch (err) {
|
|
297
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
298
|
+
console.warn(`[worktree] Failed to copy CLAUDE.md: ${msg}`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Initialize and update git submodules in a worktree.
|
|
303
|
+
*
|
|
304
|
+
* Git worktrees don't automatically init submodules — the directories
|
|
305
|
+
* exist but are empty. We run `git submodule update --init --recursive`
|
|
306
|
+
* to populate them. This is skipped if no .gitmodules file exists.
|
|
307
|
+
*/
|
|
308
|
+
async function initSubmodules(worktreePath, stderr) {
|
|
309
|
+
if (!existsSync(join(worktreePath, '.gitmodules'))) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
console.log(`[worktree] Initializing submodules in ${worktreePath}`);
|
|
313
|
+
try {
|
|
314
|
+
await execFileAsync('git', ['-C', worktreePath, 'submodule', 'update', '--init', '--recursive'], { env: withGitEnv(), timeout: 120_000 });
|
|
315
|
+
}
|
|
316
|
+
catch (err) {
|
|
317
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
318
|
+
stderr?.(`[worktree] Submodule init failed: ${msg}`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
async function getGitRoot(workingDirectory) {
|
|
322
|
+
try {
|
|
323
|
+
const { stdout } = await execFileAsync('git', ['-C', workingDirectory, 'rev-parse', '--show-toplevel'], { env: withGitEnv(), timeout: 5_000 });
|
|
324
|
+
const root = stdout.trim();
|
|
325
|
+
return root ? resolve(root) : null;
|
|
326
|
+
}
|
|
327
|
+
catch {
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
async function ensureBranchAvailable(gitRoot, branchName) {
|
|
332
|
+
try {
|
|
333
|
+
await execFileAsync('git', ['-C', gitRoot, 'branch', '-D', branchName], { env: withGitEnv(), timeout: 10_000 });
|
|
334
|
+
}
|
|
335
|
+
catch {
|
|
336
|
+
// Branch didn't exist — that's fine
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
async function cleanupWorktree(gitRoot, worktreePath, branchName, keepBranch) {
|
|
340
|
+
try {
|
|
341
|
+
await execFileAsync('git', ['-C', gitRoot, 'worktree', 'remove', '--force', worktreePath], { env: withGitEnv(), timeout: 30_000 });
|
|
342
|
+
await execFileAsync('git', ['-C', gitRoot, 'worktree', 'prune'], {
|
|
343
|
+
env: withGitEnv(),
|
|
344
|
+
timeout: 30_000,
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
// Ignore - worktree may already be removed
|
|
349
|
+
}
|
|
350
|
+
try {
|
|
351
|
+
await rm(worktreePath, { recursive: true, force: true });
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
// Ignore - directory may not exist
|
|
355
|
+
}
|
|
356
|
+
// Skip branch deletion when keepBranch is true (e.g., PR was created)
|
|
357
|
+
if (!keepBranch) {
|
|
358
|
+
try {
|
|
359
|
+
await execFileAsync('git', ['-C', gitRoot, 'branch', '-D', branchName], { env: withGitEnv(), timeout: 10_000 });
|
|
360
|
+
}
|
|
361
|
+
catch {
|
|
362
|
+
// Ignore - branch may not exist or already deleted
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
async function pruneWorktrees(gitRoot) {
|
|
367
|
+
try {
|
|
368
|
+
await execFileAsync('git', ['-C', gitRoot, 'worktree', 'prune'], {
|
|
369
|
+
env: withGitEnv(),
|
|
370
|
+
timeout: 30_000,
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
catch {
|
|
374
|
+
// Ignore prune errors
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
async function hasCommits(gitRoot) {
|
|
378
|
+
try {
|
|
379
|
+
await execFileAsync('git', ['-C', gitRoot, 'rev-parse', '--verify', 'HEAD'], {
|
|
380
|
+
env: withGitEnv(),
|
|
381
|
+
timeout: 5_000,
|
|
382
|
+
});
|
|
383
|
+
return true;
|
|
384
|
+
}
|
|
385
|
+
catch {
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Validate that taskId is safe for use in paths.
|
|
391
|
+
* Accepts both UUID format and execution ID format (exec-{uuid-prefix}-{nodeId}-{timestamp}).
|
|
392
|
+
* Command injection is not a risk because we use execFileAsync (not shell),
|
|
393
|
+
* and the sanitize() function handles path safety.
|
|
394
|
+
*/
|
|
395
|
+
function validateTaskId(taskId) {
|
|
396
|
+
// Allow: alphanumeric, hyphens, underscores, dots (same chars as sanitize keeps)
|
|
397
|
+
const safePattern = /^[a-zA-Z0-9._-]+$/;
|
|
398
|
+
if (!safePattern.test(taskId) || taskId.length > 200) {
|
|
399
|
+
throw new Error(`Invalid taskId format: ${taskId}. Must be alphanumeric with hyphens/underscores/dots, max 200 chars.`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
function sanitize(value) {
|
|
403
|
+
return value.replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
404
|
+
}
|
|
405
|
+
function withGitEnv() {
|
|
406
|
+
return {
|
|
407
|
+
...process.env,
|
|
408
|
+
GIT_TERMINAL_PROMPT: '0',
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
//# sourceMappingURL=worktree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../src/lib/worktree.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Bridge module exports
|
|
3
|
+
*/
|
|
4
|
+
export { SessionBridge } from './session-bridge.js';
|
|
5
|
+
export { runMcpServer, getClaudeCodeMcpConfig, getClaudeCodeConfigPath } from './server.js';
|
|
6
|
+
export { ToolHandlers, toolDefinitions } from './tools.js';
|
|
7
|
+
export * from './types.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC3D,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Bridge module exports
|
|
3
|
+
*/
|
|
4
|
+
export { SessionBridge } from './session-bridge.js';
|
|
5
|
+
export { runMcpServer, getClaudeCodeMcpConfig, getClaudeCodeConfigPath } from './server.js';
|
|
6
|
+
export { ToolHandlers, toolDefinitions } from './tools.js';
|
|
7
|
+
export * from './types.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC3D,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Astro MCP Server
|
|
3
|
+
*
|
|
4
|
+
* This MCP server allows existing Claude Code sessions to connect to Astro
|
|
5
|
+
* and link their activity to specific tasks. It uses the stdio transport
|
|
6
|
+
* to communicate with Claude Code.
|
|
7
|
+
*
|
|
8
|
+
* Tools provided:
|
|
9
|
+
* - astro_attach: Attach session to an Astro task
|
|
10
|
+
* - astro_detach: Detach from the current task
|
|
11
|
+
* - astro_status: Check attachment status
|
|
12
|
+
* - astro_send: Send a message/event to Astro
|
|
13
|
+
*/
|
|
14
|
+
export interface McpServerOptions {
|
|
15
|
+
/** Override relay URL (defaults to config) */
|
|
16
|
+
relayUrl?: string;
|
|
17
|
+
/** Override machine ID (defaults to config) */
|
|
18
|
+
machineId?: string;
|
|
19
|
+
/** Override WS token (defaults to config) */
|
|
20
|
+
wsToken?: string;
|
|
21
|
+
/** Log level for console output */
|
|
22
|
+
logLevel?: 'debug' | 'info' | 'warn' | 'error';
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Create and run the Astro MCP server
|
|
26
|
+
*/
|
|
27
|
+
export declare function runMcpServer(options?: McpServerOptions): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Get Claude Code MCP configuration for this server
|
|
30
|
+
*/
|
|
31
|
+
export declare function getClaudeCodeMcpConfig(options?: {
|
|
32
|
+
execPath?: string;
|
|
33
|
+
}): {
|
|
34
|
+
mcpServers: {
|
|
35
|
+
astro: {
|
|
36
|
+
command: string;
|
|
37
|
+
args: string[];
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Get the path to Claude Code's MCP configuration file
|
|
43
|
+
*/
|
|
44
|
+
export declare function getClaudeCodeConfigPath(): string;
|
|
45
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAcH,MAAM,WAAW,gBAAgB;IAC/B,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;CAChD;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6HhF;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG;IAC3E,UAAU,EAAE;QACV,KAAK,EAAE;YACL,OAAO,EAAE,MAAM,CAAC;YAChB,IAAI,EAAE,MAAM,EAAE,CAAC;SAChB,CAAC;KACH,CAAC;CACH,CAaA;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAGhD"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Astro MCP Server
|
|
3
|
+
*
|
|
4
|
+
* This MCP server allows existing Claude Code sessions to connect to Astro
|
|
5
|
+
* and link their activity to specific tasks. It uses the stdio transport
|
|
6
|
+
* to communicate with Claude Code.
|
|
7
|
+
*
|
|
8
|
+
* Tools provided:
|
|
9
|
+
* - astro_attach: Attach session to an Astro task
|
|
10
|
+
* - astro_detach: Detach from the current task
|
|
11
|
+
* - astro_status: Check attachment status
|
|
12
|
+
* - astro_send: Send a message/event to Astro
|
|
13
|
+
*/
|
|
14
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
15
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
16
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
17
|
+
import { SessionBridge } from './session-bridge.js';
|
|
18
|
+
import { ToolHandlers, toolDefinitions } from './tools.js';
|
|
19
|
+
import { config as appConfig } from '../lib/config.js';
|
|
20
|
+
/**
|
|
21
|
+
* Create and run the Astro MCP server
|
|
22
|
+
*/
|
|
23
|
+
export async function runMcpServer(options = {}) {
|
|
24
|
+
const logLevel = options.logLevel ?? 'info';
|
|
25
|
+
const log = (level, ...args) => {
|
|
26
|
+
const levels = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
27
|
+
if (levels[level] >= levels[logLevel]) {
|
|
28
|
+
console.error(`[astro-mcp] [${level}]`, ...args);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
// Get configuration from stored config or options
|
|
32
|
+
const bridgeConfig = {
|
|
33
|
+
relayUrl: options.relayUrl ?? appConfig.getRelayUrl(),
|
|
34
|
+
machineId: options.machineId ?? appConfig.getMachineId(),
|
|
35
|
+
wsToken: options.wsToken ?? appConfig.getWsToken(),
|
|
36
|
+
autoReconnect: true,
|
|
37
|
+
};
|
|
38
|
+
log('info', 'Starting Astro MCP server...');
|
|
39
|
+
log('debug', 'Config:', {
|
|
40
|
+
relayUrl: bridgeConfig.relayUrl,
|
|
41
|
+
machineId: bridgeConfig.machineId,
|
|
42
|
+
hasWsToken: !!bridgeConfig.wsToken,
|
|
43
|
+
});
|
|
44
|
+
// Create session bridge
|
|
45
|
+
const bridge = new SessionBridge(bridgeConfig);
|
|
46
|
+
// Set up bridge event logging
|
|
47
|
+
bridge.onEvent((event) => {
|
|
48
|
+
switch (event.type) {
|
|
49
|
+
case 'connected':
|
|
50
|
+
log('info', 'Connected to Astro relay');
|
|
51
|
+
break;
|
|
52
|
+
case 'disconnected':
|
|
53
|
+
log('info', 'Disconnected from Astro relay:', event.data);
|
|
54
|
+
break;
|
|
55
|
+
case 'attached':
|
|
56
|
+
log('info', 'Attached to task:', event.data);
|
|
57
|
+
break;
|
|
58
|
+
case 'detached':
|
|
59
|
+
log('info', 'Detached from task:', event.data);
|
|
60
|
+
break;
|
|
61
|
+
case 'event_sent':
|
|
62
|
+
log('debug', 'Event sent:', event.data);
|
|
63
|
+
break;
|
|
64
|
+
case 'error':
|
|
65
|
+
log('error', 'Bridge error:', event.error?.message);
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
// Create tool handlers
|
|
70
|
+
const toolHandlers = new ToolHandlers(bridge);
|
|
71
|
+
// Create MCP server
|
|
72
|
+
const server = new Server({
|
|
73
|
+
name: 'astro-mcp-bridge',
|
|
74
|
+
version: '0.1.0',
|
|
75
|
+
}, {
|
|
76
|
+
capabilities: {
|
|
77
|
+
tools: {},
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
// Handle ListTools request
|
|
81
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
82
|
+
return {
|
|
83
|
+
tools: toolDefinitions,
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
// Handle CallTool request
|
|
87
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
88
|
+
const { name, arguments: args } = request.params;
|
|
89
|
+
log('debug', `Tool called: ${name}`, args);
|
|
90
|
+
try {
|
|
91
|
+
const result = await toolHandlers.handleToolCall(name, args ?? {});
|
|
92
|
+
return {
|
|
93
|
+
content: [
|
|
94
|
+
{
|
|
95
|
+
type: 'text',
|
|
96
|
+
text: JSON.stringify(result, null, 2),
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
log('error', `Tool ${name} error:`, error);
|
|
103
|
+
return {
|
|
104
|
+
content: [
|
|
105
|
+
{
|
|
106
|
+
type: 'text',
|
|
107
|
+
text: JSON.stringify({
|
|
108
|
+
success: false,
|
|
109
|
+
message: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
110
|
+
}),
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
isError: true,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
// Handle graceful shutdown
|
|
118
|
+
const cleanup = () => {
|
|
119
|
+
log('info', 'Shutting down...');
|
|
120
|
+
bridge.disconnect();
|
|
121
|
+
process.exit(0);
|
|
122
|
+
};
|
|
123
|
+
process.on('SIGINT', cleanup);
|
|
124
|
+
process.on('SIGTERM', cleanup);
|
|
125
|
+
// Start the server using stdio transport
|
|
126
|
+
const transport = new StdioServerTransport();
|
|
127
|
+
await server.connect(transport);
|
|
128
|
+
log('info', 'Astro MCP server started on stdio');
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get Claude Code MCP configuration for this server
|
|
132
|
+
*/
|
|
133
|
+
export function getClaudeCodeMcpConfig(options = {}) {
|
|
134
|
+
// Default to using npx to run the CLI
|
|
135
|
+
const command = options.execPath ?? 'npx';
|
|
136
|
+
const args = options.execPath ? ['mcp'] : ['@astro/agent', 'mcp'];
|
|
137
|
+
return {
|
|
138
|
+
mcpServers: {
|
|
139
|
+
astro: {
|
|
140
|
+
command,
|
|
141
|
+
args,
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get the path to Claude Code's MCP configuration file
|
|
148
|
+
*/
|
|
149
|
+
export function getClaudeCodeConfigPath() {
|
|
150
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? '';
|
|
151
|
+
return `${home}/.claude/mcp_servers.json`;
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=server.js.map
|