@iflow-mcp/camoneart-maestro 5.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/CHANGELOG.md +949 -0
- package/LICENSE +21 -0
- package/README.ja.md +550 -0
- package/README.md +576 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +7407 -0
- package/dist/cli.js.map +1 -0
- package/dist/mcp/server.d.ts +28 -0
- package/dist/mcp/server.js +847 -0
- package/dist/mcp/server.js.map +1 -0
- package/package.json +93 -0
- package/scripts/generate-completions.js +51 -0
- package/scripts/maestro-tmux-attach +101 -0
- package/scripts/update-scoop-manifest.js +80 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/mcp/server.ts","../../src/core/git.ts","../../src/core/config.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'\n\n// テスト環境では早期リターンしてprocess.exitを避ける\nconst isTestEnvironment = process.env.NODE_ENV === 'test'\nimport { z } from 'zod'\nimport { GitWorktreeManager } from '../core/git.js'\nimport { readFileSync } from 'fs'\nimport { fileURLToPath } from 'url'\nimport { dirname, join } from 'path'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\nconst packageJson = JSON.parse(readFileSync(join(__dirname, '../../package.json'), 'utf-8'))\n\n// ツールのスキーマ定義\nconst CreateWorktreeArgsSchema = z.object({\n branchName: z.string().describe('作成するブランチ名'),\n baseBranch: z.string().optional().describe('ベースブランチ(省略時は現在のブランチ)'),\n})\n\nconst DeleteWorktreeArgsSchema = z.object({\n branchName: z.string().describe('削除するブランチ名'),\n force: z.boolean().optional().describe('強制削除フラグ'),\n})\n\nconst ExecInWorktreeArgsSchema = z.object({\n branchName: z.string().describe('実行対象のブランチ名'),\n command: z.string().describe('実行するコマンド'),\n})\n\n// MCPサーバーの作成\nconst server = new Server(\n {\n name: 'maestro',\n version: packageJson.version,\n },\n {\n capabilities: {\n tools: {},\n },\n }\n)\n\n// GitWorktreeManagerのインスタンス\nconst gitManager = new GitWorktreeManager()\n\n// ツール定義\nconst TOOLS = [\n {\n name: 'create_orchestra_member',\n description: '新しい演奏者(Git worktree)を招集する',\n inputSchema: {\n type: 'object',\n properties: {\n branchName: {\n type: 'string',\n description: '作成するブランチ名',\n },\n baseBranch: {\n type: 'string',\n description: 'ベースブランチ(省略時は現在のブランチ)',\n },\n },\n required: ['branchName'],\n },\n },\n {\n name: 'list_orchestra_members',\n description: 'すべての演奏者(Git worktree)を一覧表示',\n inputSchema: {\n type: 'object',\n properties: {},\n },\n },\n {\n name: 'delete_orchestra_member',\n description: '演奏者(Git worktree)を解散',\n inputSchema: {\n type: 'object',\n properties: {\n branchName: {\n type: 'string',\n description: '削除するブランチ名',\n },\n force: {\n type: 'boolean',\n description: '強制削除フラグ',\n },\n },\n required: ['branchName'],\n },\n },\n {\n name: 'exec_in_orchestra_member',\n description: '演奏者でコマンドを実行',\n inputSchema: {\n type: 'object',\n properties: {\n branchName: {\n type: 'string',\n description: '実行対象のブランチ名',\n },\n command: {\n type: 'string',\n description: '実行するコマンド',\n },\n },\n required: ['branchName', 'command'],\n },\n },\n]\n\n// ツール一覧のハンドラー\nif (!isTestEnvironment) {\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n return {\n tools: TOOLS,\n }\n })\n}\n\n// ツール実行のハンドラー\nif (!isTestEnvironment) {\n server.setRequestHandler(CallToolRequestSchema, async request => {\n const { name, arguments: args } = request.params\n\n try {\n switch (name) {\n case 'create_orchestra_member': {\n const validatedArgs = CreateWorktreeArgsSchema.parse(args)\n const worktreePath = await gitManager.createWorktree(\n validatedArgs.branchName,\n validatedArgs.baseBranch\n )\n return {\n content: [\n {\n type: 'text',\n text: `✅ 演奏者 '${validatedArgs.branchName}' を招集しました!\\n📁 ${worktreePath}`,\n },\n ],\n }\n }\n\n case 'list_orchestra_members': {\n const worktrees = await gitManager.listWorktrees()\n const orchestraMembers = worktrees.filter(wt => !wt.path.endsWith('.'))\n\n const list = orchestraMembers\n .map(wt => {\n const branchName = wt.branch?.replace('refs/heads/', '') || wt.branch\n return `• ${branchName} (${wt.path})`\n })\n .join('\\n')\n\n return {\n content: [\n {\n type: 'text',\n text:\n orchestraMembers.length > 0\n ? `🎼 オーケストラ編成(worktree):\\n${list}\\n\\n合計: ${orchestraMembers.length} 名の演奏者`\n : '演奏者が存在しません',\n },\n ],\n }\n }\n\n case 'delete_orchestra_member': {\n const validatedArgs = DeleteWorktreeArgsSchema.parse(args)\n await gitManager.deleteWorktree(validatedArgs.branchName, validatedArgs.force)\n return {\n content: [\n {\n type: 'text',\n text: `✅ 演奏者 '${validatedArgs.branchName}' を解散しました`,\n },\n ],\n }\n }\n\n case 'exec_in_orchestra_member': {\n const validatedArgs = ExecInWorktreeArgsSchema.parse(args)\n const { execa } = await import('execa')\n\n const worktrees = await gitManager.listWorktrees()\n const targetWorktree = worktrees.find(wt => {\n const branch = wt.branch?.replace('refs/heads/', '')\n return branch === validatedArgs.branchName || wt.branch === validatedArgs.branchName\n })\n\n if (!targetWorktree) {\n throw new Error(`演奏者 '${validatedArgs.branchName}' が見つかりません`)\n }\n\n const result = await execa('sh', ['-c', validatedArgs.command], {\n cwd: targetWorktree.path,\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `📍 ${validatedArgs.branchName} で実行: ${validatedArgs.command}\\n\\n${result.stdout}`,\n },\n ],\n }\n }\n\n default:\n throw new Error(`不明なツール: ${name}`)\n }\n } catch (error) {\n return {\n content: [\n {\n type: 'text',\n text: `❌ エラー: ${error instanceof Error ? error.message : '不明なエラー'}`,\n },\n ],\n }\n }\n })\n}\n\n// サーバーの起動\nasync function main() {\n const transport = new StdioServerTransport()\n await server.connect(transport)\n console.error('🎼 Maestro MCP server started')\n}\n\nif (!isTestEnvironment) {\n main().catch(error => {\n console.error('Fatal error:', error)\n process.exit(1)\n })\n}\n\n// テスト用にserverをエクスポート\nexport { server }\n","import simpleGit, { SimpleGit } from 'simple-git'\nimport { Worktree } from '../types/index.js'\nimport { ConfigManager } from './config.js'\nimport path from 'path'\nimport fs from 'fs/promises'\nimport chalk from 'chalk'\nimport inquirer from 'inquirer'\n\nexport class GitWorktreeManager {\n private git: SimpleGit\n private configManager: ConfigManager\n\n constructor(baseDir?: string) {\n this.git = simpleGit(baseDir || process.cwd())\n this.configManager = new ConfigManager()\n }\n\n async createWorktree(\n branchName: string,\n baseBranch?: string,\n skipDirCheck?: boolean\n ): Promise<string> {\n // ブランチ名の衝突をチェック\n await this.checkBranchNameCollision(branchName)\n\n // 設定を読み込み\n await this.configManager.loadProjectConfig()\n const worktreeConfig = this.configManager.get('worktrees')\n const directoryPrefix = worktreeConfig?.directoryPrefix || ''\n\n // リポジトリルートを取得して絶対パスを生成\n const repoRoot = await this.getRepositoryRoot()\n const worktreePath = path.join(repoRoot, '..', `${directoryPrefix}${branchName}`)\n\n // ディレクトリの存在をチェック(スキップオプションが false の場合のみ)\n if (!skipDirCheck) {\n const dirExists = await this.checkDirectoryExists(worktreePath)\n if (dirExists) {\n const action = await this.handleExistingDirectory(worktreePath, branchName)\n\n if (action === 'cancel') {\n throw new Error('ワークツリーの作成がキャンセルされました')\n } else if (action === 'rename') {\n // 別名を生成して再帰的に呼び出し\n const branches = await this.getAllBranches()\n const allBranches = [\n ...branches.local,\n ...branches.remote.map(r => r.replace(/^[^/]+\\//, '')),\n ]\n const alternativeName = this.generateAlternativeBranchName(branchName, allBranches)\n console.log(chalk.yellow(`\\n新しいブランチ名: ${alternativeName}`))\n return this.createWorktree(alternativeName, baseBranch, true)\n } else if (action === 'delete') {\n // ディレクトリを削除\n await fs.rm(worktreePath, { recursive: true, force: true })\n console.log(\n chalk.gray(`🗑️ 既存ディレクトリを削除しました: ${path.basename(worktreePath)}`)\n )\n }\n }\n }\n\n // ベースブランチが指定されていない場合は現在のブランチを使用\n if (!baseBranch) {\n const status = await this.git.status()\n baseBranch = status.current || 'main'\n }\n\n // ワークツリーを作成\n await this.git.raw(['worktree', 'add', '-b', branchName, worktreePath, baseBranch])\n\n return path.resolve(worktreePath)\n }\n\n async attachWorktree(existingBranch: string, skipDirCheck?: boolean): Promise<string> {\n // 設定を読み込み\n await this.configManager.loadProjectConfig()\n const worktreeConfig = this.configManager.get('worktrees')\n const directoryPrefix = worktreeConfig?.directoryPrefix || ''\n\n // リポジトリルートを取得して絶対パスを生成\n const repoRoot = await this.getRepositoryRoot()\n // ワークツリーのパスを生成(ブランチ名からスラッシュを置換)\n const safeBranchName = existingBranch.replace(/\\//g, '-')\n const worktreePath = path.join(repoRoot, '..', `${directoryPrefix}${safeBranchName}`)\n\n // ディレクトリの存在をチェック(スキップオプションが false の場合のみ)\n if (!skipDirCheck) {\n const dirExists = await this.checkDirectoryExists(worktreePath)\n if (dirExists) {\n const action = await this.handleExistingDirectory(worktreePath, safeBranchName)\n\n if (action === 'cancel') {\n throw new Error('ワークツリーの作成がキャンセルされました')\n } else if (action === 'rename') {\n // 別名を生成して再帰的に呼び出し\n const branches = await this.getAllBranches()\n const allBranches = [\n ...branches.local,\n ...branches.remote.map(r => r.replace(/^[^/]+\\//, '')),\n ]\n const alternativeName = this.generateAlternativeBranchName(safeBranchName, allBranches)\n const newWorktreePath = path.join(repoRoot, '..', `${directoryPrefix}${alternativeName}`)\n console.log(chalk.yellow(`\\n新しいディレクトリ名: ${alternativeName}`))\n\n // 別名のディレクトリでワークツリーを作成\n await this.git.raw(['worktree', 'add', newWorktreePath, existingBranch])\n return path.resolve(newWorktreePath)\n } else if (action === 'delete') {\n // ディレクトリを削除\n await fs.rm(worktreePath, { recursive: true, force: true })\n console.log(\n chalk.gray(`🗑️ 既存ディレクトリを削除しました: ${path.basename(worktreePath)}`)\n )\n }\n }\n }\n\n // 既存のブランチでワークツリーを作成\n await this.git.raw(['worktree', 'add', worktreePath, existingBranch])\n\n return path.resolve(worktreePath)\n }\n\n async listWorktrees(): Promise<Worktree[]> {\n const output = await this.git.raw(['worktree', 'list', '--porcelain'])\n const worktrees: Worktree[] = []\n\n const lines = output.split('\\n').filter(line => line.trim())\n let currentWorktree: Partial<Worktree> = {}\n\n for (const line of lines) {\n if (line.startsWith('worktree ')) {\n if (currentWorktree.path) {\n worktrees.push(currentWorktree as Worktree)\n }\n currentWorktree = {\n path: line.substring(9),\n detached: false,\n prunable: false,\n locked: false,\n }\n } else if (line.startsWith('HEAD ')) {\n currentWorktree.head = line.substring(5)\n } else if (line.startsWith('branch ')) {\n currentWorktree.branch = line.substring(7)\n } else if (line === 'detached') {\n currentWorktree.detached = true\n } else if (line === 'prunable') {\n currentWorktree.prunable = true\n } else if (line.startsWith('locked')) {\n currentWorktree.locked = true\n if (line.includes(' ')) {\n currentWorktree.reason = line.substring(line.indexOf(' ') + 1)\n }\n }\n }\n\n if (currentWorktree.path) {\n worktrees.push(currentWorktree as Worktree)\n }\n\n return worktrees\n }\n\n async deleteWorktree(branchName: string, force: boolean = false): Promise<void> {\n const worktrees = await this.listWorktrees()\n const worktree = worktrees.find(wt => {\n // refs/heads/プレフィックスを除去して比較\n const branch = wt.branch?.replace('refs/heads/', '')\n return branch === branchName\n })\n\n if (!worktree) {\n throw new Error(`ワークツリー '${branchName}' が見つかりません`)\n }\n\n // ワークツリーを削除\n const args = ['worktree', 'remove']\n if (force) args.push('--force')\n args.push(worktree.path)\n\n await this.git.raw(args)\n\n // Cleanup empty directories\n await this.cleanupEmptyDirectories(worktree.path)\n\n // Delete local branch as well\n try {\n await this.git.branch(['-d', branchName])\n } catch (error) {\n // If -d fails, try force delete with -D\n if (error instanceof Error && error.message.includes('not fully merged')) {\n await this.git.branch(['-D', branchName])\n } else {\n throw error\n }\n }\n }\n\n async getCurrentBranch(): Promise<string | null> {\n const status = await this.git.status()\n return status.current\n }\n\n async isGitRepository(): Promise<boolean> {\n try {\n await this.git.status()\n return true\n } catch {\n return false\n }\n }\n\n async getAllBranches(): Promise<{ local: string[]; remote: string[] }> {\n const localBranches = await this.git.branchLocal()\n const remoteBranches = await this.git.branch(['-r'])\n\n return {\n local: localBranches.all.filter(b => !b.startsWith('remotes/')),\n remote: remoteBranches.all\n .filter(b => b.startsWith('remotes/'))\n .map(b => b.replace('remotes/', '')),\n }\n }\n\n async listLocalBranches(): Promise<string[]> {\n const localBranches = await this.git.branchLocal()\n return localBranches.all.filter(b => !b.startsWith('remotes/'))\n }\n\n async fetchAll(): Promise<void> {\n await this.git.fetch(['--all'])\n }\n\n async getLastCommit(\n worktreePath: string\n ): Promise<{ date: string; message: string; hash: string } | null> {\n try {\n const gitInWorktree = simpleGit(worktreePath)\n const log = await gitInWorktree.log({ maxCount: 1 })\n\n if (log.latest) {\n return {\n date: log.latest.date,\n message: log.latest.message,\n hash: log.latest.hash.substring(0, 7),\n }\n }\n return null\n } catch {\n return null\n }\n }\n\n async getRepositoryRoot(): Promise<string> {\n try {\n const output = await this.git.raw(['rev-parse', '--show-toplevel'])\n return output.trim()\n } catch {\n throw new Error('リポジトリルートの取得に失敗しました')\n }\n }\n\n async isGitignored(filePath: string): Promise<boolean> {\n try {\n // git check-ignore returns 0 if the file is ignored\n await this.git.raw(['check-ignore', filePath])\n return true\n } catch {\n // Non-zero exit code means the file is not ignored\n return false\n }\n }\n\n async checkBranchNameCollision(branchName: string): Promise<void> {\n const branches = await this.getAllBranches()\n const allBranches = [...branches.local, ...branches.remote.map(r => r.replace(/^[^/]+\\//, ''))]\n\n // 完全一致のチェック\n if (allBranches.includes(branchName)) {\n throw new Error(`ブランチ '${branchName}' は既に存在します`)\n }\n\n // プレフィックス衝突のチェック(新しいブランチが既存ブランチのプレフィックスになる場合)\n const conflictingBranches = allBranches.filter(existing =>\n existing.startsWith(branchName + '/')\n )\n\n if (conflictingBranches.length > 0) {\n const examples = conflictingBranches.slice(0, 3).join(', ')\n throw new Error(\n `ブランチ '${branchName}' を作成できません。以下の既存ブランチと競合します: ${examples}${\n conflictingBranches.length > 3 ? ` など (${conflictingBranches.length}件)` : ''\n }`\n )\n }\n\n // 逆方向の衝突チェック(既存ブランチが新しいブランチのプレフィックスになる場合)\n const parentConflicts = allBranches.filter(existing => branchName.startsWith(existing + '/'))\n\n if (parentConflicts.length > 0) {\n const examples = parentConflicts.slice(0, 3).join(', ')\n throw new Error(\n `ブランチ '${branchName}' を作成できません。以下の既存ブランチのサブブランチになります: ${examples}${\n parentConflicts.length > 3 ? ` など (${parentConflicts.length}件)` : ''\n }`\n )\n }\n }\n\n generateAlternativeBranchName(originalName: string, allBranches: string[]): string {\n let counter = 1\n let alternativeName = `${originalName}-${counter}`\n\n while (\n allBranches.includes(alternativeName) ||\n allBranches.some(\n b => b.startsWith(alternativeName + '/') || alternativeName.startsWith(b + '/')\n )\n ) {\n counter++\n alternativeName = `${originalName}-${counter}`\n }\n\n return alternativeName\n }\n\n private async cleanupEmptyDirectories(worktreePath: string): Promise<void> {\n const repoRoot = await this.getRepositoryRoot()\n const baseDir = path.join(repoRoot, '..')\n let currentDir = path.dirname(worktreePath)\n\n // Recursively remove empty directories up to base directory\n while (currentDir !== baseDir && currentDir !== path.dirname(currentDir)) {\n try {\n const entries = await fs.readdir(currentDir)\n if (entries.length === 0) {\n await fs.rmdir(currentDir)\n console.log(chalk.gray(`🧹 Removed empty directory: ${path.basename(currentDir)}`))\n currentDir = path.dirname(currentDir)\n } else {\n break // Stop if directory is not empty\n }\n } catch {\n break // Stop on error\n }\n }\n }\n\n private async checkDirectoryExists(dirPath: string): Promise<boolean> {\n try {\n const stats = await fs.stat(dirPath)\n return stats.isDirectory()\n } catch {\n return false\n }\n }\n\n private async handleExistingDirectory(\n dirPath: string,\n branchName: string\n ): Promise<'delete' | 'rename' | 'cancel'> {\n const repoRoot = await this.getRepositoryRoot()\n const relativePath = path.relative(repoRoot, dirPath)\n console.log(chalk.yellow(`\\n⚠️ ディレクトリ '${relativePath}' は既に存在します`))\n\n const choices = [\n { name: '既存ディレクトリを削除して新規作成', value: 'delete' },\n { name: `別の名前を使用(${branchName}-2など)`, value: 'rename' },\n { name: 'キャンセル', value: 'cancel' },\n ]\n\n const answer = await inquirer.prompt([\n {\n type: 'list',\n name: 'action',\n message: 'どのように処理しますか?',\n choices,\n },\n ])\n\n return answer.action\n }\n}\n","import { z } from 'zod'\nimport Conf from 'conf'\nimport path from 'path'\nimport fs from 'fs/promises'\n\n// 設定ファイルのスキーマ定義\nexport const ConfigSchema = z.object({\n // Git worktree設定\n worktrees: z\n .object({\n // worktreeを作成するディレクトリ(デフォルト: .git/orchestrations)\n path: z.string().optional(),\n // ブランチ名のプレフィックス\n branchPrefix: z.string().optional(),\n // ディレクトリ名のプレフィックス(デフォルト: 空文字列)\n directoryPrefix: z.string().optional(),\n })\n .optional(),\n\n // 開発環境設定\n development: z\n .object({\n // 自動でnpm installを実行\n autoSetup: z.boolean().default(true),\n // 同期するファイル(.envなど)\n syncFiles: z.array(z.string()).default(['.env', '.env.local']),\n // デフォルトのエディタ\n defaultEditor: z.enum(['vscode', 'cursor', 'none']).default('cursor'),\n })\n .optional(),\n\n // tmux統合設定\n tmux: z\n .object({\n enabled: z.boolean().default(false),\n // 新規ウィンドウかペインか\n openIn: z.enum(['window', 'pane']).default('window'),\n // セッション名の命名規則\n sessionNaming: z.string().default('{branch}'),\n })\n .optional(),\n\n // Claude Code統合設定\n claude: z\n .object({\n // CLAUDE.mdの処理方法\n markdownMode: z.enum(['shared', 'split']).default('shared'),\n })\n .optional(),\n\n // GitHub統合設定\n github: z\n .object({\n // 自動でfetchを実行\n autoFetch: z.boolean().default(true),\n // ブランチ命名規則\n branchNaming: z\n .object({\n // PR用のテンプレート (例: \"pr-{number}-{title}\")\n prTemplate: z.string().default('pr-{number}'),\n // Issue用のテンプレート (例: \"issue-{number}-{title}\")\n issueTemplate: z.string().default('issue-{number}'),\n })\n .optional(),\n })\n .optional(),\n\n // UI表示設定\n ui: z\n .object({\n // パス表示形式 ('absolute' | 'relative')\n pathDisplay: z.enum(['absolute', 'relative']).default('absolute'),\n })\n .optional(),\n\n // カスタムコマンドとファイルコピー設定\n hooks: z\n .object({\n // worktree作成後に実行(文字列または配列)\n afterCreate: z.union([z.string(), z.array(z.string())]).optional(),\n // worktree削除前に実行\n beforeDelete: z.string().optional(),\n })\n .optional(),\n\n // worktree作成時の処理\n postCreate: z\n .object({\n // コピーするファイル(gitignoreファイルも含む)\n copyFiles: z.array(z.string()).optional(),\n // 実行するコマンド\n commands: z.array(z.string()).optional(),\n })\n .optional(),\n})\n\nexport type Config = z.infer<typeof ConfigSchema>\n\n// デフォルト設定\nconst DEFAULT_CONFIG: Config = {\n worktrees: {\n path: '../maestro-{branch}',\n directoryPrefix: '',\n },\n development: {\n autoSetup: true,\n syncFiles: ['.env', '.env.local'],\n defaultEditor: 'cursor',\n },\n tmux: {\n enabled: false,\n openIn: 'window',\n sessionNaming: '{branch}',\n },\n claude: {\n markdownMode: 'shared',\n },\n github: {\n autoFetch: true,\n },\n ui: {\n pathDisplay: 'absolute',\n },\n hooks: {},\n}\n\nexport class ConfigManager {\n private conf: Conf<Config>\n private projectConfig: Config | null = null\n private userConfig: Config | null = null\n\n constructor() {\n // グローバル設定(ユーザーホーム)\n this.conf = new Conf<Config>({\n projectName: 'maestro',\n defaults: DEFAULT_CONFIG,\n })\n }\n\n async loadProjectConfig(): Promise<void> {\n try {\n // ユーザー設定ファイル(.maestro.local.json)を先に読み込む\n await this.loadUserConfig()\n\n // プロジェクトルートの設定ファイルを探す\n const configPaths = [\n path.join(process.cwd(), '.maestro.json'),\n path.join(process.cwd(), '.maestrorc.json'),\n path.join(process.cwd(), 'maestro.config.json'),\n // グローバル設定ファイル\n path.join(process.env.HOME || '~', '.maestrorc'),\n path.join(process.env.HOME || '~', '.maestrorc.json'),\n ]\n\n for (const configPath of configPaths) {\n try {\n const configData = await fs.readFile(configPath, 'utf-8')\n const parsedConfig = JSON.parse(configData)\n this.projectConfig = ConfigSchema.parse(parsedConfig)\n return\n } catch {\n // ファイルが存在しない場合は次を試す\n }\n }\n } catch (error) {\n console.error('プロジェクト設定の読み込みに失敗しました:', error)\n }\n }\n\n async loadUserConfig(): Promise<void> {\n try {\n const userConfigPath = path.join(process.cwd(), '.maestro.local.json')\n const configData = await fs.readFile(userConfigPath, 'utf-8')\n const parsedConfig = JSON.parse(configData)\n this.userConfig = ConfigSchema.parse(parsedConfig)\n } catch {\n // ユーザー設定ファイルが存在しない場合は無視\n this.userConfig = null\n }\n }\n\n // 設定を取得(ユーザー設定 > プロジェクト設定 > グローバル設定 > デフォルト)\n get<K extends keyof Config>(key: K): Config[K] {\n if (this.userConfig && this.userConfig[key] !== undefined) {\n return this.userConfig[key]\n }\n if (this.projectConfig && this.projectConfig[key] !== undefined) {\n return this.projectConfig[key]\n }\n return this.conf.get(key) ?? DEFAULT_CONFIG[key]\n }\n\n // 設定を更新(グローバル設定のみ)\n set<K extends keyof Config>(key: K, value: Config[K]): void {\n this.conf.set(key, value)\n }\n\n // 全設定を取得\n getAll(): Config {\n const globalConfig = this.conf.store\n return {\n ...DEFAULT_CONFIG,\n ...globalConfig,\n ...(this.projectConfig || {}),\n ...(this.userConfig || {}),\n }\n }\n\n // 設定ファイルのパスを取得\n getConfigPath(): string {\n return this.conf.path\n }\n\n // ドット記法で設定値を取得\n getConfigValue(keyPath: string): unknown {\n const keys = keyPath.split('.')\n const config = this.getAll()\n\n return keys.reduce((obj: unknown, key: string) => {\n if (obj && typeof obj === 'object' && key in obj) {\n return (obj as Record<string, unknown>)[key]\n }\n return undefined\n }, config as unknown)\n }\n\n // ドット記法で設定値を設定\n async setConfigValue(\n keyPath: string,\n value: unknown,\n target: 'user' | 'project' = 'project'\n ): Promise<void> {\n if (target === 'user') {\n await this.setUserConfigValue(keyPath, value)\n } else {\n await this.setProjectConfigValue(keyPath, value)\n }\n }\n\n // ユーザー設定を設定\n async setUserConfigValue(keyPath: string, value: unknown): Promise<void> {\n const configPath = path.join(process.cwd(), '.maestro.local.json')\n\n // 既存のユーザー設定を読み込む\n let userConfig: Record<string, unknown> = {}\n try {\n const configData = await fs.readFile(configPath, 'utf-8')\n userConfig = JSON.parse(configData)\n } catch {\n // ファイルが存在しない場合は空のオブジェクトから開始\n }\n\n // ドット記法でネストしたオブジェクトを作成\n const keys = keyPath.split('.')\n let current = userConfig\n\n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i]\n if (!key) continue\n if (!current[key] || typeof current[key] !== 'object') {\n current[key] = {}\n }\n current = current[key] as Record<string, unknown>\n }\n\n // 値の型変換\n const lastKey = keys[keys.length - 1]\n if (lastKey) {\n current[lastKey] = this.parseValue(value)\n }\n\n // バリデーション\n const validatedConfig = ConfigSchema.parse(userConfig)\n\n // ファイルに保存\n await fs.writeFile(configPath, JSON.stringify(validatedConfig, null, 2) + '\\n', 'utf-8')\n\n // メモリ上の設定も更新\n this.userConfig = validatedConfig\n }\n\n // プロジェクト設定を設定\n async setProjectConfigValue(keyPath: string, value: unknown): Promise<void> {\n const configPath = path.join(process.cwd(), '.maestro.json')\n\n // 既存のプロジェクト設定を読み込む\n let projectConfig: Record<string, unknown> = {}\n try {\n const configData = await fs.readFile(configPath, 'utf-8')\n projectConfig = JSON.parse(configData)\n } catch {\n // ファイルが存在しない場合は空のオブジェクトから開始\n }\n\n // ドット記法でネストしたオブジェクトを作成\n const keys = keyPath.split('.')\n let current = projectConfig\n\n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i]\n if (!key) continue\n if (!current[key] || typeof current[key] !== 'object') {\n current[key] = {}\n }\n current = current[key] as Record<string, unknown>\n }\n\n // 値の型変換\n const lastKey = keys[keys.length - 1]\n if (lastKey) {\n current[lastKey] = this.parseValue(value)\n }\n\n // バリデーション\n const validatedConfig = ConfigSchema.parse(projectConfig)\n\n // ファイルに保存\n await fs.writeFile(configPath, JSON.stringify(validatedConfig, null, 2) + '\\n', 'utf-8')\n\n // メモリ上の設定も更新\n this.projectConfig = validatedConfig\n }\n\n // 設定値をリセット(デフォルトに戻す)\n async resetConfigValue(keyPath: string): Promise<void> {\n const configPath = path.join(process.cwd(), '.maestro.json')\n\n // 既存のプロジェクト設定を読み込む\n let projectConfig: Record<string, unknown> = {}\n try {\n const configData = await fs.readFile(configPath, 'utf-8')\n projectConfig = JSON.parse(configData)\n } catch {\n // ファイルが存在しない場合は何もしない\n return\n }\n\n // ドット記法でキーを削除\n const keys = keyPath.split('.')\n let current = projectConfig\n const parents: Array<{ obj: Record<string, unknown>; key: string }> = []\n\n // パスをたどって削除対象を見つける\n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i]\n if (!key || !current[key]) {\n return // キーが存在しない場合は何もしない\n }\n parents.push({ obj: current, key })\n current = current[key] as Record<string, unknown>\n }\n\n const lastKey = keys[keys.length - 1]\n if (lastKey && current[lastKey] !== undefined) {\n delete current[lastKey]\n }\n\n // 空のオブジェクトを削除\n this.cleanEmptyObjects(projectConfig, keyPath.split('.').slice(0, -1))\n\n // ファイルに保存\n await fs.writeFile(configPath, JSON.stringify(projectConfig, null, 2) + '\\n', 'utf-8')\n\n // メモリ上の設定も更新\n this.projectConfig = Object.keys(projectConfig).length > 0 ? projectConfig : null\n }\n\n // 値の型変換\n private parseValue(value: unknown): unknown {\n if (typeof value === 'string') {\n // boolean値の変換\n if (value === 'true') return true\n if (value === 'false') return false\n\n // 数値の変換\n if (/^\\d+$/.test(value)) return parseInt(value, 10)\n if (/^\\d+\\.\\d+$/.test(value)) return parseFloat(value)\n }\n\n return value\n }\n\n // 空のオブジェクトを削除\n private cleanEmptyObjects(obj: Record<string, unknown>, keys: string[]): void {\n if (keys.length === 0) return\n\n let current = obj\n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i]\n if (!key || !current[key]) return\n current = current[key] as Record<string, unknown>\n }\n\n const lastKey = keys[keys.length - 1]\n if (\n lastKey &&\n current[lastKey] &&\n typeof current[lastKey] === 'object' &&\n Object.keys(current[lastKey] as Record<string, unknown>).length === 0\n ) {\n delete current[lastKey]\n // 再帰的にチェック\n this.cleanEmptyObjects(obj, keys.slice(0, -1))\n }\n }\n\n // プロジェクト設定ファイルの作成\n async createProjectConfig(configPath?: string): Promise<void> {\n const targetPath = configPath || path.join(process.cwd(), '.maestro.json')\n const exampleConfig: Partial<Config> = {\n worktrees: {\n path: '../maestro-{branch}',\n branchPrefix: 'feature/',\n directoryPrefix: 'maestro-',\n },\n development: {\n autoSetup: true,\n syncFiles: ['.env', '.env.local'],\n defaultEditor: 'cursor',\n },\n tmux: {\n enabled: true,\n openIn: 'window',\n sessionNaming: '{branch}',\n },\n claude: {\n markdownMode: 'shared',\n },\n github: {\n autoFetch: true,\n branchNaming: {\n prTemplate: 'pr-{number}',\n issueTemplate: 'issue-{number}',\n },\n },\n ui: {\n pathDisplay: 'absolute',\n },\n hooks: {\n afterCreate: 'npm install',\n beforeDelete: 'echo \"オーケストラメンバーを解散します: $MAESTRO_BRANCH\"',\n },\n postCreate: {\n copyFiles: ['.env', '.env.local'],\n commands: ['pnpm install', 'pnpm run dev'],\n },\n }\n\n await fs.writeFile(targetPath, JSON.stringify(exampleConfig, null, 2) + '\\n', 'utf-8')\n }\n}\n"],"mappings":"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","names":["z","path","fs","__dirname","z"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@iflow-mcp/camoneart-maestro",
|
|
3
|
+
"version": "5.0.0",
|
|
4
|
+
"description": "A CLI tool that conducts Git worktrees like an orchestra and accelerates parallel development with Claude Code",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"iflow-mcp_camoneart-maestro": "./dist/mcp/server.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"scripts",
|
|
12
|
+
"completion",
|
|
13
|
+
"README.md",
|
|
14
|
+
"README.ja.md",
|
|
15
|
+
"LICENSE",
|
|
16
|
+
"CHANGELOG.md"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"dev": "tsx watch src/cli.ts",
|
|
20
|
+
"build": "tsup",
|
|
21
|
+
"start": "node dist/cli.js",
|
|
22
|
+
"lint": "eslint src --ext .ts",
|
|
23
|
+
"lint:ci": "eslint src --ext .ts --max-warnings 26",
|
|
24
|
+
"format": "prettier --write 'src/**/*.ts'",
|
|
25
|
+
"prettier:check": "prettier --check 'src/**/*.ts'",
|
|
26
|
+
"test": "vitest",
|
|
27
|
+
"test:e2e": "pnpm build && vitest run -c vitest.config.e2e.ts",
|
|
28
|
+
"test:coverage": "vitest run --coverage",
|
|
29
|
+
"typecheck": "tsc --noEmit",
|
|
30
|
+
"update-scoop-manifest": "node scripts/update-scoop-manifest.js",
|
|
31
|
+
"changeset": "changeset",
|
|
32
|
+
"version": "changeset version",
|
|
33
|
+
"release": "pnpm build && changeset publish --access public",
|
|
34
|
+
"prepublishOnly": "pnpm build && node scripts/generate-completions.js",
|
|
35
|
+
"postinstall": "node -e \"try { require('fs').chmodSync(require('path').join(__dirname, 'scripts', 'maestro-tmux-attach'), '755'); } catch (e) { /* ignore */ }\""
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"git",
|
|
39
|
+
"worktree",
|
|
40
|
+
"cli",
|
|
41
|
+
"mcp",
|
|
42
|
+
"claude",
|
|
43
|
+
"development-tools"
|
|
44
|
+
],
|
|
45
|
+
"author": "camoneart",
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"repository": {
|
|
48
|
+
"type": "git",
|
|
49
|
+
"url": "git+https://github.com/camoneart/maestro.git"
|
|
50
|
+
},
|
|
51
|
+
"homepage": "https://github.com/camoneart/maestro#readme",
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/camoneart/maestro/issues"
|
|
54
|
+
},
|
|
55
|
+
"packageManager": "pnpm@10.14.0",
|
|
56
|
+
"engines": {
|
|
57
|
+
"node": ">=20.0.0"
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@modelcontextprotocol/sdk": "1.17.0",
|
|
61
|
+
"chalk": "5.4.1",
|
|
62
|
+
"chokidar": "4.0.3",
|
|
63
|
+
"cli-progress": "3.12.0",
|
|
64
|
+
"commander": "14.0.0",
|
|
65
|
+
"conf": "14.0.0",
|
|
66
|
+
"execa": "9.6.0",
|
|
67
|
+
"inquirer": "12.8.2",
|
|
68
|
+
"node-pty": "1.0.0",
|
|
69
|
+
"open": "10.2.0",
|
|
70
|
+
"ora": "8.2.0",
|
|
71
|
+
"p-limit": "6.2.0",
|
|
72
|
+
"simple-git": "3.28.0",
|
|
73
|
+
"zod": "4.0.9"
|
|
74
|
+
},
|
|
75
|
+
"devDependencies": {
|
|
76
|
+
"@changesets/changelog-github": "0.5.1",
|
|
77
|
+
"@changesets/cli": "2.29.5",
|
|
78
|
+
"@eslint/js": "9.31.0",
|
|
79
|
+
"@types/cli-progress": "3.11.6",
|
|
80
|
+
"@types/inquirer": "9.0.8",
|
|
81
|
+
"@types/node": "24.1.0",
|
|
82
|
+
"@typescript-eslint/eslint-plugin": "8.38.0",
|
|
83
|
+
"@typescript-eslint/parser": "8.38.0",
|
|
84
|
+
"@vitest/coverage-v8": "3.2.4",
|
|
85
|
+
"eslint": "9.31.0",
|
|
86
|
+
"eslint-config-prettier": "10.1.8",
|
|
87
|
+
"prettier": "3.6.2",
|
|
88
|
+
"tsup": "8.5.0",
|
|
89
|
+
"tsx": "4.20.3",
|
|
90
|
+
"typescript": "5.8.3",
|
|
91
|
+
"vitest": "3.2.4"
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { fileURLToPath } from 'url'
|
|
4
|
+
import { dirname, join } from 'path'
|
|
5
|
+
import { mkdirSync, writeFileSync } from 'fs'
|
|
6
|
+
import { execSync } from 'child_process'
|
|
7
|
+
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
9
|
+
const rootDir = join(__dirname, '..')
|
|
10
|
+
|
|
11
|
+
// Create completion directories
|
|
12
|
+
const completionDir = join(rootDir, 'completion')
|
|
13
|
+
const bashDir = join(completionDir, 'bash')
|
|
14
|
+
const zshDir = join(completionDir, 'zsh')
|
|
15
|
+
const fishDir = join(completionDir, 'fish')
|
|
16
|
+
|
|
17
|
+
mkdirSync(completionDir, { recursive: true })
|
|
18
|
+
mkdirSync(bashDir, { recursive: true })
|
|
19
|
+
mkdirSync(zshDir, { recursive: true })
|
|
20
|
+
mkdirSync(fishDir, { recursive: true })
|
|
21
|
+
|
|
22
|
+
console.log('🎼 Generating shell completions...')
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
// Generate completions using the CLI
|
|
26
|
+
const bashCompletion = execSync('node dist/cli.js completion bash', {
|
|
27
|
+
cwd: rootDir,
|
|
28
|
+
encoding: 'utf-8'
|
|
29
|
+
})
|
|
30
|
+
const zshCompletion = execSync('node dist/cli.js completion zsh', {
|
|
31
|
+
cwd: rootDir,
|
|
32
|
+
encoding: 'utf-8'
|
|
33
|
+
})
|
|
34
|
+
const fishCompletion = execSync('node dist/cli.js completion fish', {
|
|
35
|
+
cwd: rootDir,
|
|
36
|
+
encoding: 'utf-8'
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
// Write completion files
|
|
40
|
+
writeFileSync(join(bashDir, 'mst'), bashCompletion)
|
|
41
|
+
writeFileSync(join(zshDir, '_mst'), zshCompletion)
|
|
42
|
+
writeFileSync(join(fishDir, 'mst.fish'), fishCompletion)
|
|
43
|
+
|
|
44
|
+
console.log('✅ Shell completions generated successfully!')
|
|
45
|
+
console.log(' - completion/bash/mst')
|
|
46
|
+
console.log(' - completion/zsh/_mst')
|
|
47
|
+
console.log(' - completion/fish/mst.fish')
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error('❌ Failed to generate completions:', error.message)
|
|
50
|
+
process.exit(1)
|
|
51
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# maestro-tmux-attach - Native tmux attach helper for TTY control
|
|
3
|
+
# This script properly transfers TTY control by using exec to replace the process
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
# Function to display usage
|
|
8
|
+
usage() {
|
|
9
|
+
echo "Usage: $0 [attach|new|switch] <session-name> [working-directory] [command]"
|
|
10
|
+
echo ""
|
|
11
|
+
echo "Commands:"
|
|
12
|
+
echo " attach - Attach to existing session"
|
|
13
|
+
echo " new - Create new session and attach"
|
|
14
|
+
echo " switch - Switch client to session (from within tmux)"
|
|
15
|
+
echo ""
|
|
16
|
+
echo "Examples:"
|
|
17
|
+
echo " $0 attach my-session"
|
|
18
|
+
echo " $0 new my-session /path/to/dir"
|
|
19
|
+
echo " $0 new my-session /path/to/dir 'vim .'"
|
|
20
|
+
echo " $0 switch my-session"
|
|
21
|
+
exit 1
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
# Validate arguments
|
|
25
|
+
if [ $# -lt 2 ]; then
|
|
26
|
+
usage
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
ACTION="$1"
|
|
30
|
+
SESSION_NAME="$2"
|
|
31
|
+
WORKING_DIR="${3:-}"
|
|
32
|
+
COMMAND="${4:-}"
|
|
33
|
+
|
|
34
|
+
# Validate session name
|
|
35
|
+
if [ -z "$SESSION_NAME" ]; then
|
|
36
|
+
echo "Error: Session name cannot be empty" >&2
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Sanitize session name (replace non-alphanumeric chars with dashes)
|
|
41
|
+
SESSION_NAME=$(echo "$SESSION_NAME" | sed 's/[^a-zA-Z0-9_-]/-/g')
|
|
42
|
+
|
|
43
|
+
case "$ACTION" in
|
|
44
|
+
"attach")
|
|
45
|
+
# Check if session exists
|
|
46
|
+
if ! tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
|
|
47
|
+
echo "Error: tmux session '$SESSION_NAME' does not exist" >&2
|
|
48
|
+
exit 1
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# Use exec to replace the current process with tmux
|
|
52
|
+
# This ensures proper TTY control transfer
|
|
53
|
+
exec tmux attach -t "$SESSION_NAME"
|
|
54
|
+
;;
|
|
55
|
+
|
|
56
|
+
"new")
|
|
57
|
+
# Prepare new-session arguments
|
|
58
|
+
TMUX_ARGS=("new-session" "-s" "$SESSION_NAME")
|
|
59
|
+
|
|
60
|
+
# Add working directory if specified
|
|
61
|
+
if [ -n "$WORKING_DIR" ]; then
|
|
62
|
+
TMUX_ARGS+=("-c" "$WORKING_DIR")
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
# Add command if specified
|
|
66
|
+
if [ -n "$COMMAND" ]; then
|
|
67
|
+
TMUX_ARGS+=("--" "$COMMAND")
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
# Check if session already exists
|
|
71
|
+
if tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
|
|
72
|
+
echo "Warning: tmux session '$SESSION_NAME' already exists, attaching instead" >&2
|
|
73
|
+
exec tmux attach -t "$SESSION_NAME"
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
# Use exec to replace the current process with tmux
|
|
77
|
+
exec tmux "${TMUX_ARGS[@]}"
|
|
78
|
+
;;
|
|
79
|
+
|
|
80
|
+
"switch")
|
|
81
|
+
# Check if we're inside tmux
|
|
82
|
+
if [ -z "${TMUX:-}" ]; then
|
|
83
|
+
echo "Error: switch command can only be used from within tmux" >&2
|
|
84
|
+
exit 1
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# Check if target session exists
|
|
88
|
+
if ! tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
|
|
89
|
+
echo "Error: tmux session '$SESSION_NAME' does not exist" >&2
|
|
90
|
+
exit 1
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
# Switch client - no exec needed as this doesn't replace the process
|
|
94
|
+
tmux switch-client -t "$SESSION_NAME"
|
|
95
|
+
;;
|
|
96
|
+
|
|
97
|
+
*)
|
|
98
|
+
echo "Error: Unknown action '$ACTION'" >&2
|
|
99
|
+
usage
|
|
100
|
+
;;
|
|
101
|
+
esac
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { readFile, writeFile } from 'fs/promises'
|
|
4
|
+
import { createHash } from 'crypto'
|
|
5
|
+
import { execa } from 'execa'
|
|
6
|
+
import path from 'path'
|
|
7
|
+
import { fileURLToPath } from 'url'
|
|
8
|
+
import https from 'https'
|
|
9
|
+
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
11
|
+
const __dirname = path.dirname(__filename)
|
|
12
|
+
|
|
13
|
+
async function getSHA256FromURL(url) {
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
https.get(url, (response) => {
|
|
16
|
+
const hash = createHash('sha256')
|
|
17
|
+
response.on('data', (chunk) => hash.update(chunk))
|
|
18
|
+
response.on('end', () => resolve(hash.digest('hex')))
|
|
19
|
+
response.on('error', reject)
|
|
20
|
+
}).on('error', reject)
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function getSHA256() {
|
|
25
|
+
try {
|
|
26
|
+
// npm packコマンドでtarballを作成
|
|
27
|
+
const { stdout } = await execa('npm', ['pack', '--json'])
|
|
28
|
+
const packInfo = JSON.parse(stdout)[0]
|
|
29
|
+
const tarballPath = packInfo.filename
|
|
30
|
+
|
|
31
|
+
// tarballのSHA256を計算
|
|
32
|
+
const content = await readFile(tarballPath)
|
|
33
|
+
const hash = createHash('sha256').update(content).digest('hex')
|
|
34
|
+
|
|
35
|
+
// tarballを削除
|
|
36
|
+
await execa('rm', [tarballPath])
|
|
37
|
+
|
|
38
|
+
return hash
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error('Failed to calculate SHA256:', error)
|
|
41
|
+
return 'PLACEHOLDER_SHA256'
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function updateManifest() {
|
|
46
|
+
try {
|
|
47
|
+
// package.jsonからバージョンを取得
|
|
48
|
+
const packageJsonPath = path.join(__dirname, '..', 'package.json')
|
|
49
|
+
const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8'))
|
|
50
|
+
const version = packageJson.version
|
|
51
|
+
|
|
52
|
+
// Scoop manifestのパス
|
|
53
|
+
const manifestPath = path.join(__dirname, '..', 'scoop', 'maestro.json')
|
|
54
|
+
const manifestContent = await readFile(manifestPath, 'utf8')
|
|
55
|
+
const manifest = JSON.parse(manifestContent)
|
|
56
|
+
|
|
57
|
+
// バージョンを更新
|
|
58
|
+
manifest.version = version
|
|
59
|
+
|
|
60
|
+
// URLを更新
|
|
61
|
+
const newUrl = `https://registry.npmjs.org/maestro/-/maestro-${version}.tgz`
|
|
62
|
+
manifest.architecture['64bit'].url = newUrl
|
|
63
|
+
|
|
64
|
+
// SHA256を更新(本番環境では実際のSHA256を計算)
|
|
65
|
+
const sha256 = await getSHA256()
|
|
66
|
+
manifest.architecture['64bit'].hash = sha256
|
|
67
|
+
|
|
68
|
+
// ファイルを更新
|
|
69
|
+
await writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\n')
|
|
70
|
+
|
|
71
|
+
console.log(`✅ Scoop manifest updated for version ${version}`)
|
|
72
|
+
console.log(` URL: ${newUrl}`)
|
|
73
|
+
console.log(` SHA256: ${sha256}`)
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error('❌ Failed to update Scoop manifest:', error)
|
|
76
|
+
process.exit(1)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
updateManifest()
|