├── haconiwa-npm ├── node_modules │ ├── .bin │ │ └── node-which │ ├── isexe │ │ ├── .npmignore │ │ ├── LICENSE │ │ ├── package.json │ │ ├── windows.js │ │ ├── mode.js │ │ ├── index.js │ │ └── README.md │ ├── shebang-regex │ │ ├── index.js │ │ ├── index.d.ts │ │ ├── package.json │ │ ├── readme.md │ │ └── license │ ├── shebang-command │ │ ├── index.js │ │ ├── readme.md │ │ ├── package.json │ │ └── license │ ├── path-key │ │ ├── index.js │ │ ├── package.json │ │ ├── license │ │ ├── index.d.ts │ │ └── readme.md │ ├── which │ │ ├── LICENSE │ │ ├── bin │ │ │ └── node-which │ │ ├── package.json │ │ ├── README.md │ │ ├── CHANGELOG.md │ │ └── which.js │ ├── cross-spawn │ │ ├── LICENSE │ │ ├── index.js │ │ ├── package.json │ │ └── README.md │ └── .package-lock.json ├── state.pkl ├── LICENSE ├── package.json ├── check-python.js ├── bin │ └── haconiwa └── package-lock.json ├── .coverage ├── state.pkl ├── tests ├── test_scan │ └── __init__.py ├── __init__.py └── unit │ ├── test_resource.py │ ├── test_watch.py │ └── test_task.py ├── src └── haconiwa │ ├── legal │ └── __init__.py │ ├── organization │ └── __init__.py │ ├── scripts │ └── __init__.py │ ├── __main__.py │ ├── monitor │ └── __init__.py │ ├── tool │ └── __init__.py │ ├── world │ ├── __init__.py │ ├── provider │ │ ├── __init__.py │ │ └── docker.py │ └── cli.py │ ├── core │ ├── policy │ │ └── __init__.py │ ├── crd │ │ └── __init__.py │ ├── __init__.py │ ├── state.py │ ├── upgrade.py │ └── config.py │ ├── agent │ ├── __init__.py │ ├── manager.py │ ├── boss.py │ └── base.py │ ├── task │ └── __init__.py │ ├── watch │ ├── __init__.py │ ├── cli.py │ └── monitor.py │ ├── utils │ ├── __init__.py │ └── typer_ext.py │ ├── scan │ └── __init__.py │ ├── space │ └── __init__.py │ ├── resource │ ├── __init__.py │ ├── cli.py │ └── db_fetcher.py │ └── __init__.py ├── examples ├── files.txt ├── prompts.txt ├── parallel-dev-example.yaml └── demo_flow.sh ├── claude-settings ├── CLAUDE.md └── settings.local.json ├── .haconiwa-debug-test.json ├── update-claude-code.sh ├── .haconiwa-test-v030-company.json ├── .env.base.example ├── .haconiwa-lifecycle-test-simple.json ├── .haconiwa-test-directory-creation.json ├── .env.local.example ├── test_files ├── file1.py └── file2.py ├── .env.production.example ├── tools └── security-check │ ├── .gitignore │ ├── config.json │ ├── nglist.json.example │ ├── install_hook.py │ └── setup_personal_config.py ├── scripts ├── lint.sh ├── bootstrap.sh ├── check-relative-paths.sh ├── release.sh ├── verify-claude-execution.sh ├── check-pane-borders.sh └── README.md ├── .claude └── settings.json ├── .coderabbit.yaml ├── voice-systems ├── command-permission │ ├── test_popup.py │ ├── test_keywords.py │ ├── test_gpt4o.py │ └── test_voice_simple.py └── experimental │ ├── test_gemini_text_streaming.py │ └── test_streaming_tts.py ├── organizations └── org-01 │ ├── tasks │ └── backlog │ │ └── .gitkeep │ ├── workers │ ├── worker_b.py │ └── worker_c.py │ ├── boss │ └── boss.py │ └── config.yaml ├── .haconiwa ├── agent_assignment.json ├── task_ai_strategy_01 │ ├── agent_assignment.json │ └── README.md ├── task_product_roadmap_04 │ ├── agent_assignment.json │ └── README.md ├── task_financial_planning_03 │ └── agent_assignment.json └── README.md ├── parallel-dev.yaml ├── .github └── RELEASE_TEMPLATE.md ├── LICENSE ├── test-aicode-simple.yaml ├── .gitignore ├── debug_apply_test.py ├── docs ├── readme_additions.md ├── CI_STRATEGY_OPTIONS.md ├── quickstart.md ├── ai │ └── core-engine │ │ └── claude_code_sdk_documentation.md ├── backend │ └── performance │ │ └── tool_parallel_dev_command_design.md ├── architecture.md ├── VERSION_MANAGEMENT.md └── parallel-dev-usage.md ├── test_cases ├── minimal_config.yaml └── error_case_test.yaml ├── worlds └── local-dev.yaml ├── pyproject.toml ├── haconiwa-simple-dev.yaml └── test_32pane.py /haconiwa-npm/node_modules/.bin/node-which: -------------------------------------------------------------------------------- 1 | ../which/bin/node-which -------------------------------------------------------------------------------- /.coverage: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dai-motoki/haconiwa/HEAD/.coverage -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/isexe/.npmignore: -------------------------------------------------------------------------------- 1 | .nyc_output/ 2 | coverage/ 3 | -------------------------------------------------------------------------------- /state.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dai-motoki/haconiwa/HEAD/state.pkl -------------------------------------------------------------------------------- /tests/test_scan/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test suite for haconiwa scan module 3 | """ -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/shebang-regex/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = /^#!(.*)/; 3 | -------------------------------------------------------------------------------- /haconiwa-npm/state.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dai-motoki/haconiwa/HEAD/haconiwa-npm/state.pkl -------------------------------------------------------------------------------- /src/haconiwa/legal/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Legal Framework Package 3 | 法的フレームワークパッケージ 4 | 5 | 階層的法的フレームワークの実装を提供します。 6 | """ -------------------------------------------------------------------------------- /src/haconiwa/organization/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Organization management for Haconiwa 3 | """ 4 | 5 | __version__ = "1.0.0" -------------------------------------------------------------------------------- /examples/files.txt: -------------------------------------------------------------------------------- 1 | src/models/user.py 2 | src/models/product.py 3 | src/models/order.py 4 | src/services/auth.py 5 | src/services/payment.py -------------------------------------------------------------------------------- /src/haconiwa/scripts/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Haconiwa scripts module for testing and release automation. 3 | """ 4 | 5 | __version__ = "0.2.1" -------------------------------------------------------------------------------- /src/haconiwa/__main__.py: -------------------------------------------------------------------------------- 1 | """Main entry point for haconiwa when run as a module.""" 2 | 3 | from haconiwa.cli import app 4 | 5 | if __name__ == "__main__": 6 | app() -------------------------------------------------------------------------------- /claude-settings/CLAUDE.md: -------------------------------------------------------------------------------- 1 | # Claude Code Guidelines 2 | 3 | 基本的なコーディング規約に従ってください。 4 | 5 | ## プロジェクトルール 6 | 7 | 1. 型ヒントを必ず使用する 8 | 2. テストを先に書く 9 | 3. コミット前にlintを実行する 10 | -------------------------------------------------------------------------------- /src/haconiwa/monitor/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Monitor module for Haconiwa 3 | Real-time monitoring tools for tmux multi-agent environments 4 | """ 5 | 6 | from .tmux_monitor import TmuxMonitor 7 | 8 | __all__ = ['TmuxMonitor'] -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # test/__init__.py 2 | 3 | import pytest 4 | 5 | # テスト設定の定義 6 | pytest_plugins = ["pytest_asyncio"] 7 | 8 | # Pythonテストランナーとの統合設定 9 | def pytest_configure(): 10 | # ここに設定を追加 11 | pass; -------------------------------------------------------------------------------- /claude-settings/settings.local.json: -------------------------------------------------------------------------------- 1 | {"permissions":{"allow":["Read(*)","Edit(*)","Write(*)","Bash(ls:*)","Bash(cat:*)","Bash(rg:*)","Bash(git:*)","Bash(python:*)","Bash(pytest:*)","Bash(ruff:*)","Bash(mypy:*)"],"deny":[]}} 2 | -------------------------------------------------------------------------------- /src/haconiwa/tool/__init__.py: -------------------------------------------------------------------------------- 1 | """Tool module for external tool integrations.""" 2 | 3 | from .parallel_dev import parallel_dev_app, ParallelDevManager 4 | 5 | __all__ = [ 6 | "parallel_dev_app", 7 | "ParallelDevManager" 8 | ] -------------------------------------------------------------------------------- /src/haconiwa/world/__init__.py: -------------------------------------------------------------------------------- 1 | # haconiwa/world/__init__.py 2 | 3 | from .provider import local, docker 4 | 5 | __all__ = ["local", "docker"] 6 | 7 | def initialize(): 8 | # worldモジュールの初期化処理 9 | pass 10 | 11 | initialize(); -------------------------------------------------------------------------------- /.haconiwa-debug-test.json: -------------------------------------------------------------------------------- 1 | { 2 | "company_name": "debug-test", 3 | "created_at": "2025-06-09 01:44:53", 4 | "directories": [ 5 | "org-01", 6 | "org-02", 7 | "org-03", 8 | "org-04" 9 | ], 10 | "base_path": "." 11 | } -------------------------------------------------------------------------------- /update-claude-code.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Update @anthropic-ai/claude-code npm package 4 | echo "Updating @anthropic-ai/claude-code in ~/.claude/local..." 5 | cd ~/.claude/local && npm update @anthropic-ai/claude-code 6 | echo "Update complete!" -------------------------------------------------------------------------------- /.haconiwa-test-v030-company.json: -------------------------------------------------------------------------------- 1 | { 2 | "company_name": "test-v030-company", 3 | "created_at": "2025-06-09 02:39:32", 4 | "directories": [ 5 | "org-01", 6 | "org-02", 7 | "org-03", 8 | "org-04" 9 | ], 10 | "base_path": "." 11 | } -------------------------------------------------------------------------------- /.env.base.example: -------------------------------------------------------------------------------- 1 | # Base environment variables for Haconiwa 2 | COMPANY_NAME="Your Company Name" 3 | API_ENDPOINT="https://api.yourdomain.com" 4 | LOG_LEVEL="INFO" 5 | TIMEZONE="Asia/Tokyo" 6 | LOCALE="ja_JP.UTF-8" 7 | PROJECT_NAME="Your Project" 8 | VERSION="1.0.0" -------------------------------------------------------------------------------- /.haconiwa-lifecycle-test-simple.json: -------------------------------------------------------------------------------- 1 | { 2 | "company_name": "lifecycle-test-simple", 3 | "created_at": "2025-06-09 01:53:13", 4 | "directories": [ 5 | "org-01", 6 | "org-02", 7 | "org-03", 8 | "org-04" 9 | ], 10 | "base_path": "." 11 | } -------------------------------------------------------------------------------- /.haconiwa-test-directory-creation.json: -------------------------------------------------------------------------------- 1 | { 2 | "company_name": "test-directory-creation", 3 | "created_at": "2025-06-09 02:47:36", 4 | "directories": [ 5 | "org-01", 6 | "org-02", 7 | "org-03", 8 | "org-04" 9 | ], 10 | "base_path": "." 11 | } -------------------------------------------------------------------------------- /examples/prompts.txt: -------------------------------------------------------------------------------- 1 | Add validation methods and comprehensive type hints 2 | Implement inventory tracking with stock level management 3 | Add order status transitions and state management 4 | Implement JWT authentication with secure token handling 5 | Add payment gateway integration with proper error handling -------------------------------------------------------------------------------- /.env.local.example: -------------------------------------------------------------------------------- 1 | # Local development environment variables 2 | ANTHROPIC_API_KEY="sk-ant-api03-YOUR-KEY-HERE" 3 | CLAUDE_MODEL="claude-3-opus-20240229" 4 | DEBUG_MODE=true 5 | DATABASE_URL="postgresql://user:pass@localhost:5432/yourdb_dev" 6 | REDIS_URL="redis://localhost:6379" 7 | LOG_LEVEL="DEBUG" 8 | ENABLE_HOT_RELOAD=true -------------------------------------------------------------------------------- /src/haconiwa/core/policy/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Haconiwa Policy Module 3 | """ 4 | 5 | from .engine import PolicyEngine, PolicyViolationError 6 | from .validator import CommandValidator, ValidationResult 7 | 8 | __all__ = [ 9 | 'PolicyEngine', 'PolicyViolationError', 10 | 'CommandValidator', 'ValidationResult' 11 | ] -------------------------------------------------------------------------------- /test_files/file1.py: -------------------------------------------------------------------------------- 1 | def add(a: int | float, b: int | float) -> int | float: 2 | """a と b の和を返す""" 3 | return a + b 4 | 5 | def multiply(x: int | float, y: int | float) -> int | float: 6 | """x と y の積を返す""" 7 | return x * y 8 | 9 | def greet(name: str) -> str: 10 | """挨拶メッセージを返す""" 11 | return f"Hello, {name}!" -------------------------------------------------------------------------------- /.env.production.example: -------------------------------------------------------------------------------- 1 | # Production environment variables 2 | API_ENDPOINT="https://api.yourdomain.com" 3 | LOG_LEVEL="WARNING" 4 | DEBUG_MODE="false" 5 | DATABASE_URL="postgresql://prod_user:prod_pass@db.yourdomain.com:5432/yourdb_prod" 6 | REDIS_URL="redis://cache.yourdomain.com:6379" 7 | ENABLE_MONITORING="true" 8 | SENTRY_DSN="https://sentry.yourdomain.com/dsn" -------------------------------------------------------------------------------- /tools/security-check/.gitignore: -------------------------------------------------------------------------------- 1 | # 個人用設定ファイル - コミットしない 2 | nglist.json 3 | personal_config.json 4 | user_settings.json 5 | 6 | # 実行時に生成されるファイル 7 | *.log 8 | security_report.json 9 | temp_* 10 | 11 | # Python関連 12 | __pycache__/ 13 | *.pyc 14 | *.pyo 15 | 16 | # エディタ関連 17 | .vscode/ 18 | .idea/ 19 | *.swp 20 | *.swo 21 | *~ 22 | 23 | # OS関連 24 | .DS_Store 25 | Thumbs.db -------------------------------------------------------------------------------- /scripts/lint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Python コード品質チェック用シェルスクリプト 4 | 5 | # black フォーマット実行 6 | black . 7 | 8 | # flake8 リンティング 9 | flake8 . 10 | 11 | # mypy 型チェック 12 | mypy . 13 | 14 | # bandit セキュリティスキャン 15 | bandit -r . 16 | 17 | # isort インポート整理 18 | isort . 19 | 20 | # pytest カバレッジ測定 21 | pytest --cov=src --cov-report=html 22 | 23 | # エラー集約とレポート出力 24 | echo "コード品質チェックが完了しました。" -------------------------------------------------------------------------------- /src/haconiwa/core/crd/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Haconiwa CRD (Custom Resource Definition) Module 3 | """ 4 | 5 | from .models import ( 6 | SpaceCRD, AgentCRD, TaskCRD, PathScanCRD, DatabaseCRD, CommandPolicyCRD 7 | ) 8 | from .parser import CRDParser, CRDValidationError 9 | 10 | __all__ = [ 11 | 'SpaceCRD', 'AgentCRD', 'TaskCRD', 'PathScanCRD', 'DatabaseCRD', 'CommandPolicyCRD', 12 | 'CRDParser', 'CRDValidationError' 13 | ] -------------------------------------------------------------------------------- /src/haconiwa/core/__init__.py: -------------------------------------------------------------------------------- 1 | # src/haconiwa/core/__init__.py 2 | 3 | """ 4 | Haconiwa Core Module 5 | """ 6 | 7 | from .config import Config 8 | from .state import StateManager 9 | 10 | # v1.0 新機能 11 | try: 12 | from .crd import * 13 | from .applier import CRDApplier 14 | from .policy import * 15 | except ImportError: 16 | # v1.0機能がない場合はスキップ 17 | pass 18 | 19 | __all__ = [ 20 | 'Config', 21 | 'StateManager' 22 | ] -------------------------------------------------------------------------------- /src/haconiwa/agent/__init__.py: -------------------------------------------------------------------------------- 1 | # haconiwa/agent/__init__.py 2 | 3 | """ 4 | Agent Integration Package 5 | エージェント統合パッケージ 6 | 7 | Claude Code、Cursor、その他のエージェントツールとの統合機能を提供します。 8 | """ 9 | 10 | class Agent: 11 | def __init__(self): 12 | self.agents = [] 13 | 14 | def register_agent(self, agent): 15 | self.agents.append(agent) 16 | 17 | def get_agents(self): 18 | return self.agents 19 | 20 | # エージェント管理機能のインスタンスを作成 21 | agent_manager = Agent() -------------------------------------------------------------------------------- /src/haconiwa/task/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ["TaskManager"] 2 | 3 | class TaskManager: 4 | def __init__(self): 5 | self.tasks = [] 6 | 7 | def add_task(self, task): 8 | self.tasks.append(task) 9 | 10 | def remove_task(self, task): 11 | self.tasks.remove(task) 12 | 13 | def list_tasks(self): 14 | return self.tasks 15 | 16 | def clear_tasks(self): 17 | self.tasks.clear() 18 | 19 | # git-worktree integration functionality can be added here 20 | -------------------------------------------------------------------------------- /.claude/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "tools": { 3 | "ripgrep": { 4 | "path": "~/bin/rg", 5 | "description": "Fast file content search tool" 6 | } 7 | }, 8 | "commands": { 9 | "lint": { 10 | "python": "ruff check src/" 11 | }, 12 | "typecheck": { 13 | "python": "mypy src/" 14 | } 15 | }, 16 | "project": { 17 | "name": "haconiwa", 18 | "type": "python", 19 | "description": "Multiroom tmux session management with CRD-based configuration" 20 | } 21 | } -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/shebang-command/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const shebangRegex = require('shebang-regex'); 3 | 4 | module.exports = (string = '') => { 5 | const match = string.match(shebangRegex); 6 | 7 | if (!match) { 8 | return null; 9 | } 10 | 11 | const [path, argument] = match[0].replace(/#! ?/, '').split(' '); 12 | const binary = path.split('/').pop(); 13 | 14 | if (binary === 'env') { 15 | return argument; 16 | } 17 | 18 | return argument ? `${binary} ${argument}` : binary; 19 | }; 20 | -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/path-key/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const pathKey = (options = {}) => { 4 | const environment = options.env || process.env; 5 | const platform = options.platform || process.platform; 6 | 7 | if (platform !== 'win32') { 8 | return 'PATH'; 9 | } 10 | 11 | return Object.keys(environment).reverse().find(key => key.toUpperCase() === 'PATH') || 'Path'; 12 | }; 13 | 14 | module.exports = pathKey; 15 | // TODO: Remove this for the next major release 16 | module.exports.default = pathKey; 17 | -------------------------------------------------------------------------------- /src/haconiwa/watch/__init__.py: -------------------------------------------------------------------------------- 1 | # haconiwa/watch/__init__.py 2 | 3 | class Watch: 4 | def __init__(self): 5 | self.metrics = {} 6 | self.alerts = [] 7 | 8 | def add_metric(self, name, value): 9 | self.metrics[name] = value 10 | 11 | def trigger_alert(self, message): 12 | self.alerts.append(message) 13 | 14 | def get_metrics(self): 15 | return self.metrics 16 | 17 | def get_alerts(self): 18 | return self.alerts 19 | 20 | # モジュールの初期化処理 21 | watch = Watch(); -------------------------------------------------------------------------------- /src/haconiwa/utils/__init__.py: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const UtilsInit: React.FC = () => { 4 | return ( 5 | 6 | 7 | Utilsモジュール初期化 8 | 共通ユーティリティクラスのエクスポートとヘルパー機能の提供 9 | 10 | 11 | {/* ヘルパー機能をここに配置 */} 12 | 13 | 14 | ); 15 | }; 16 | export default UtilsInit; -------------------------------------------------------------------------------- /.coderabbit.yaml: -------------------------------------------------------------------------------- 1 | # CodeRabbit Configuration 2 | # This file enables automatic code review for all branches 3 | 4 | reviews: 5 | auto: true # Enable automatic reviews 6 | review_status: true # Show status messages 7 | # Review all branches by not specifying any filters 8 | # This means CodeRabbit will review PRs to any branch 9 | 10 | # Optional: You can customize other settings 11 | language: "ja" # Use Japanese for reviews 12 | path_filters: 13 | # You can exclude certain paths if needed 14 | # exclude: 15 | # - "docs/**" 16 | # - "*.md" -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/shebang-regex/index.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Regular expression for matching a [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) line. 3 | 4 | @example 5 | ``` 6 | import shebangRegex = require('shebang-regex'); 7 | 8 | const string = '#!/usr/bin/env node\nconsole.log("unicorns");'; 9 | 10 | shebangRegex.test(string); 11 | //=> true 12 | 13 | shebangRegex.exec(string)[0]; 14 | //=> '#!/usr/bin/env node' 15 | 16 | shebangRegex.exec(string)[1]; 17 | //=> '/usr/bin/env node' 18 | ``` 19 | */ 20 | declare const shebangRegex: RegExp; 21 | 22 | export = shebangRegex; 23 | -------------------------------------------------------------------------------- /src/haconiwa/scan/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Haconiwa Scan Module - Universal AI Model Search Implementation 3 | 4 | This module provides comprehensive search capabilities for AI model directories, 5 | supporting model name searching, file content searching, and various output formats. 6 | """ 7 | 8 | from .cli import scan_app 9 | from .scanner import ModelScanner 10 | from .analyzer import ModelAnalyzer 11 | from .formatter import OutputFormatter 12 | from .generate_parallel import ParallelYAMLGenerator 13 | 14 | __all__ = ['scan_app', 'ModelScanner', 'ModelAnalyzer', 'OutputFormatter', 'ParallelYAMLGenerator'] -------------------------------------------------------------------------------- /voice-systems/command-permission/test_popup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | ポップアップテスト 4 | """ 5 | 6 | import subprocess 7 | 8 | def test_popup(): 9 | """ポップアップテスト""" 10 | print("ポップアップをテストします...") 11 | 12 | try: 13 | subprocess.run([ 14 | "osascript", "-e", 15 | 'display notification "🎙️ 音声録音中... (5秒間)" with title "Claude Code 音声認識" sound name "Submarine"' 16 | ], check=False) 17 | print("✅ ポップアップ送信成功") 18 | except Exception as e: 19 | print(f"❌ ポップアップエラー: {e}") 20 | 21 | if __name__ == "__main__": 22 | test_popup() -------------------------------------------------------------------------------- /scripts/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Python 仮想環境の作成と有効化 4 | python3 -m venv .venv 5 | source .venv/bin/activate 6 | 7 | # 依存関係の一括インストール 8 | pip install -e .[dev] 9 | 10 | # pre-commit フックの設定 11 | pre-commit install 12 | 13 | # tmux, git の設定確認 14 | tmux -V 15 | git --version 16 | 17 | # 初期設定ファイルの生成 18 | if [ ! -f config.yaml ]; then 19 | echo "初期設定ファイルを生成します..." 20 | touch config.yaml 21 | fi 22 | 23 | # 開発用データベースのセットアップ 24 | if [ ! -d db ]; then 25 | mkdir db 26 | echo "データベースのセットアップが完了しました。" 27 | fi 28 | 29 | # 開発サーバーの起動確認 30 | echo "開発サーバーを起動します..." 31 | # ここにサーバー起動コマンドを追加 (例: python -m flask run) -------------------------------------------------------------------------------- /src/haconiwa/space/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | __all__ = ["TmuxManager"] 4 | 5 | class TmuxManager: 6 | def __init__(self): 7 | self.sessions = {} 8 | 9 | def create_session(self, name): 10 | os.system(f"tmux new-session -d -s {name}") 11 | self.sessions[name] = True 12 | 13 | def list_sessions(self): 14 | return os.popen("tmux ls").read().strip() 15 | 16 | def attach_session(self, name): 17 | os.system(f"tmux attach-session -t {name}") 18 | 19 | def kill_session(self, name): 20 | os.system(f"tmux kill-session -t {name}") 21 | del self.sessions[name] -------------------------------------------------------------------------------- /organizations/org-01/tasks/backlog/.gitkeep: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | 3 | const .gitkeep: React.FC = () => { 4 | return ( 5 | 6 | 7 | Git ディレクトリ保持ファイル 8 | 空のbacklogディレクトリをGitで管理するためのファイル 9 | 10 | 11 | {/* ディレクトリ構造の維持 */} 12 | {/* 将来的なタスクブランチファイルの配置場所として機能 */} 13 | 14 | 15 | ); 16 | }; 17 | export default .gitkeep; -------------------------------------------------------------------------------- /.haconiwa/agent_assignment.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "agent_id": "vpp-suzuki", 4 | "task_name": "task_product_roadmap_04", 5 | "space_session": "haconiwa-dev-company", 6 | "tmux_window": null, 7 | "tmux_pane": null, 8 | "assigned_at": "2025-06-14T21:46:58.638026", 9 | "assignment_type": "automatic", 10 | "task_directory": "haconiwa-dev-world/tasks/task_product_roadmap_04", 11 | "status": "active", 12 | "description": "## Product Roadmap Development\n\nCreate detailed product roadmap for next 12 months.\n\n### Requirements:\n- Feature prioritization\n- User research analysis\n- Market requirements\n- Timeline planning\n" 13 | } 14 | ] -------------------------------------------------------------------------------- /src/haconiwa/resource/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | __all__ = ["ResourceManager"] 4 | 5 | class ResourceManager: 6 | def __init__(self): 7 | self.resources = {} 8 | 9 | def load_file(self, file_path): 10 | if os.path.exists(file_path): 11 | with open(file_path, 'r') as file: 12 | data = file.read() 13 | self.resources[file_path] = data 14 | else: 15 | raise FileNotFoundError(f"{file_path} not found.") 16 | 17 | def get_resource(self, file_path): 18 | return self.resources.get(file_path, None) 19 | 20 | def clear_resources(self): 21 | self.resources.clear() -------------------------------------------------------------------------------- /.haconiwa/task_ai_strategy_01/agent_assignment.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "agent_id": "ceo-motoki", 4 | "task_name": "task_ai_strategy_01", 5 | "space_session": "haconiwa-dev-company", 6 | "tmux_window": null, 7 | "tmux_pane": null, 8 | "assigned_at": "2025-06-14T18:33:02.972928", 9 | "assignment_type": "automatic", 10 | "task_directory": "haconiwa-dev-world/tasks/task_ai_strategy_01", 11 | "status": "active", 12 | "description": "## AI Strategy Development\n\nDevelop comprehensive AI strategy for Haconiwa platform.\n\n### Requirements:\n- Market analysis\n- Technology roadmap\n- Competitive analysis\n- Investment planning\n" 13 | } 14 | ] -------------------------------------------------------------------------------- /.haconiwa/task_product_roadmap_04/agent_assignment.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "agent_id": "vpp-suzuki", 4 | "task_name": "task_product_roadmap_04", 5 | "space_session": "haconiwa-dev-company", 6 | "tmux_window": null, 7 | "tmux_pane": null, 8 | "assigned_at": "2025-06-14T21:45:59.459459", 9 | "assignment_type": "automatic", 10 | "task_directory": "haconiwa-dev-world/tasks/task_product_roadmap_04", 11 | "status": "active", 12 | "description": "## Product Roadmap Development\n\nCreate detailed product roadmap for next 12 months.\n\n### Requirements:\n- Feature prioritization\n- User research analysis\n- Market requirements\n- Timeline planning\n" 13 | } 14 | ] -------------------------------------------------------------------------------- /.haconiwa/task_financial_planning_03/agent_assignment.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "agent_id": "cfo-tanaka", 4 | "task_name": "task_financial_planning_03", 5 | "space_session": "haconiwa-dev-company", 6 | "tmux_window": null, 7 | "tmux_pane": null, 8 | "assigned_at": "2025-06-14T18:33:03.010894", 9 | "assignment_type": "automatic", 10 | "task_directory": "haconiwa-dev-world/tasks/task_financial_planning_03", 11 | "status": "active", 12 | "description": "## Financial Planning & Analysis\n\nDevelop comprehensive financial model and planning.\n\n### Requirements:\n- Revenue projections\n- Cost analysis\n- Investment planning\n- Financial reporting\n" 13 | } 14 | ] -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/shebang-command/readme.md: -------------------------------------------------------------------------------- 1 | # shebang-command [![Build Status](https://travis-ci.org/kevva/shebang-command.svg?branch=master)](https://travis-ci.org/kevva/shebang-command) 2 | 3 | > Get the command from a shebang 4 | 5 | 6 | ## Install 7 | 8 | ``` 9 | $ npm install shebang-command 10 | ``` 11 | 12 | 13 | ## Usage 14 | 15 | ```js 16 | const shebangCommand = require('shebang-command'); 17 | 18 | shebangCommand('#!/usr/bin/env node'); 19 | //=> 'node' 20 | 21 | shebangCommand('#!/bin/bash'); 22 | //=> 'bash' 23 | ``` 24 | 25 | 26 | ## API 27 | 28 | ### shebangCommand(string) 29 | 30 | #### string 31 | 32 | Type: `string` 33 | 34 | String containing a shebang. 35 | -------------------------------------------------------------------------------- /.haconiwa/README.md: -------------------------------------------------------------------------------- 1 | # エージェント割り当て情報 2 | 3 | ## 基本情報 4 | - **エージェントID**: `vpp-suzuki` 5 | - **タスクブランチ名**: `task_product_roadmap_04` 6 | - **割り当て日時**: 2025-06-14T21:46:58.638026 7 | - **ステータス**: active 8 | 9 | ## 環境情報 10 | - **スペースセッション**: `haconiwa-dev-company` 11 | - **tmuxウィンドウ**: None 12 | - **tmuxペイン**: None 13 | - **タスクブランチディレクトリ**: `haconiwa-dev-world/tasks/task_product_roadmap_04` 14 | 15 | ## エージェント役割 16 | **役割**: 未定義 17 | 18 | ## このディレクトリについて 19 | このディレクトリは、GitのWorktree機能を使用して作成された専用の作業ディレクトリです。 20 | このエージェント専用のブランチで作業を行い、他のエージェントとは独立した開発環境を提供します。 21 | 22 | ## ログファイル 23 | - `agent_assignment.json`: 割り当て履歴のJSON形式ログ 24 | - `README.md`: この説明ファイル 25 | 26 | --- 27 | *このファイルは Haconiwa v1.0 によって自動生成されました* 28 | -------------------------------------------------------------------------------- /.haconiwa/task_ai_strategy_01/README.md: -------------------------------------------------------------------------------- 1 | # エージェント割り当て情報 2 | 3 | ## 基本情報 4 | - **エージェントID**: `ceo-motoki` 5 | - **タスクブランチ名**: `task_ai_strategy_01` 6 | - **割り当て日時**: 2025-06-14T18:33:02.972928 7 | - **ステータス**: active 8 | 9 | ## 環境情報 10 | - **スペースセッション**: `haconiwa-dev-company` 11 | - **tmuxウィンドウ**: None 12 | - **tmuxペイン**: None 13 | - **タスクブランチディレクトリ**: `haconiwa-dev-world/tasks/task_ai_strategy_01` 14 | 15 | ## エージェント役割 16 | **役割**: 未定義 17 | 18 | ## このディレクトリについて 19 | このディレクトリは、GitのWorktree機能を使用して作成された専用の作業ディレクトリです。 20 | このエージェント専用のブランチで作業を行い、他のエージェントとは独立した開発環境を提供します。 21 | 22 | ## ログファイル 23 | - `agent_assignment.json`: 割り当て履歴のJSON形式ログ 24 | - `README.md`: この説明ファイル 25 | 26 | --- 27 | *このファイルは Haconiwa v1.0 によって自動生成されました* 28 | -------------------------------------------------------------------------------- /.haconiwa/task_product_roadmap_04/README.md: -------------------------------------------------------------------------------- 1 | # エージェント割り当て情報 2 | 3 | ## 基本情報 4 | - **エージェントID**: `vpp-suzuki` 5 | - **タスクブランチ名**: `task_product_roadmap_04` 6 | - **割り当て日時**: 2025-06-14T21:45:59.459459 7 | - **ステータス**: active 8 | 9 | ## 環境情報 10 | - **スペースセッション**: `haconiwa-dev-company` 11 | - **tmuxウィンドウ**: None 12 | - **tmuxペイン**: None 13 | - **タスクブランチディレクトリ**: `haconiwa-dev-world/tasks/task_product_roadmap_04` 14 | 15 | ## エージェント役割 16 | **役割**: 未定義 17 | 18 | ## このディレクトリについて 19 | このディレクトリは、GitのWorktree機能を使用して作成された専用の作業ディレクトリです。 20 | このエージェント専用のブランチで作業を行い、他のエージェントとは独立した開発環境を提供します。 21 | 22 | ## ログファイル 23 | - `agent_assignment.json`: 割り当て履歴のJSON形式ログ 24 | - `README.md`: この説明ファイル 25 | 26 | --- 27 | *このファイルは Haconiwa v1.0 によって自動生成されました* 28 | -------------------------------------------------------------------------------- /src/haconiwa/world/provider/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | __all__ = ['LocalProvider', 'DockerProvider'] 4 | 5 | class BaseProvider: 6 | def __init__(self): 7 | self.name = self.__class__.__name__ 8 | 9 | class LocalProvider(BaseProvider): 10 | def __init__(self): 11 | super().__init__() 12 | # Local provider specific initialization 13 | 14 | class DockerProvider(BaseProvider): 15 | def __init__(self): 16 | super().__init__() 17 | # Docker provider specific initialization 18 | 19 | def register_providers(): 20 | providers = { 21 | 'local': LocalProvider, 22 | 'docker': DockerProvider, 23 | } 24 | return providers 25 | 26 | providers = register_providers() -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/shebang-command/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shebang-command", 3 | "version": "2.0.0", 4 | "description": "Get the command from a shebang", 5 | "license": "MIT", 6 | "repository": "kevva/shebang-command", 7 | "author": { 8 | "name": "Kevin Mårtensson", 9 | "email": "kevinmartensson@gmail.com", 10 | "url": "github.com/kevva" 11 | }, 12 | "engines": { 13 | "node": ">=8" 14 | }, 15 | "scripts": { 16 | "test": "xo && ava" 17 | }, 18 | "files": [ 19 | "index.js" 20 | ], 21 | "keywords": [ 22 | "cmd", 23 | "command", 24 | "parse", 25 | "shebang" 26 | ], 27 | "dependencies": { 28 | "shebang-regex": "^3.0.0" 29 | }, 30 | "devDependencies": { 31 | "ava": "^2.3.0", 32 | "xo": "^0.24.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/haconiwa/watch/cli.py: -------------------------------------------------------------------------------- 1 | import typer 2 | from haconiwa.watch.monitor import Monitor 3 | 4 | watch_app = typer.Typer(help="監視・モニタリング (開発中)") 5 | 6 | @watch_app.command() 7 | def start(): 8 | """監視デーモンの起動""" 9 | monitor = Monitor() 10 | typer.echo("監視デーモンを起動しました。") 11 | 12 | @watch_app.command() 13 | def stop(): 14 | """監視デーモンの停止""" 15 | monitor = Monitor() 16 | typer.echo("監視デーモンを停止しました。") 17 | 18 | @watch_app.command() 19 | def tail(): 20 | """リアルタイムメトリクス表示""" 21 | monitor = Monitor() 22 | typer.echo("メトリクス表示機能(実装予定)") 23 | 24 | @watch_app.command() 25 | def health(): 26 | """ヘルスチェックと診断""" 27 | monitor = Monitor() 28 | typer.echo("システムのヘルスステータス: OK(デモ)") 29 | 30 | if __name__ == "__main__": 31 | watch_app() -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/shebang-regex/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shebang-regex", 3 | "version": "3.0.0", 4 | "description": "Regular expression for matching a shebang line", 5 | "license": "MIT", 6 | "repository": "sindresorhus/shebang-regex", 7 | "author": { 8 | "name": "Sindre Sorhus", 9 | "email": "sindresorhus@gmail.com", 10 | "url": "sindresorhus.com" 11 | }, 12 | "engines": { 13 | "node": ">=8" 14 | }, 15 | "scripts": { 16 | "test": "xo && ava && tsd" 17 | }, 18 | "files": [ 19 | "index.js", 20 | "index.d.ts" 21 | ], 22 | "keywords": [ 23 | "regex", 24 | "regexp", 25 | "shebang", 26 | "match", 27 | "test", 28 | "line" 29 | ], 30 | "devDependencies": { 31 | "ava": "^1.4.1", 32 | "tsd": "^0.7.2", 33 | "xo": "^0.24.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /parallel-dev.yaml: -------------------------------------------------------------------------------- 1 | provider: claude 2 | metadata: 3 | generated_at: '2025-06-13T14:35:46.096487' 4 | source: haconiwa scan generate-parallel 5 | description: Example parallel development configuration 6 | tasks: 7 | - file: src/models/user.py 8 | prompt: Add validation methods and type hints 9 | - file: src/models/product.py 10 | prompt: Implement inventory tracking 11 | - file: src/models/order.py 12 | prompt: Add status management 13 | - file: src/api/routes/users.py 14 | prompt: Implement CRUD endpoints with validation 15 | - file: src/services/auth.py 16 | prompt: Add JWT authentication 17 | options: 18 | max_concurrent: 3 19 | timeout: 90 20 | allowed_tools: 21 | - Read 22 | - Write 23 | - Edit 24 | - MultiEdit 25 | permission_mode: confirmEach 26 | output_dir: ./parallel-dev-results 27 | -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/shebang-regex/readme.md: -------------------------------------------------------------------------------- 1 | # shebang-regex [![Build Status](https://travis-ci.org/sindresorhus/shebang-regex.svg?branch=master)](https://travis-ci.org/sindresorhus/shebang-regex) 2 | 3 | > Regular expression for matching a [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) line 4 | 5 | 6 | ## Install 7 | 8 | ``` 9 | $ npm install shebang-regex 10 | ``` 11 | 12 | 13 | ## Usage 14 | 15 | ```js 16 | const shebangRegex = require('shebang-regex'); 17 | 18 | const string = '#!/usr/bin/env node\nconsole.log("unicorns");'; 19 | 20 | shebangRegex.test(string); 21 | //=> true 22 | 23 | shebangRegex.exec(string)[0]; 24 | //=> '#!/usr/bin/env node' 25 | 26 | shebangRegex.exec(string)[1]; 27 | //=> '/usr/bin/env node' 28 | ``` 29 | 30 | 31 | ## License 32 | 33 | MIT © [Sindre Sorhus](https://sindresorhus.com) 34 | -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/isexe/LICENSE: -------------------------------------------------------------------------------- 1 | The ISC License 2 | 3 | Copyright (c) Isaac Z. Schlueter and Contributors 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/which/LICENSE: -------------------------------------------------------------------------------- 1 | The ISC License 2 | 3 | Copyright (c) Isaac Z. Schlueter and Contributors 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/path-key/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "path-key", 3 | "version": "3.1.1", 4 | "description": "Get the PATH environment variable key cross-platform", 5 | "license": "MIT", 6 | "repository": "sindresorhus/path-key", 7 | "author": { 8 | "name": "Sindre Sorhus", 9 | "email": "sindresorhus@gmail.com", 10 | "url": "sindresorhus.com" 11 | }, 12 | "engines": { 13 | "node": ">=8" 14 | }, 15 | "scripts": { 16 | "test": "xo && ava && tsd" 17 | }, 18 | "files": [ 19 | "index.js", 20 | "index.d.ts" 21 | ], 22 | "keywords": [ 23 | "path", 24 | "key", 25 | "environment", 26 | "env", 27 | "variable", 28 | "var", 29 | "get", 30 | "cross-platform", 31 | "windows" 32 | ], 33 | "devDependencies": { 34 | "@types/node": "^11.13.0", 35 | "ava": "^1.4.1", 36 | "tsd": "^0.7.2", 37 | "xo": "^0.24.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test_files/file2.py: -------------------------------------------------------------------------------- 1 | class Calculator: 2 | """簡易計算機クラス(加算・減算を順次適用)""" 3 | 4 | def __init__(self) -> None: 5 | self.result: int | float = 0 6 | 7 | def add(self, x: int | float) -> 'Calculator': 8 | """数値を加算する""" 9 | if not isinstance(x, (int, float)): 10 | raise TypeError("x must be a number") 11 | self.result += x 12 | return self 13 | 14 | def subtract(self, x: int | float) -> 'Calculator': 15 | """数値を減算する""" 16 | if not isinstance(x, (int, float)): 17 | raise TypeError("x must be a number") 18 | self.result -= x 19 | return self 20 | 21 | @property 22 | def value(self) -> int | float: 23 | """現在の計算結果を返す""" 24 | return self.result 25 | 26 | def get_result(self) -> int | float: 27 | """現在の計算結果を返す(互換性のため残す)""" 28 | return self.result -------------------------------------------------------------------------------- /src/haconiwa/resource/cli.py: -------------------------------------------------------------------------------- 1 | import typer 2 | from haconiwa.resource.path_scanner import PathScanner 3 | from haconiwa.resource.db_fetcher import DBFetcher 4 | 5 | resource_app = typer.Typer(help="リソース管理 (開発中)") 6 | 7 | @resource_app.command() 8 | def scan(directory: str, extension: str = ""): 9 | """ファイルパススキャンと拡張子フィルタ""" 10 | scanner = PathScanner(directory, extension) 11 | results = scanner.scan() 12 | typer.echo(f"スキャン結果: {results}") 13 | 14 | @resource_app.command() 15 | def pull(query: str): 16 | """データベースクエリ実行とデータ取得""" 17 | fetcher = DBFetcher() 18 | results = fetcher.execute_query(query) 19 | typer.echo(f"クエリ結果: {results}") 20 | 21 | @resource_app.command() 22 | def sync(remote: str): 23 | """リモートストレージ同期(S3/GCS等)""" 24 | typer.echo(f"{remote} との同期を開始します...") 25 | # リモートストレージ同期処理を実装 26 | typer.echo("同期が完了しました。") 27 | 28 | if __name__ == "__main__": 29 | resource_app() -------------------------------------------------------------------------------- /.github/RELEASE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Release v{VERSION} 2 | 3 | ## 🚀 What's New 4 | 5 | {BRIEF_DESCRIPTION} 6 | 7 | ## ✨ Added 8 | - 9 | 10 | ## 🔄 Changed 11 | - 12 | 13 | ## 🐛 Fixed 14 | - 15 | 16 | ## 📦 Installation 17 | 18 | ```bash 19 | pip install haconiwa=={VERSION} 20 | ``` 21 | 22 | ## 📝 Full Changelog 23 | 24 | **Full Changelog**: https://github.com/dai-motoki/haconiwa/compare/v{PREVIOUS_VERSION}...v{VERSION} 25 | 26 | For detailed changes, see [CHANGELOG.md](https://github.com/dai-motoki/haconiwa/blob/main/CHANGELOG.md). 27 | 28 | ## 🔗 Links 29 | 30 | - 📦 [PyPI Package](https://pypi.org/project/haconiwa/{VERSION}/) 31 | - 📖 [Documentation](https://github.com/dai-motoki/haconiwa#readme) 32 | - 🐛 [Report Issues](https://github.com/dai-motoki/haconiwa/issues) 33 | - 💬 [Discussions](https://github.com/dai-motoki/haconiwa/discussions) 34 | 35 | --- 36 | 37 | 🙏 **Thank you** to all contributors who made this release possible! -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/isexe/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "isexe", 3 | "version": "2.0.0", 4 | "description": "Minimal module to check if a file is executable.", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "devDependencies": { 10 | "mkdirp": "^0.5.1", 11 | "rimraf": "^2.5.0", 12 | "tap": "^10.3.0" 13 | }, 14 | "scripts": { 15 | "test": "tap test/*.js --100", 16 | "preversion": "npm test", 17 | "postversion": "npm publish", 18 | "postpublish": "git push origin --all; git push origin --tags" 19 | }, 20 | "author": "Isaac Z. Schlueter (http://blog.izs.me/)", 21 | "license": "ISC", 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/isaacs/isexe.git" 25 | }, 26 | "keywords": [], 27 | "bugs": { 28 | "url": "https://github.com/isaacs/isexe/issues" 29 | }, 30 | "homepage": "https://github.com/isaacs/isexe#readme" 31 | } 32 | -------------------------------------------------------------------------------- /tools/security-check/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "セキュリティチェック設定ファイル", 3 | "version": "1.0.0", 4 | "settings": { 5 | "strict_mode": false, 6 | "auto_fix": false, 7 | "ignore_warnings": false 8 | }, 9 | "custom_patterns": { 10 | "organization_specific": { 11 | "patterns": [ 12 | "internal\\.company\\.com", 13 | "staging\\.[a-zA-Z0-9-]+\\.internal" 14 | ], 15 | "severity": "WARNING", 16 | "description": "組織内部URL" 17 | } 18 | }, 19 | "excluded_extensions": [ 20 | ".png", ".jpg", ".jpeg", ".gif", ".ico", ".svg", 21 | ".woff", ".woff2", ".ttf", ".eot", 22 | ".mp3", ".mp4", ".wav", ".avi", 23 | ".zip", ".tar", ".gz", ".7z" 24 | ], 25 | "allowed_domains": [ 26 | "example.com", 27 | "test.example.org", 28 | "localhost", 29 | "127.0.0.1" 30 | ], 31 | "ci_integration": { 32 | "github_actions": true, 33 | "pre_commit_hook": true, 34 | "fail_on_error": true, 35 | "fail_on_warning": false 36 | } 37 | } -------------------------------------------------------------------------------- /organizations/org-01/workers/worker_b.py: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const WorkerB: React.FC = () => { 4 | return ( 5 |
6 | 7 | 8 | Worker B AIエージェント 9 | 10 | バックエンド開発専門のWorkerエージェント 11 | 12 | 13 | 14 |
    15 |
  • BaseAgentクラスからの継承とPython実装
  • 16 |
  • API開発・データベース設計・サーバー構築対応
  • 17 |
  • Python/Java/Go等のバックエンド言語対応
  • 18 |
  • Bossからの指示受信と実行結果の報告
  • 19 |
  • セキュリティ・パフォーマンス最適化
  • 20 |
  • インフラ構築とDevOps対応
  • 21 |
  • 障害対応と復旧処理
  • 22 |
23 |
24 |
25 |
26 | ); 27 | }; 28 | 29 | export default WorkerB; -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/isexe/windows.js: -------------------------------------------------------------------------------- 1 | module.exports = isexe 2 | isexe.sync = sync 3 | 4 | var fs = require('fs') 5 | 6 | function checkPathExt (path, options) { 7 | var pathext = options.pathExt !== undefined ? 8 | options.pathExt : process.env.PATHEXT 9 | 10 | if (!pathext) { 11 | return true 12 | } 13 | 14 | pathext = pathext.split(';') 15 | if (pathext.indexOf('') !== -1) { 16 | return true 17 | } 18 | for (var i = 0; i < pathext.length; i++) { 19 | var p = pathext[i].toLowerCase() 20 | if (p && path.substr(-p.length).toLowerCase() === p) { 21 | return true 22 | } 23 | } 24 | return false 25 | } 26 | 27 | function checkStat (stat, path, options) { 28 | if (!stat.isSymbolicLink() && !stat.isFile()) { 29 | return false 30 | } 31 | return checkPathExt(path, options) 32 | } 33 | 34 | function isexe (path, options, cb) { 35 | fs.stat(path, function (er, stat) { 36 | cb(er, er ? false : checkStat(stat, path, options)) 37 | }) 38 | } 39 | 40 | function sync (path, options) { 41 | return checkStat(fs.statSync(path), path, options) 42 | } 43 | -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/isexe/mode.js: -------------------------------------------------------------------------------- 1 | module.exports = isexe 2 | isexe.sync = sync 3 | 4 | var fs = require('fs') 5 | 6 | function isexe (path, options, cb) { 7 | fs.stat(path, function (er, stat) { 8 | cb(er, er ? false : checkStat(stat, options)) 9 | }) 10 | } 11 | 12 | function sync (path, options) { 13 | return checkStat(fs.statSync(path), options) 14 | } 15 | 16 | function checkStat (stat, options) { 17 | return stat.isFile() && checkMode(stat, options) 18 | } 19 | 20 | function checkMode (stat, options) { 21 | var mod = stat.mode 22 | var uid = stat.uid 23 | var gid = stat.gid 24 | 25 | var myUid = options.uid !== undefined ? 26 | options.uid : process.getuid && process.getuid() 27 | var myGid = options.gid !== undefined ? 28 | options.gid : process.getgid && process.getgid() 29 | 30 | var u = parseInt('100', 8) 31 | var g = parseInt('010', 8) 32 | var o = parseInt('001', 8) 33 | var ug = u | g 34 | 35 | var ret = (mod & o) || 36 | (mod & g) && gid === myGid || 37 | (mod & u) && uid === myUid || 38 | (mod & ug) && myUid === 0 39 | 40 | return ret 41 | } 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Daisuke Motoki 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /voice-systems/experimental/test_gemini_text_streaming.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Gemini テキストストリーミングテスト 4 | """ 5 | 6 | import os 7 | from google import genai 8 | from dotenv import load_dotenv 9 | 10 | load_dotenv() 11 | 12 | def test_gemini_text_streaming(): 13 | """Geminiのテキストストリーミングをテスト""" 14 | 15 | # 環境変数からAPI KEYを取得 16 | api_key = os.environ.get("GEMINI_API_KEY") 17 | if not api_key: 18 | print("エラー: GEMINI_API_KEYが設定されていません") 19 | return 20 | 21 | client = genai.Client(api_key=api_key) 22 | 23 | print("🤖 Gemini: ", end="", flush=True) 24 | 25 | try: 26 | for chunk in client.models.generate_content_stream( 27 | model="gemini-2.0-flash", 28 | contents="ハコニワプロジェクトの音声システムについて、簡潔に状況を教えてください" 29 | ): 30 | if hasattr(chunk, 'text') and chunk.text: 31 | print(chunk.text, end="", flush=True) 32 | 33 | print() # 改行 34 | print("✅ ストリーミング完了") 35 | 36 | except Exception as e: 37 | print(f"\nエラー: {e}") 38 | 39 | if __name__ == "__main__": 40 | test_gemini_text_streaming() -------------------------------------------------------------------------------- /haconiwa-npm/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Daisuke Motoki 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/path-key/license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Sindre Sorhus (sindresorhus.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/shebang-regex/license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Sindre Sorhus (sindresorhus.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/shebang-command/license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Kevin Mårtensson (github.com/kevva) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/cross-spawn/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Made With MOXY Lda 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/path-key/index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare namespace pathKey { 4 | interface Options { 5 | /** 6 | Use a custom environment variables object. Default: [`process.env`](https://nodejs.org/api/process.html#process_process_env). 7 | */ 8 | readonly env?: {[key: string]: string | undefined}; 9 | 10 | /** 11 | Get the PATH key for a specific platform. Default: [`process.platform`](https://nodejs.org/api/process.html#process_process_platform). 12 | */ 13 | readonly platform?: NodeJS.Platform; 14 | } 15 | } 16 | 17 | declare const pathKey: { 18 | /** 19 | Get the [PATH](https://en.wikipedia.org/wiki/PATH_(variable)) environment variable key cross-platform. 20 | 21 | @example 22 | ``` 23 | import pathKey = require('path-key'); 24 | 25 | const key = pathKey(); 26 | //=> 'PATH' 27 | 28 | const PATH = process.env[key]; 29 | //=> '/usr/local/bin:/usr/bin:/bin' 30 | ``` 31 | */ 32 | (options?: pathKey.Options): string; 33 | 34 | // TODO: Remove this for the next major release, refactor the whole definition to: 35 | // declare function pathKey(options?: pathKey.Options): string; 36 | // export = pathKey; 37 | default: typeof pathKey; 38 | }; 39 | 40 | export = pathKey; 41 | -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/which/bin/node-which: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var which = require("../") 3 | if (process.argv.length < 3) 4 | usage() 5 | 6 | function usage () { 7 | console.error('usage: which [-as] program ...') 8 | process.exit(1) 9 | } 10 | 11 | var all = false 12 | var silent = false 13 | var dashdash = false 14 | var args = process.argv.slice(2).filter(function (arg) { 15 | if (dashdash || !/^-/.test(arg)) 16 | return true 17 | 18 | if (arg === '--') { 19 | dashdash = true 20 | return false 21 | } 22 | 23 | var flags = arg.substr(1).split('') 24 | for (var f = 0; f < flags.length; f++) { 25 | var flag = flags[f] 26 | switch (flag) { 27 | case 's': 28 | silent = true 29 | break 30 | case 'a': 31 | all = true 32 | break 33 | default: 34 | console.error('which: illegal option -- ' + flag) 35 | usage() 36 | } 37 | } 38 | return false 39 | }) 40 | 41 | process.exit(args.reduce(function (pv, current) { 42 | try { 43 | var f = which.sync(current, { all: all }) 44 | if (all) 45 | f = f.join('\n') 46 | if (!silent) 47 | console.log(f) 48 | return pv; 49 | } catch (e) { 50 | return 1; 51 | } 52 | }, 0)) 53 | -------------------------------------------------------------------------------- /test-aicode-simple.yaml: -------------------------------------------------------------------------------- 1 | # 簡易版テストYAML - AICodeConfig最小限実装テスト 2 | --- 3 | apiVersion: haconiwa.dev/v1 4 | kind: AICodeConfig 5 | metadata: 6 | name: test-claude-config 7 | spec: 8 | provider: "claude" 9 | claude: 10 | settingsFile: "./claude-settings/settings.local.json" 11 | guidelinesFile: "./claude-settings/CLAUDE.md" 12 | targetCompany: "kamui-dev-company" 13 | 14 | --- 15 | apiVersion: haconiwa.dev/v1 16 | kind: Space 17 | metadata: 18 | name: kamui-dev-world-simple 19 | spec: 20 | nations: 21 | - id: jp 22 | name: "Japan" 23 | cities: 24 | - id: tokyo 25 | name: "Tokyo" 26 | villages: 27 | - id: kamui-village 28 | name: "Kamui Village" 29 | companies: 30 | - name: kamui-dev-company 31 | gitRepo: 32 | url: "https://github.com/dai-motoki/haconiwa" 33 | defaultBranch: "main" 34 | auth: "https" 35 | 36 | --- 37 | apiVersion: haconiwa.dev/v1 38 | kind: Task 39 | metadata: 40 | name: task_test_01 41 | spec: 42 | branch: "test/aicode-config" 43 | worktree: true 44 | assignee: "test-agent" 45 | spaceRef: "kamui-dev-company" 46 | description: "AICodeConfig test task" -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/which/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Isaac Z. Schlueter (http://blog.izs.me)", 3 | "name": "which", 4 | "description": "Like which(1) unix command. Find the first instance of an executable in the PATH.", 5 | "version": "2.0.2", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/isaacs/node-which.git" 9 | }, 10 | "main": "which.js", 11 | "bin": { 12 | "node-which": "./bin/node-which" 13 | }, 14 | "license": "ISC", 15 | "dependencies": { 16 | "isexe": "^2.0.0" 17 | }, 18 | "devDependencies": { 19 | "mkdirp": "^0.5.0", 20 | "rimraf": "^2.6.2", 21 | "tap": "^14.6.9" 22 | }, 23 | "scripts": { 24 | "test": "tap", 25 | "preversion": "npm test", 26 | "postversion": "npm publish", 27 | "prepublish": "npm run changelog", 28 | "prechangelog": "bash gen-changelog.sh", 29 | "changelog": "git add CHANGELOG.md", 30 | "postchangelog": "git commit -m 'update changelog - '${npm_package_version}", 31 | "postpublish": "git push origin --follow-tags" 32 | }, 33 | "files": [ 34 | "which.js", 35 | "bin/node-which" 36 | ], 37 | "tap": { 38 | "check-coverage": true 39 | }, 40 | "engines": { 41 | "node": ">= 8" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/parallel-dev-example.yaml: -------------------------------------------------------------------------------- 1 | # Claude Code SDK Parallel Development Example Configuration 2 | provider: claude 3 | tasks: 4 | - file: src/models/user.py 5 | prompt: Add comprehensive validation methods and type hints for all attributes 6 | - file: src/models/product.py 7 | prompt: Implement inventory tracking with stock management methods 8 | - file: src/models/order.py 9 | prompt: Add order status management with state transitions 10 | - file: src/services/auth.py 11 | prompt: Implement JWT authentication with refresh token support 12 | - file: src/services/payment.py 13 | prompt: Add payment gateway integration with error handling 14 | - file: src/api/routes/users.py 15 | prompt: Create RESTful CRUD endpoints with proper validation 16 | - file: src/api/routes/products.py 17 | prompt: Implement product search functionality with filtering 18 | - file: src/utils/validators.py 19 | prompt: Create comprehensive input validation functions 20 | - file: src/utils/formatters.py 21 | prompt: Add data formatting utilities for API responses 22 | - file: src/config/settings.py 23 | prompt: Update configuration structure with environment variables 24 | options: 25 | max_concurrent: 5 26 | timeout: 90 27 | allowed_tools: 28 | - Read 29 | - Write 30 | - Edit 31 | - MultiEdit -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Python 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | *.so 6 | 7 | # Distribution / packaging 8 | .Python 9 | build/ 10 | develop-eggs/ 11 | dist/ 12 | downloads/ 13 | eggs/ 14 | .eggs/ 15 | lib/ 16 | lib64/ 17 | parts/ 18 | sdist/ 19 | var/ 20 | wheels/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # Virtual environments 26 | .venv 27 | env/ 28 | venv/ 29 | ENV/ 30 | env.bak/ 31 | venv.bak/ 32 | 33 | # Environment variables 34 | .env 35 | .env.* 36 | .env.local 37 | !.env.*.example 38 | 39 | # IDE 40 | .vscode/ 41 | .idea/ 42 | *.swp 43 | *.swo 44 | *~ 45 | 46 | # OS 47 | .DS_Store 48 | Thumbs.db 49 | 50 | # haconiwa specific 51 | /worlds/*/state/ 52 | /organizations/*/tasks/in-progress/* 53 | /organizations/*/tasks/done/* 54 | .haconiwa_cache/ 55 | haconiwa-world/ 56 | haconiwa-dev-world/ 57 | haconiwa-dev-company/ 58 | kamui-dev-company.yaml 59 | kamui-dev-world/ 60 | kamui-dev-company/ 61 | 62 | # Test output and temporary directories 63 | test_output/ 64 | basic-executive-space/ 65 | test_cases/basic_executive/ 66 | test_cases/heavy_tasks/ 67 | test_cases/error_cases/ 68 | test_cases/minimal/ 69 | test-*/ 70 | *-test-*/ 71 | *.test-* 72 | 73 | # Parallel-dev specific 74 | parallel-dev-results/ 75 | test_claude_direct.py 76 | test_claude_sdk.py 77 | test_simple_claude.py 78 | test_parallel_yaml.yaml 79 | 80 | # Test results 81 | command_test_results.json -------------------------------------------------------------------------------- /scripts/check-relative-paths.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Check relative path usage in tmux panes 4 | # 5 | 6 | SESSION="${1:-test-company-multiroom-tasks}" 7 | 8 | echo "=== Checking relative path usage in session: $SESSION ===" 9 | echo 10 | 11 | # Check first 5 panes 12 | COUNT=0 13 | while read -r pane_info && [ $COUNT -lt 5 ]; do 14 | window_id=$(echo "$pane_info" | cut -d'.' -f1) 15 | pane_id=$(echo "$pane_info" | cut -d'.' -f2) 16 | 17 | echo "Checking pane $window_id.$pane_id:" 18 | 19 | # Capture command history 20 | content=$(tmux capture-pane -t "$SESSION:$window_id.$pane_id" -p -S -30) 21 | 22 | # Look for cd commands 23 | if echo "$content" | grep -q "cd tasks/"; then 24 | echo " ✅ Found relative path: cd tasks/..." 25 | elif echo "$content" | grep -q "cd standby"; then 26 | echo " ✅ Found relative path: cd standby" 27 | elif echo "$content" | grep -q "cd /"; then 28 | echo " ❌ Found absolute path: cd /..." 29 | else 30 | echo " ⚠️ No cd command found" 31 | fi 32 | 33 | # Extract the cd command line 34 | cd_line=$(echo "$content" | grep -E "cd.*&&.*claude" | tail -1) 35 | if [ -n "$cd_line" ]; then 36 | echo " Command: $cd_line" 37 | fi 38 | 39 | echo 40 | ((COUNT++)) 41 | done < <(tmux list-panes -t "$SESSION" -F "#{window_index}.#{pane_index}") -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/cross-spawn/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const cp = require('child_process'); 4 | const parse = require('./lib/parse'); 5 | const enoent = require('./lib/enoent'); 6 | 7 | function spawn(command, args, options) { 8 | // Parse the arguments 9 | const parsed = parse(command, args, options); 10 | 11 | // Spawn the child process 12 | const spawned = cp.spawn(parsed.command, parsed.args, parsed.options); 13 | 14 | // Hook into child process "exit" event to emit an error if the command 15 | // does not exists, see: https://github.com/IndigoUnited/node-cross-spawn/issues/16 16 | enoent.hookChildProcess(spawned, parsed); 17 | 18 | return spawned; 19 | } 20 | 21 | function spawnSync(command, args, options) { 22 | // Parse the arguments 23 | const parsed = parse(command, args, options); 24 | 25 | // Spawn the child process 26 | const result = cp.spawnSync(parsed.command, parsed.args, parsed.options); 27 | 28 | // Analyze if the command does not exist, see: https://github.com/IndigoUnited/node-cross-spawn/issues/16 29 | result.error = result.error || enoent.verifyENOENTSync(result.status, parsed); 30 | 31 | return result; 32 | } 33 | 34 | module.exports = spawn; 35 | module.exports.spawn = spawn; 36 | module.exports.sync = spawnSync; 37 | 38 | module.exports._parse = parse; 39 | module.exports._enoent = enoent; 40 | -------------------------------------------------------------------------------- /tests/unit/test_resource.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pathlib import Path 3 | from src.haconiwa.resource.path_scanner import PathScanner 4 | from src.haconiwa.resource.db_fetcher import DBFetcher 5 | import sqlite3 6 | 7 | def test_file_scan(): 8 | scanner = PathScanner() 9 | result = scanner.scan_directory("/path/to/test/directory") 10 | assert isinstance(result, list) 11 | assert all(isinstance(file, Path) for file in result) 12 | 13 | def test_file_formats(): 14 | scanner = PathScanner() 15 | result = scanner.scan_directory("/path/to/test/directory", extensions=[".txt", ".md"]) 16 | assert all(file.suffix in [".txt", ".md"] for file in result) 17 | 18 | def test_large_file_handling(): 19 | scanner = PathScanner() 20 | result = scanner.scan_directory("/path/to/large/files") 21 | assert len(result) > 1000 22 | 23 | def test_db_connection(): 24 | fetcher = DBFetcher("sqlite:///test.db") 25 | connection = fetcher.get_connection() 26 | assert isinstance(connection, sqlite3.Connection) 27 | 28 | def test_db_query(): 29 | fetcher = DBFetcher("sqlite:///test.db") 30 | result = fetcher.execute_query("SELECT * FROM test_table") 31 | assert isinstance(result, list) 32 | 33 | def test_db_error_handling(): 34 | fetcher = DBFetcher("sqlite:///non_existent.db") 35 | with pytest.raises(sqlite3.OperationalError): 36 | fetcher.get_connection() -------------------------------------------------------------------------------- /haconiwa-npm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "haconiwa", 3 | "version": "0.4.0", 4 | "description": "AI collaborative development support CLI tool - tmux company management, git-worktree integration, task management, and AI agent coordination", 5 | "main": "index.js", 6 | "bin": { 7 | "haconiwa": "./bin/haconiwa" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1", 11 | "prepublishOnly": "node check-python.js" 12 | }, 13 | "keywords": [ 14 | "ai", 15 | "collaborative", 16 | "development", 17 | "tmux", 18 | "git-worktree", 19 | "task-management", 20 | "agent", 21 | "cli", 22 | "python", 23 | "wrapper" 24 | ], 25 | "author": "Daisuke Motoki ", 26 | "license": "MIT", 27 | "repository": { 28 | "type": "git", 29 | "url": "git+https://github.com/dai-motoki/haconiwa.git" 30 | }, 31 | "bugs": { 32 | "url": "https://github.com/dai-motoki/haconiwa/issues" 33 | }, 34 | "homepage": "https://github.com/dai-motoki/haconiwa#readme", 35 | "engines": { 36 | "node": ">=12.0.0" 37 | }, 38 | "dependencies": { 39 | "cross-spawn": "^7.0.3" 40 | }, 41 | "devDependencies": {}, 42 | "files": [ 43 | "bin/", 44 | "index.js", 45 | "README.md", 46 | "LICENSE" 47 | ], 48 | "preferGlobal": true, 49 | "os": [ 50 | "darwin", 51 | "linux", 52 | "win32" 53 | ] 54 | } -------------------------------------------------------------------------------- /debug_apply_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Debug script for CLI apply command test failure 4 | """ 5 | 6 | import sys 7 | sys.path.insert(0, 'src') 8 | 9 | from unittest.mock import patch, MagicMock, mock_open 10 | from typer.testing import CliRunner 11 | from haconiwa.cli import app 12 | from haconiwa.core.crd.models import SpaceCRD 13 | 14 | def main(): 15 | runner = CliRunner() 16 | 17 | # Mock CRD object with proper metadata structure 18 | mock_space_crd = MagicMock(spec=SpaceCRD) 19 | mock_metadata = MagicMock() 20 | mock_metadata.name = 'test-space' 21 | mock_space_crd.metadata = mock_metadata 22 | 23 | with patch('haconiwa.core.crd.parser.CRDParser.parse_file', return_value=mock_space_crd), \ 24 | patch('pathlib.Path.exists', return_value=True), \ 25 | patch('builtins.open', mock_open(read_data="yaml content")), \ 26 | patch('haconiwa.core.applier.CRDApplier.apply') as mock_apply: 27 | 28 | result = runner.invoke(app, ['apply', '-f', 'test.yaml']) 29 | print(f'Exit code: {result.exit_code}') 30 | print(f'Stdout: {result.stdout}') 31 | if result.exception: 32 | print(f'Exception: {result.exception}') 33 | import traceback 34 | traceback.print_exception(type(result.exception), result.exception, result.exception.__traceback__) 35 | 36 | if __name__ == "__main__": 37 | main() -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/isexe/index.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var core 3 | if (process.platform === 'win32' || global.TESTING_WINDOWS) { 4 | core = require('./windows.js') 5 | } else { 6 | core = require('./mode.js') 7 | } 8 | 9 | module.exports = isexe 10 | isexe.sync = sync 11 | 12 | function isexe (path, options, cb) { 13 | if (typeof options === 'function') { 14 | cb = options 15 | options = {} 16 | } 17 | 18 | if (!cb) { 19 | if (typeof Promise !== 'function') { 20 | throw new TypeError('callback not provided') 21 | } 22 | 23 | return new Promise(function (resolve, reject) { 24 | isexe(path, options || {}, function (er, is) { 25 | if (er) { 26 | reject(er) 27 | } else { 28 | resolve(is) 29 | } 30 | }) 31 | }) 32 | } 33 | 34 | core(path, options || {}, function (er, is) { 35 | // ignore EACCES because that just means we aren't allowed to run it 36 | if (er) { 37 | if (er.code === 'EACCES' || options && options.ignoreErrors) { 38 | er = null 39 | is = false 40 | } 41 | } 42 | cb(er, is) 43 | }) 44 | } 45 | 46 | function sync (path, options) { 47 | // my kingdom for a filtered catch 48 | try { 49 | return core.sync(path, options || {}) 50 | } catch (er) { 51 | if (options && options.ignoreErrors || er.code === 'EACCES') { 52 | return false 53 | } else { 54 | throw er 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /organizations/org-01/boss/boss.py: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { Card, CardHeader, CardTitle, CardDescription, CardContent } from './src/components/ui/card'; 3 | 4 | const boss: React.FC = () => { 5 | return ( 6 |
7 |
8 | 9 | 10 | Boss AIエージェント 11 | 12 | タスクブランチ分解、割り当て、Worker監視、進捗管理を行うAIエージェントです。 13 | 14 | 15 | 16 |
17 |

機能

18 |
    19 |
  • BaseAgentクラスからの継承
  • 20 |
  • タスクブランチ分解と割り当て戦略の実装
  • 21 |
  • Worker監視と進捗管理
  • 22 |
  • 意思決定ロジック(Python実装)
  • 23 |
  • エラーハンドリングと復旧処理
  • 24 |
  • 学習・最適化機能
  • 25 |
  • レポート生成とログ出力
  • 26 |
  • 外部システムとの連携インターフェース
  • 27 |
28 |
29 |
30 |
31 |
32 |
33 | ); 34 | }; 35 | export default boss; 36 | -------------------------------------------------------------------------------- /haconiwa-npm/check-python.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Pre-publish check script for haconiwa npm package 5 | * Ensures Python and haconiwa are available before publishing 6 | */ 7 | 8 | const { checkHaconiwaInstallation } = require('./bin/haconiwa'); 9 | 10 | function main() { 11 | console.log('🔍 Checking Python and haconiwa installation...\n'); 12 | 13 | const installationType = checkHaconiwaInstallation(); 14 | 15 | if (!installationType) { 16 | console.error('❌ Pre-publish check failed!'); 17 | console.error(''); 18 | console.error('Haconiwa Python package is not available.'); 19 | console.error('Please ensure haconiwa is installed via pip:'); 20 | console.error(''); 21 | console.error(' pip install haconiwa --upgrade'); 22 | console.error(''); 23 | console.error('This npm package is a wrapper for the Python haconiwa package.'); 24 | console.error('The Python package must be available for testing.'); 25 | console.error(''); 26 | process.exit(1); 27 | } 28 | 29 | console.log('✅ Python haconiwa package is available!'); 30 | console.log(`📦 Installation type: ${installationType}`); 31 | console.log(''); 32 | console.log('🚀 Ready to publish npm package.'); 33 | console.log(''); 34 | console.log('Note: Users will need to install the Python package separately:'); 35 | console.log(' pip install haconiwa'); 36 | console.log(''); 37 | } 38 | 39 | if (require.main === module) { 40 | main(); 41 | } -------------------------------------------------------------------------------- /examples/demo_flow.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # 色の定義 6 | GREEN='\033[0;32m' 7 | BLUE='\033[0;34m' 8 | NC='\033[0m' 9 | 10 | echo_step() { 11 | echo -e "${BLUE}===> $1${NC}" 12 | sleep 1 13 | } 14 | 15 | cleanup() { 16 | echo_step "クリーンアップを実行中..." 17 | haconiwa watch stop 18 | haconiwa agent stop --all 19 | haconiwa world destroy local-dev 20 | } 21 | 22 | trap cleanup EXIT 23 | 24 | # 初期化 25 | echo_step "箱庭環境を初期化中..." 26 | haconiwa core init 27 | 28 | # 開発環境の作成 29 | echo_step "開発用ワールドを作成中..." 30 | haconiwa world create local-dev 31 | 32 | # tmux区画の設定 33 | echo_step "作業スペースを構築中..." 34 | haconiwa space create --layout=dev 35 | 36 | # AIエージェントの起動 37 | echo_step "AIエージェントを起動中..." 38 | haconiwa agent spawn boss --name main-boss 39 | haconiwa agent spawn worker --name frontend-worker --type frontend 40 | haconiwa agent spawn worker --name backend-worker --type backend 41 | haconiwa agent spawn worker --name qa-worker --type qa 42 | 43 | # タスクブランチの作成と割り当て 44 | echo_step "タスクブランチを作成・割り当て中..." 45 | TASK_ID=$(haconiwa task new --title "新機能実装" --description "ログイン機能の実装" --output=id) 46 | haconiwa task assign $TASK_ID --to frontend-worker 47 | 48 | # 監視の開始 49 | echo_step "システム監視を開始中..." 50 | haconiwa watch start --metrics=all 51 | 52 | # 開発作業のシミュレーション 53 | echo_step "開発作業をシミュレート中..." 54 | sleep 5 55 | 56 | echo -e "${GREEN}フロントエンドワーカーがタスクブランチを実行中...${NC}" 57 | sleep 3 58 | 59 | echo -e "${GREEN}QAワーカーがテストを実行中...${NC}" 60 | sleep 3 61 | 62 | echo -e "${GREEN}タスクブランチが完了しました${NC}" 63 | haconiwa task done $TASK_ID 64 | 65 | echo_step "デモが完了しました" -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/which/README.md: -------------------------------------------------------------------------------- 1 | # which 2 | 3 | Like the unix `which` utility. 4 | 5 | Finds the first instance of a specified executable in the PATH 6 | environment variable. Does not cache the results, so `hash -r` is not 7 | needed when the PATH changes. 8 | 9 | ## USAGE 10 | 11 | ```javascript 12 | var which = require('which') 13 | 14 | // async usage 15 | which('node', function (er, resolvedPath) { 16 | // er is returned if no "node" is found on the PATH 17 | // if it is found, then the absolute path to the exec is returned 18 | }) 19 | 20 | // or promise 21 | which('node').then(resolvedPath => { ... }).catch(er => { ... not found ... }) 22 | 23 | // sync usage 24 | // throws if not found 25 | var resolved = which.sync('node') 26 | 27 | // if nothrow option is used, returns null if not found 28 | resolved = which.sync('node', {nothrow: true}) 29 | 30 | // Pass options to override the PATH and PATHEXT environment vars. 31 | which('node', { path: someOtherPath }, function (er, resolved) { 32 | if (er) 33 | throw er 34 | console.log('found at %j', resolved) 35 | }) 36 | ``` 37 | 38 | ## CLI USAGE 39 | 40 | Same as the BSD `which(1)` binary. 41 | 42 | ``` 43 | usage: which [-as] program ... 44 | ``` 45 | 46 | ## OPTIONS 47 | 48 | You may pass an options object as the second argument. 49 | 50 | - `path`: Use instead of the `PATH` environment variable. 51 | - `pathExt`: Use instead of the `PATHEXT` environment variable. 52 | - `all`: Return all matches, instead of just the first one. Note that 53 | this means the function returns an array of strings instead of a 54 | single string. 55 | -------------------------------------------------------------------------------- /tests/unit/test_watch.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from unittest.mock import MagicMock, patch 3 | from src.haconiwa.watch.monitor import Monitor 4 | 5 | @pytest.fixture 6 | def monitor(): 7 | return Monitor() 8 | 9 | def test_metrics_collection(monitor): 10 | monitor.collect_metrics = MagicMock(return_value={"cpu": 50, "memory": 1024}) 11 | metrics = monitor.collect_metrics() 12 | assert metrics["cpu"] == 50 13 | assert metrics["memory"] == 1024 14 | 15 | def test_alert_functionality(monitor): 16 | monitor.alert = MagicMock() 17 | monitor.alert("High CPU usage") 18 | monitor.alert.assert_called_with("High CPU usage") 19 | 20 | @patch("src.haconiwa.watch.monitor.prometheus_client") 21 | def test_prometheus_integration(mock_prometheus, monitor): 22 | monitor.export_metrics_to_prometheus = MagicMock() 23 | monitor.export_metrics_to_prometheus() 24 | monitor.export_metrics_to_prometheus.assert_called_once() 25 | 26 | def test_performance_monitoring(monitor): 27 | monitor.check_performance = MagicMock(return_value=True) 28 | assert monitor.check_performance() is True 29 | 30 | def test_log_rotation_and_archiving(monitor): 31 | monitor.rotate_logs = MagicMock() 32 | monitor.archive_logs = MagicMock() 33 | monitor.rotate_logs() 34 | monitor.archive_logs() 35 | monitor.rotate_logs.assert_called_once() 36 | monitor.archive_logs.assert_called_once() 37 | 38 | def test_integration_with_monitoring_library(monitor): 39 | monitor.integrate_with_library = MagicMock() 40 | monitor.integrate_with_library() 41 | monitor.integrate_with_library.assert_called_once() -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/isexe/README.md: -------------------------------------------------------------------------------- 1 | # isexe 2 | 3 | Minimal module to check if a file is executable, and a normal file. 4 | 5 | Uses `fs.stat` and tests against the `PATHEXT` environment variable on 6 | Windows. 7 | 8 | ## USAGE 9 | 10 | ```javascript 11 | var isexe = require('isexe') 12 | isexe('some-file-name', function (err, isExe) { 13 | if (err) { 14 | console.error('probably file does not exist or something', err) 15 | } else if (isExe) { 16 | console.error('this thing can be run') 17 | } else { 18 | console.error('cannot be run') 19 | } 20 | }) 21 | 22 | // same thing but synchronous, throws errors 23 | var isExe = isexe.sync('some-file-name') 24 | 25 | // treat errors as just "not executable" 26 | isexe('maybe-missing-file', { ignoreErrors: true }, callback) 27 | var isExe = isexe.sync('maybe-missing-file', { ignoreErrors: true }) 28 | ``` 29 | 30 | ## API 31 | 32 | ### `isexe(path, [options], [callback])` 33 | 34 | Check if the path is executable. If no callback provided, and a 35 | global `Promise` object is available, then a Promise will be returned. 36 | 37 | Will raise whatever errors may be raised by `fs.stat`, unless 38 | `options.ignoreErrors` is set to true. 39 | 40 | ### `isexe.sync(path, [options])` 41 | 42 | Same as `isexe` but returns the value and throws any errors raised. 43 | 44 | ### Options 45 | 46 | * `ignoreErrors` Treat all errors as "no, this is not executable", but 47 | don't raise them. 48 | * `uid` Number to use as the user id 49 | * `gid` Number to use as the group id 50 | * `pathExt` List of path extensions to use instead of `PATHEXT` 51 | environment variable on Windows. 52 | -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/path-key/readme.md: -------------------------------------------------------------------------------- 1 | # path-key [![Build Status](https://travis-ci.org/sindresorhus/path-key.svg?branch=master)](https://travis-ci.org/sindresorhus/path-key) 2 | 3 | > Get the [PATH](https://en.wikipedia.org/wiki/PATH_(variable)) environment variable key cross-platform 4 | 5 | It's usually `PATH`, but on Windows it can be any casing like `Path`... 6 | 7 | 8 | ## Install 9 | 10 | ``` 11 | $ npm install path-key 12 | ``` 13 | 14 | 15 | ## Usage 16 | 17 | ```js 18 | const pathKey = require('path-key'); 19 | 20 | const key = pathKey(); 21 | //=> 'PATH' 22 | 23 | const PATH = process.env[key]; 24 | //=> '/usr/local/bin:/usr/bin:/bin' 25 | ``` 26 | 27 | 28 | ## API 29 | 30 | ### pathKey(options?) 31 | 32 | #### options 33 | 34 | Type: `object` 35 | 36 | ##### env 37 | 38 | Type: `object`
39 | Default: [`process.env`](https://nodejs.org/api/process.html#process_process_env) 40 | 41 | Use a custom environment variables object. 42 | 43 | #### platform 44 | 45 | Type: `string`
46 | Default: [`process.platform`](https://nodejs.org/api/process.html#process_process_platform) 47 | 48 | Get the PATH key for a specific platform. 49 | 50 | 51 | --- 52 | 53 |
54 | 55 | Get professional support for this package with a Tidelift subscription 56 | 57 |
58 | 59 | Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies. 60 |
61 |
62 | -------------------------------------------------------------------------------- /src/haconiwa/__init__.py: -------------------------------------------------------------------------------- 1 | from importlib.metadata import version 2 | from typing import Dict, Any 3 | 4 | from .core.config import Config 5 | from .core.logging import setup_logging 6 | from .core.state import StateManager 7 | from .world.provider.local import LocalProvider 8 | 9 | try: 10 | from .world.provider.docker import DockerProvider 11 | except ImportError: 12 | DockerProvider = None 13 | 14 | from .agent.base import BaseAgent 15 | from .agent.boss import BossAgent 16 | from .agent.worker import WorkerAgent 17 | from .agent.manager import AgentManager 18 | from .task.worktree import WorktreeManager 19 | from .watch.monitor import Monitor 20 | 21 | __version__ = version("haconiwa") 22 | 23 | DEFAULT_CONFIG: Dict[str, Any] = { 24 | "log_level": "INFO", 25 | "data_dir": "~/.haconiwa", 26 | "world": { 27 | "default_provider": "local", 28 | "providers": { 29 | "local": {"class": "LocalProvider"}, 30 | "docker": {"class": "DockerProvider"} 31 | } 32 | }, 33 | "agent": { 34 | "types": { 35 | "boss": {"class": "BossAgent"}, 36 | "worker": {"class": "WorkerAgent"}, 37 | "manager": {"class": "AgentManager"} 38 | } 39 | } 40 | } 41 | 42 | def initialize() -> None: 43 | """Initialize haconiwa with default configuration.""" 44 | setup_logging("INFO") 45 | 46 | __all__ = [ 47 | "Config", 48 | "StateManager", 49 | "LocalProvider", 50 | ] 51 | 52 | if DockerProvider: 53 | __all__.append("DockerProvider") 54 | 55 | __all__.extend([ 56 | "BaseAgent", 57 | "BossAgent", 58 | "WorkerAgent", 59 | "AgentManager", 60 | "WorktreeManager", 61 | "Monitor", 62 | "initialize", 63 | "__version__" 64 | ]) -------------------------------------------------------------------------------- /docs/readme_additions.md: -------------------------------------------------------------------------------- 1 | # README_JA.md 追加内容 2 | 3 | ## コマンドリファレンスセクションに追加 4 | 5 | ### `claude` - Claude Code SDK並列実行コマンド 🚧 **開発中** 6 | Claude Code SDKを使用した高速並列ファイル編集機能 7 | - `haconiwa claude parallel` - 複数ファイルの並列編集実行 8 | - `haconiwa claude parallel --from-yaml ` - YAML設定からの並列実行 9 | - `haconiwa claude status` - 実行中タスクブランチの状態確認 10 | - `haconiwa claude cancel ` - 実行中タスクブランチのキャンセル 11 | 12 | **主な機能:** 13 | - 🚀 **高速並列処理**: 最大10ファイルの同時編集 14 | - 📝 **柔軟なプロンプト指定**: ファイルごとに個別のプロンプト 15 | - 🎯 **セマフォ制御**: 同時実行数の制限でAPI負荷を管理 16 | - 📊 **リアルタイム進捗表示**: 処理状況の可視化 17 | - 🔧 **エラーハンドリング**: 個別失敗でも他タスクブランチは継続 18 | 19 | **使用例:** 20 | ```bash 21 | # 基本的な並列編集(3ファイル) 22 | haconiwa claude parallel \ 23 | --files src/main.py,src/utils.py,src/api.py \ 24 | --prompts "Add type hints","Refactor functions","Add error handling" 25 | 26 | # 10ファイルの一斉修正 27 | haconiwa claude parallel \ 28 | --file-list files.txt \ 29 | --prompt-file prompts.txt \ 30 | --max-concurrent 5 \ 31 | --timeout 120 32 | 33 | # YAML設定ファイルから実行 34 | haconiwa claude parallel --from-yaml parallel-edits.yaml 35 | ``` 36 | 37 | ## 開発中機能セクションに追加 38 | 39 | ### 🚧 開発中機能 40 | - AIエージェントの生成と管理 (プレースホルダー → 実装) 41 | - git-worktreeとのタスクブランチ管理 (プレースホルダー → 実装) 42 | - リソーススキャン機能 (プレースホルダー → 実装) 43 | - リアルタイム監視システム (プレースホルダー → 実装) 44 | - ワールド/環境管理 (プレースホルダー → 実装) 45 | - **🆕 Claude Code SDK並列実行機能** (設計 → 実装中) 46 | - 複数ファイルの並列編集 47 | - asyncio.gatherによる高速処理 48 | - 柔軟なプロンプト管理 49 | - エラーハンドリングと進捗表示 50 | 51 | ## 主な機能セクションに追加 52 | 53 | - 🤖 **AIエージェント管理**: Boss/Workerエージェントの作成・監視 54 | - 📦 **ワールド管理**: 開発環境の構築・管理 55 | - 🖥️ **tmux会社連携**: 開発スペースの効率的な管理 56 | - 📋 **タスクブランチ管理**: git-worktreeと連携したタスクブランチ管理システム 57 | - 📊 **リソース管理**: DBやファイルパスの効率的なスキャン 58 | - 👁️ **リアルタイム監視**: エージェントやタスクブランチの進捗監視 59 | - **🚀 Claude Code SDK並列実行**: 最大10ファイルの同時編集による高速開発支援(開発中) -------------------------------------------------------------------------------- /src/haconiwa/agent/manager.py: -------------------------------------------------------------------------------- 1 | """ 2 | Agent Manager for Haconiwa v1.0 3 | """ 4 | 5 | import logging 6 | from typing import Dict, Any 7 | 8 | logger = logging.getLogger(__name__) 9 | 10 | 11 | class AgentManager: 12 | """Agent manager for AI agent lifecycle""" 13 | 14 | def __init__(self): 15 | self.agents = {} 16 | 17 | def create_agent(self, config: Dict[str, Any]) -> bool: 18 | """Create agent from configuration""" 19 | try: 20 | name = config.get("name") 21 | role = config.get("role", "worker") 22 | model = config.get("model", "gpt-4o") 23 | 24 | self.agents[name] = { 25 | "config": config, 26 | "status": "created" 27 | } 28 | 29 | logger.info(f"Created agent: {name} (role: {role}, model: {model})") 30 | return True 31 | 32 | except Exception as e: 33 | logger.error(f"Failed to create agent: {e}") 34 | return False 35 | 36 | def allocate_resources(self, tasks): 37 | with self.lock: 38 | # リソース配分ロジック 39 | pass 40 | 41 | def resolve_conflicts(self, agents): 42 | with self.lock: 43 | # 競合解決ロジック 44 | pass 45 | 46 | def optimize_processes(self): 47 | # 全体最適化ロジック 48 | pass 49 | 50 | def facilitate_communication(self, agents): 51 | # コミュニケーション促進ロジック 52 | pass 53 | 54 | def ensure_quality(self, standards): 55 | # 品質保証ロジック 56 | pass 57 | 58 | def improve_processes(self): 59 | # プロセス改善ロジック 60 | pass 61 | 62 | def handle_incidents(self, incident): 63 | # 障害対応ロジック 64 | pass 65 | 66 | def manage_collaboration(self, agents): 67 | # 協調制御ロジック 68 | pass -------------------------------------------------------------------------------- /tools/security-check/nglist.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "description": "個人用NGワードリスト - このファイルをnglist.jsonにコピーして使用してください", 3 | "version": "1.1.0", 4 | "user_specific_patterns": { 5 | "personal_paths": { 6 | "patterns": [ 7 | "/Users/your_username", 8 | "/home/your_username", 9 | "C:\\\\Users\\\\your_username" 10 | ], 11 | "severity": "ERROR", 12 | "description": "個人のフルパス" 13 | }, 14 | "personal_emails": { 15 | "patterns": [ 16 | "dai\\.motoki1123@gmail\\.com", 17 | "your_email@company\\.com" 18 | ], 19 | "severity": "WARNING", 20 | "description": "個人のメールアドレス" 21 | }, 22 | "personal_domains": { 23 | "patterns": [ 24 | "mydomain\\.local", 25 | "internal\\.mycompany\\.com" 26 | ], 27 | "severity": "WARNING", 28 | "description": "個人/組織固有のドメイン" 29 | }, 30 | "api_key_prefixes": { 31 | "patterns": [ 32 | "sk-proj-[a-zA-Z0-9]{20,}", 33 | "gho_[a-zA-Z0-9]{20,}", 34 | "ghp_[a-zA-Z0-9]{20,}" 35 | ], 36 | "severity": "ERROR", 37 | "description": "特定のAPIキープレフィックス" 38 | } 39 | }, 40 | "whitelist_patterns": { 41 | "safe_placeholders": [ 42 | "your_username", 43 | "your_email", 44 | "your_api_key", 45 | "motokidaisuke", 46 | "username", 47 | "example", 48 | "placeholder", 49 | "sample", 50 | "dummy" 51 | ], 52 | "safe_domains": [ 53 | "example.com", 54 | "test.example.org", 55 | "localhost", 56 | "127.0.0.1" 57 | ] 58 | }, 59 | "env_files": { 60 | "description": "環境変数ファイルの内容を無視するファイル一覧", 61 | "files": [ 62 | ".env", 63 | ".env.local", 64 | ".env.development", 65 | ".env.production", 66 | ".env.staging", 67 | ".env.test" 68 | ] 69 | } 70 | } -------------------------------------------------------------------------------- /src/haconiwa/core/state.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import pickle 4 | import threading 5 | import asyncio 6 | from typing import Any, Dict, Optional 7 | 8 | class StateManager: 9 | def __init__(self, config_path: str): 10 | self.config_path = config_path 11 | self.state = {} 12 | self.lock = threading.Lock() 13 | 14 | def load_state(self, file_path: str) -> None: 15 | if os.path.exists(file_path): 16 | with open(file_path, 'rb') as f: 17 | self.state = pickle.load(f) 18 | 19 | def save_state(self, file_path: str) -> None: 20 | with open(file_path, 'wb') as f: 21 | pickle.dump(self.state, f) 22 | 23 | def update_state(self, key: str, value: Any) -> None: 24 | with self.lock: 25 | self.state[key] = value 26 | 27 | def get_state(self, key: str) -> Optional[Any]: 28 | return self.state.get(key) 29 | 30 | def rollback_state(self, history_file: str) -> None: 31 | if os.path.exists(history_file): 32 | with open(history_file, 'rb') as f: 33 | self.state = pickle.load(f) 34 | 35 | async def sync_state(self, remote_path: str) -> None: 36 | await asyncio.sleep(1) # Simulate network delay 37 | with open(remote_path, 'w') as f: 38 | json.dump(self.state, f) 39 | 40 | def check_and_repair(self) -> None: 41 | # Implement consistency check and repair logic 42 | pass 43 | 44 | def optimize_memory(self) -> None: 45 | # Implement memory optimization logic 46 | pass 47 | 48 | def optimize_disk(self) -> None: 49 | # Implement disk optimization logic 50 | pass 51 | 52 | # Example usage 53 | state_manager = StateManager(config_path='config.yaml') 54 | state_manager.load_state('state.pkl') 55 | state_manager.update_state('world', {'status': 'active'}) 56 | state_manager.save_state('state.pkl') -------------------------------------------------------------------------------- /organizations/org-01/workers/worker_c.py: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { Card, CardHeader, CardTitle, CardDescription, CardContent } from './src/components/Card'; 3 | 4 | const worker_c: React.FC = () => { 5 | return ( 6 |
7 |
8 | 9 | 10 | Worker C: QA/テスト専門エージェント 11 | 12 | 自動テスト設計、実行、結果検証を行うQA/テスト専門のWorkerエージェントです。 13 | 14 | 15 | 16 |
17 |

主な機能

18 |
    19 |
  • 自動テストの設計・実行・結果検証
  • 20 |
  • 品質保証とバグレポートの作成
  • 21 |
  • Bossからの指示に基づくテスト戦略の実装
  • 22 |
  • パフォーマンステスト・セキュリティテストへの対応
  • 23 |
  • CI/CDパイプラインとの統合
  • 24 |
  • テストデータ管理と環境構築
  • 25 |
26 |
27 |
28 |

得意分野

29 |

30 | 品質保証、テスト自動化、CI/CD連携 31 |

32 |
33 |
34 |

技術スタック

35 |

36 | Python, pytest, Selenium, Jenkins, JUnit 37 |

38 |
39 |
40 |
41 |
42 |
43 | ); 44 | }; 45 | 46 | export default worker_c; 47 | -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/cross-spawn/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cross-spawn", 3 | "version": "7.0.6", 4 | "description": "Cross platform child_process#spawn and child_process#spawnSync", 5 | "keywords": [ 6 | "spawn", 7 | "spawnSync", 8 | "windows", 9 | "cross-platform", 10 | "path-ext", 11 | "shebang", 12 | "cmd", 13 | "execute" 14 | ], 15 | "author": "André Cruz ", 16 | "homepage": "https://github.com/moxystudio/node-cross-spawn", 17 | "repository": { 18 | "type": "git", 19 | "url": "git@github.com:moxystudio/node-cross-spawn.git" 20 | }, 21 | "license": "MIT", 22 | "main": "index.js", 23 | "files": [ 24 | "lib" 25 | ], 26 | "scripts": { 27 | "lint": "eslint .", 28 | "test": "jest --env node --coverage", 29 | "prerelease": "npm t && npm run lint", 30 | "release": "standard-version", 31 | "postrelease": "git push --follow-tags origin HEAD && npm publish" 32 | }, 33 | "husky": { 34 | "hooks": { 35 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS", 36 | "pre-commit": "lint-staged" 37 | } 38 | }, 39 | "lint-staged": { 40 | "*.js": [ 41 | "eslint --fix", 42 | "git add" 43 | ] 44 | }, 45 | "commitlint": { 46 | "extends": [ 47 | "@commitlint/config-conventional" 48 | ] 49 | }, 50 | "dependencies": { 51 | "path-key": "^3.1.0", 52 | "shebang-command": "^2.0.0", 53 | "which": "^2.0.1" 54 | }, 55 | "devDependencies": { 56 | "@commitlint/cli": "^8.1.0", 57 | "@commitlint/config-conventional": "^8.1.0", 58 | "babel-core": "^6.26.3", 59 | "babel-jest": "^24.9.0", 60 | "babel-preset-moxy": "^3.1.0", 61 | "eslint": "^5.16.0", 62 | "eslint-config-moxy": "^7.1.0", 63 | "husky": "^3.0.5", 64 | "jest": "^24.9.0", 65 | "lint-staged": "^9.2.5", 66 | "mkdirp": "^0.5.1", 67 | "rimraf": "^3.0.0", 68 | "standard-version": "^9.5.0" 69 | }, 70 | "engines": { 71 | "node": ">= 8" 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/haconiwa/agent/boss.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, List, Any 2 | import asyncio 3 | from .base import BaseAgent 4 | 5 | class BossAgent(BaseAgent): 6 | """Boss AIエージェント - タスクブランチ分解・計画・割り当て・Worker監視・進捗管理""" 7 | 8 | def __init__(self, agent_id: str, config): 9 | super().__init__(agent_id, config) 10 | self.workers: Dict[str, Any] = {} 11 | self.tasks: List[Dict[str, Any]] = [] 12 | self.task_assignments: Dict[str, str] = {} 13 | 14 | async def _initialize(self): 15 | """Bossエージェントの初期化""" 16 | self.logger.info("Boss agent initialized") 17 | 18 | async def _process_message(self, message: Dict[str, Any]): 19 | """メッセージ処理""" 20 | msg_type = message.get("type") 21 | 22 | if msg_type == "task_request": 23 | await self._handle_task_request(message) 24 | elif msg_type == "worker_report": 25 | await self._handle_worker_report(message) 26 | elif msg_type == "status_update": 27 | await self._handle_status_update(message) 28 | 29 | async def _cleanup(self): 30 | """クリーンアップ処理""" 31 | self.logger.info("Boss agent cleanup") 32 | 33 | async def assign_task(self, task: Dict[str, Any], worker_id: str): 34 | """タスクブランチをWorkerに割り当て""" 35 | task_id = task.get("id") 36 | self.task_assignments[task_id] = worker_id 37 | self.logger.info(f"Assigned task {task_id} to worker {worker_id}") 38 | 39 | async def monitor_workers(self): 40 | """Worker監視""" 41 | for worker_id in self.workers: 42 | # Worker状態チェック 43 | pass 44 | 45 | async def _handle_task_request(self, message: Dict[str, Any]): 46 | """タスクブランチリクエスト処理""" 47 | pass 48 | 49 | async def _handle_worker_report(self, message: Dict[str, Any]): 50 | """Workerレポート処理""" 51 | pass 52 | 53 | async def _handle_status_update(self, message: Dict[str, Any]): 54 | """ステータス更新処理""" 55 | pass 56 | -------------------------------------------------------------------------------- /scripts/release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Haconiwa Release Script 4 | # Usage: ./scripts/release.sh 5 | # Example: ./scripts/release.sh 0.1.5 6 | 7 | set -e 8 | 9 | VERSION=$1 10 | if [ -z "$VERSION" ]; then 11 | echo "❌ Usage: $0 " 12 | echo "📝 Example: $0 0.1.5" 13 | exit 1 14 | fi 15 | 16 | echo "🚀 Starting release process for version $VERSION" 17 | 18 | # Update version in pyproject.toml 19 | echo "📝 Updating pyproject.toml version to $VERSION" 20 | sed -i '' "s/version = \".*\"/version = \"$VERSION\"/" pyproject.toml 21 | 22 | # Update latest version in README files 23 | echo "📝 Updating README files with latest version" 24 | sed -i '' "s/最新バージョン**: .*/最新バージョン**: $VERSION/" README_JA.md 25 | sed -i '' "s/Latest Version**: .*/Latest Version**: $VERSION/" README.md 26 | 27 | # Run pre-release checks 28 | echo "🧪 Running pre-release checks..." 29 | if command -v haconiwa-prerelease >/dev/null 2>&1; then 30 | haconiwa-prerelease 31 | else 32 | echo "⚠️ haconiwa-prerelease not found, running basic tests..." 33 | python -m pytest tests/ -v 34 | fi 35 | 36 | # Build package 37 | echo "📦 Building package" 38 | rm -rf dist/ build/ src/*.egg-info 39 | python -m build 40 | 41 | # Upload to PyPI 42 | echo "🔄 Uploading to PyPI" 43 | python -m twine upload dist/* 44 | 45 | # Git operations 46 | echo "📋 Committing changes" 47 | git add . 48 | git commit -m "chore: release v$VERSION 49 | 50 | - Update version in pyproject.toml 51 | - Update README with latest version 52 | - Build and upload to PyPI" 53 | 54 | echo "🏷️ Creating Git tag" 55 | git tag -a "v$VERSION" -m "Release v$VERSION 56 | 57 | See CHANGELOG.md for details." 58 | 59 | echo "🚀 Pushing changes and tags" 60 | git push origin main 61 | git push origin "v$VERSION" 62 | 63 | echo "✅ Release v$VERSION completed successfully!" 64 | echo "📝 Next steps:" 65 | echo " 1. Create GitHub Release at: https://github.com/dai-motoki/haconiwa/releases/new" 66 | echo " 2. Update CHANGELOG.md with new version details" 67 | echo " 3. Verify PyPI release at: https://pypi.org/project/haconiwa/$VERSION/" -------------------------------------------------------------------------------- /src/haconiwa/world/cli.py: -------------------------------------------------------------------------------- 1 | import typer 2 | from haconiwa.world.provider.local import LocalProvider 3 | 4 | try: 5 | from haconiwa.world.provider.docker import DockerProvider 6 | DOCKER_AVAILABLE = True 7 | except ImportError: 8 | DockerProvider = None 9 | DOCKER_AVAILABLE = False 10 | 11 | world_app = typer.Typer(help="ワールド・環境管理 (開発中)") 12 | 13 | providers = { 14 | "local": LocalProvider 15 | } 16 | 17 | if DOCKER_AVAILABLE: 18 | providers["docker"] = DockerProvider 19 | 20 | @world_app.command() 21 | def create(provider: str, name: str): 22 | """Create a new environment.""" 23 | if provider in providers: 24 | provider_class = providers[provider] 25 | try: 26 | provider_instance = provider_class() 27 | # provider_instance.create(name) - method implementation may vary 28 | typer.echo(f"Environment '{name}' created using {provider} provider.") 29 | except Exception as e: 30 | typer.echo(f"Error creating environment: {e}") 31 | else: 32 | typer.echo(f"Provider '{provider}' not supported.") 33 | 34 | @world_app.command() 35 | def list_worlds(provider: str = "local"): 36 | """List all environments.""" 37 | if provider in providers: 38 | typer.echo(f"Listing environments for {provider} provider...") 39 | # Implementation would depend on actual provider methods 40 | else: 41 | typer.echo(f"Provider '{provider}' not supported.") 42 | 43 | @world_app.command() 44 | def enter(provider: str, name: str): 45 | """Enter an environment.""" 46 | if provider in providers: 47 | typer.echo(f"Entered environment '{name}' using {provider} provider.") 48 | else: 49 | typer.echo(f"Provider '{provider}' not supported.") 50 | 51 | @world_app.command() 52 | def destroy(provider: str, name: str): 53 | """Destroy an environment.""" 54 | if provider in providers: 55 | typer.echo(f"Environment '{name}' destroyed using {provider} provider.") 56 | else: 57 | typer.echo(f"Provider '{provider}' not supported.") 58 | 59 | if __name__ == "__main__": 60 | world_app() -------------------------------------------------------------------------------- /scripts/verify-claude-execution.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Verify claude command execution in tmux panes 4 | # 5 | 6 | SESSION="${1:-test-company-multiroom-tasks}" 7 | CHECK_COUNT=5 8 | 9 | echo "=== Verifying claude command execution in session: $SESSION ===" 10 | echo 11 | 12 | # Check a sample of panes 13 | PANE_COUNT=0 14 | CD_CLAUDE_COUNT=0 15 | CLAUDE_ONLY_COUNT=0 16 | NO_CLAUDE_COUNT=0 17 | 18 | while read -r pane_info && [ $PANE_COUNT -lt $CHECK_COUNT ]; do 19 | window_id=$(echo "$pane_info" | cut -d'.' -f1) 20 | pane_id=$(echo "$pane_info" | cut -d'.' -f2) 21 | 22 | # Capture last 30 lines of pane content 23 | content=$(tmux capture-pane -t "$SESSION:$window_id.$pane_id" -p -S -30 2>/dev/null) 24 | 25 | # Check for cd && claude pattern 26 | if echo "$content" | grep -q "cd.*&&.*claude"; then 27 | echo "✅ Pane $window_id.$pane_id: Found 'cd ... && claude' pattern" 28 | ((CD_CLAUDE_COUNT++)) 29 | elif echo "$content" | grep -q "claude"; then 30 | echo "⚠️ Pane $window_id.$pane_id: Found 'claude' but not with '&&'" 31 | ((CLAUDE_ONLY_COUNT++)) 32 | else 33 | echo "❌ Pane $window_id.$pane_id: No claude command found" 34 | ((NO_CLAUDE_COUNT++)) 35 | fi 36 | 37 | # Also check current directory 38 | pwd_output=$(tmux send-keys -t "$SESSION:$window_id.$pane_id" "pwd" Enter 2>/dev/null) 39 | sleep 0.1 40 | current_dir=$(tmux capture-pane -t "$SESSION:$window_id.$pane_id" -p | tail -2 | head -1) 41 | echo " Current directory: $current_dir" 42 | echo 43 | 44 | ((PANE_COUNT++)) 45 | done < <(tmux list-panes -t "$SESSION" -F "#{window_index}.#{pane_index}" | head -$CHECK_COUNT) 46 | 47 | echo "=== Summary ===" 48 | echo "Checked $PANE_COUNT panes:" 49 | echo " - With 'cd && claude': $CD_CLAUDE_COUNT" 50 | echo " - Claude only: $CLAUDE_ONLY_COUNT" 51 | echo " - No claude: $NO_CLAUDE_COUNT" 52 | 53 | if [ $CD_CLAUDE_COUNT -eq $PANE_COUNT ]; then 54 | echo 55 | echo "✅ All checked panes use the correct 'cd && claude' pattern!" 56 | else 57 | echo 58 | echo "⚠️ Some panes may not have the correct pattern" 59 | fi -------------------------------------------------------------------------------- /scripts/check-pane-borders.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Check pane border settings for tmux session 4 | # 5 | 6 | SESSION="${1:-test-company-multiroom-tasks}" 7 | 8 | echo "=== Checking pane border settings for session: $SESSION ===" 9 | echo 10 | 11 | # Check session-level settings 12 | echo "Session-level settings:" 13 | echo -n " pane-border-status: " 14 | tmux show-options -t "$SESSION" pane-border-status 2>/dev/null || echo "(not set)" 15 | echo -n " pane-border-format: " 16 | tmux show-options -t "$SESSION" pane-border-format 2>/dev/null || echo "(not set)" 17 | 18 | echo 19 | echo "Window-level settings:" 20 | 21 | # Check each window 22 | while read -r window_info; do 23 | window_id=$(echo "$window_info" | cut -d: -f1) 24 | window_name=$(echo "$window_info" | cut -d: -f2) 25 | 26 | echo 27 | echo "Window $window_id ($window_name):" 28 | echo -n " pane-border-status: " 29 | tmux show-options -t "$SESSION:$window_id" pane-border-status 2>/dev/null || echo "(not set)" 30 | echo -n " pane-border-format: " 31 | tmux show-options -t "$SESSION:$window_id" pane-border-format 2>/dev/null || echo "(not set)" 32 | 33 | # Show first few pane titles 34 | echo " Sample pane titles:" 35 | tmux list-panes -t "$SESSION:$window_id" -F " Pane #{pane_index}: #{pane_title}" | head -3 36 | done < <(tmux list-windows -t "$SESSION" -F "#{window_index}:#{window_name}") 37 | 38 | echo 39 | echo "=== Applying missing settings if needed ===" 40 | 41 | # Apply settings to any windows that don't have them 42 | while read -r window_id; do 43 | if ! tmux show-options -t "$SESSION:$window_id" pane-border-status &>/dev/null; then 44 | echo "Applying pane-border-status to window $window_id..." 45 | tmux set-option -t "$SESSION:$window_id" pane-border-status top 46 | fi 47 | 48 | if ! tmux show-options -t "$SESSION:$window_id" pane-border-format &>/dev/null; then 49 | echo "Applying pane-border-format to window $window_id..." 50 | tmux set-option -t "$SESSION:$window_id" pane-border-format '#{pane_title}' 51 | fi 52 | done < <(tmux list-windows -t "$SESSION" -F "#{window_index}") -------------------------------------------------------------------------------- /test_cases/minimal_config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: haconiwa.dev/v1 2 | kind: Organization 3 | metadata: 4 | name: minimal-org 5 | spec: 6 | companyName: "Minimal Company" 7 | industry: "Minimal" 8 | basePath: "./test_output/minimal" 9 | hierarchy: 10 | departments: 11 | - id: "executive" 12 | name: "Executive" 13 | roles: 14 | - roleType: "executive" 15 | title: "CEO" 16 | - id: "frontend" 17 | name: "Frontend" 18 | roles: 19 | - roleType: "management" 20 | title: "Lead" 21 | - id: "backend" 22 | name: "Backend" 23 | roles: 24 | - roleType: "management" 25 | title: "Lead" 26 | - id: "devops" 27 | name: "DevOps" 28 | roles: 29 | - roleType: "management" 30 | title: "Lead" 31 | - id: "qa" 32 | name: "QA" 33 | roles: 34 | - roleType: "management" 35 | title: "Lead" 36 | 37 | --- 38 | apiVersion: haconiwa.dev/v1 39 | kind: Space 40 | metadata: 41 | name: minimal-space 42 | spec: 43 | nations: 44 | - id: jp 45 | name: Japan 46 | cities: 47 | - id: tokyo 48 | name: Tokyo 49 | villages: 50 | - id: village 51 | name: Village 52 | companies: 53 | - name: minimal-company 54 | grid: 8x4 55 | organizationRef: "minimal-org" 56 | gitRepo: 57 | url: "https://github.com/dai-motoki/haconiwa" 58 | defaultBranch: "main" 59 | auth: "https" 60 | buildings: 61 | - id: hq 62 | name: HQ 63 | floors: 64 | - id: floor-1 65 | name: Floor 1 66 | rooms: 67 | - id: room-01 68 | name: Alpha 69 | - id: room-02 70 | name: Beta 71 | - id: floor-2 72 | name: Floor 2 73 | rooms: 74 | - id: room-executive 75 | name: Executive 76 | 77 | --- 78 | apiVersion: haconiwa.dev/v1 79 | kind: Task 80 | metadata: 81 | name: minimal_task 82 | spec: 83 | branch: minimal_task 84 | worktree: true 85 | assignee: org05-ceo-re 86 | spaceRef: minimal-company 87 | description: "Minimal test task" -------------------------------------------------------------------------------- /docs/CI_STRATEGY_OPTIONS.md: -------------------------------------------------------------------------------- 1 | # CI/CD戦略オプション比較 2 | 3 | ## 現在の戦略 (推奨) 4 | 5 | ### 基本方針: 環境分離 6 | ```yaml 7 | main: PyPI版のみ # ユーザー環境再現 8 | dev: 開発版のみ # 開発効率重視 9 | release: 両方テスト # リリース前確認 10 | ``` 11 | 12 | ### 利点 13 | - **明確な責務分離** 14 | - **高速なCI/CD** 15 | - **本番環境との一致** 16 | 17 | ## オプション1: mainで両方テスト 18 | 19 | ### 設定例 20 | ```yaml 21 | # .github/workflows/ci.yml (main) 22 | jobs: 23 | test-production: 24 | name: "Production Environment Test" 25 | steps: 26 | - name: Test PyPI version 27 | run: pip install haconiwa==0.6.3 28 | 29 | test-development: 30 | name: "Development Environment Test" 31 | steps: 32 | - name: Test development version 33 | run: pip install -e . 34 | ``` 35 | 36 | ### 利点 37 | - より包括的なテスト 38 | - 早期の問題発見 39 | 40 | ### 欠点 41 | - CI時間が2倍 42 | - 複雑性増加 43 | - リソース消費増大 44 | 45 | ## オプション2: 条件付き両方テスト 46 | 47 | ### 設定例 48 | ```yaml 49 | # 重要なコミット(タグ付き)のみ両方テスト 50 | jobs: 51 | test-production: 52 | # 常にPyPI版テスト 53 | 54 | test-comprehensive: 55 | # タグがある場合のみ両方テスト 56 | if: startsWith(github.ref, 'refs/tags/') 57 | steps: 58 | - name: Test both versions 59 | ``` 60 | 61 | ### 利点 62 | - 通常は高速、重要時は包括的 63 | - リソース効率的 64 | 65 | ## オプション3: 並列テスト 66 | 67 | ### 設定例 68 | ```yaml 69 | strategy: 70 | matrix: 71 | test-type: ["production", "development"] 72 | 73 | steps: 74 | - name: Install based on test type 75 | run: | 76 | if [ "${{ matrix.test-type }}" = "production" ]; then 77 | pip install haconiwa==0.6.3 78 | else 79 | pip install -e . 80 | fi 81 | ``` 82 | 83 | ### 利点 84 | - 並列実行で時間短縮 85 | - 両方の結果を同時確認 86 | 87 | ## 推奨戦略の選択指針 88 | 89 | ### 小規模プロジェクト 90 | → **現在の戦略** (環境分離) 91 | 92 | ### 中規模プロジェクト 93 | → **オプション2** (条件付き) 94 | 95 | ### 大規模プロジェクト 96 | → **オプション3** (並列テスト) 97 | 98 | ## 実装の判断基準 99 | 100 | 1. **チーム規模**: 小さいほど現在の戦略が有効 101 | 2. **リリース頻度**: 高いほど包括的テストが必要 102 | 3. **CI/CDリソース**: 限られているほど分離戦略が有効 103 | 4. **ユーザー影響度**: 高いほど本番環境テストが重要 104 | 105 | ## 結論 106 | 107 | **Haconiwaの現在の状況**では: 108 | - 開発初期段階 109 | - 小規模チーム 110 | - リソース効率重視 111 | 112 | → **現在の環境分離戦略が最適** 113 | 114 | 将来的に規模が拡大したら、オプション2または3への移行を検討。 -------------------------------------------------------------------------------- /worlds/local-dev.yaml: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { 3 | Card, 4 | CardContent, 5 | CardDescription, 6 | CardHeader, 7 | CardTitle, 8 | } from "@/components/ui/card" 9 | 10 | const LocalDev: React.FC = () => { 11 | return ( 12 |
13 | 14 | 15 | Local-Dev ワールド定義 16 | 17 | Python製 haconiwa ワールド定義ファイル(YAML形式) 18 | 19 | 20 | 21 |
22 |

ワールドID

23 |

local-dev

24 |
25 |
26 |

プロバイダー設定

27 |

local, docker, lxc

28 |
29 |
30 |

ネットワーク設定

31 |

ポート、ファイアウォール

32 |
33 |
34 |

ストレージ設定

35 |

ボリューム、マウントポイント

36 |
37 |
38 |

環境変数とシステム設定

39 |

環境変数、システム設定

40 |
41 |
42 |

Pythonランタイム設定

43 |

バージョン、パッケージ

44 |
45 |
46 |

セキュリティ設定

47 |

namespace分離、権限

48 |
49 |
50 |

監視・ログ設定

51 |

監視設定、ログ設定

52 |
53 |
54 |

バックアップ・復旧設定

55 |

バックアップ設定、復旧設定

56 |
57 |
58 |
59 |
60 | ); 61 | }; 62 | 63 | export default LocalDev; -------------------------------------------------------------------------------- /src/haconiwa/world/provider/docker.py: -------------------------------------------------------------------------------- 1 | try: 2 | import docker 3 | from docker.models.containers import Container 4 | DOCKER_AVAILABLE = True 5 | except ImportError: 6 | DOCKER_AVAILABLE = False 7 | Container = None 8 | 9 | from haconiwa.core.config import Config 10 | 11 | class DockerProvider: 12 | def __init__(self): 13 | if not DOCKER_AVAILABLE: 14 | raise ImportError("Docker is not available. Install docker with: pip install docker") 15 | self.client = docker.from_env() 16 | self.config = Config() 17 | 18 | def create_container(self, image: str, name: str, **kwargs) -> Container: 19 | return self.client.containers.run(image, name=name, detach=True, **kwargs) 20 | 21 | def start_container(self, container_id: str): 22 | container = self.client.containers.get(container_id) 23 | container.start() 24 | 25 | def stop_container(self, container_id: str): 26 | container = self.client.containers.get(container_id) 27 | container.stop() 28 | 29 | def remove_container(self, container_id: str): 30 | container = self.client.containers.get(container_id) 31 | container.remove() 32 | 33 | def build_image(self, path: str, tag: str): 34 | self.client.images.build(path=path, tag=tag) 35 | 36 | def manage_volumes(self, name: str, **kwargs): 37 | return self.client.volumes.create(name=name, **kwargs) 38 | 39 | def configure_network(self, name: str, **kwargs): 40 | return self.client.networks.create(name=name, **kwargs) 41 | 42 | def connect_containers(self, network_name: str, container_id: str): 43 | network = self.client.networks.get(network_name) 44 | network.connect(container_id) 45 | 46 | def set_resource_limits(self, container_id: str, cpu_quota: int, mem_limit: str): 47 | container = self.client.containers.get(container_id) 48 | container.update(cpu_quota=cpu_quota, mem_limit=mem_limit) 49 | 50 | def health_check(self, container_id: str): 51 | container = self.client.containers.get(container_id) 52 | return container.attrs['State']['Health'] 53 | 54 | def log_container(self, container_id: str): 55 | container = self.client.containers.get(container_id) 56 | return container.logs() 57 | 58 | def debug_container(self, container_id: str): 59 | container = self.client.containers.get(container_id) 60 | return container.exec_run('sh', tty=True); -------------------------------------------------------------------------------- /src/haconiwa/watch/monitor.py: -------------------------------------------------------------------------------- 1 | import psutil 2 | from prometheus_client import Gauge, start_http_server 3 | import matplotlib.pyplot as plt 4 | import smtplib 5 | from email.mime.text import MIMEText 6 | from email.mime.multipart import MIMEMultipart 7 | from haconiwa.core.config import Config 8 | from haconiwa.core.logging import get_logger 9 | 10 | class Monitor: 11 | def __init__(self): 12 | self.config = Config() 13 | self.logger = get_logger(__name__) 14 | self.cpu_usage_gauge = Gauge('cpu_usage', 'CPU Usage') 15 | self.memory_usage_gauge = Gauge('memory_usage', 'Memory Usage') 16 | start_http_server(8000) 17 | 18 | def collect_metrics(self): 19 | cpu_usage = psutil.cpu_percent(interval=1) 20 | memory_info = psutil.virtual_memory() 21 | self.cpu_usage_gauge.set(cpu_usage) 22 | self.memory_usage_gauge.set(memory_info.percent) 23 | self.logger.info(f"CPU Usage: {cpu_usage}%, Memory Usage: {memory_info.percent}%") 24 | 25 | def generate_dashboard(self): 26 | cpu_usage = psutil.cpu_percent(interval=1, percpu=True) 27 | plt.figure(figsize=(10, 5)) 28 | plt.plot(cpu_usage, label='CPU Usage') 29 | plt.title('CPU Usage Over Time') 30 | plt.xlabel('Time') 31 | plt.ylabel('CPU Usage (%)') 32 | plt.legend() 33 | plt.savefig('cpu_usage_dashboard.png') 34 | plt.close() 35 | 36 | def send_alert(self, message): 37 | email_config = self.config.get_email_config() 38 | msg = MIMEMultipart() 39 | msg['From'] = email_config['from'] 40 | msg['To'] = email_config['to'] 41 | msg['Subject'] = 'Alert: System Metrics' 42 | msg.attach(MIMEText(message, 'plain')) 43 | server = smtplib.SMTP(email_config['smtp_server'], email_config['smtp_port']) 44 | server.starttls() 45 | server.login(email_config['from'], email_config['password']) 46 | server.send_message(msg) 47 | server.quit() 48 | 49 | def check_alert_conditions(self): 50 | cpu_usage = psutil.cpu_percent(interval=1) 51 | if cpu_usage > self.config.get_alert_threshold('cpu'): 52 | self.send_alert(f"High CPU usage detected: {cpu_usage}%") 53 | 54 | def run(self): 55 | while True: 56 | self.collect_metrics() 57 | self.check_alert_conditions() 58 | self.generate_dashboard() 59 | 60 | if __name__ == "__main__": 61 | monitor = Monitor() 62 | monitor.run() -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/.package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "haconiwa", 3 | "version": "0.4.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "node_modules/cross-spawn": { 8 | "version": "7.0.6", 9 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", 10 | "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", 11 | "dependencies": { 12 | "path-key": "^3.1.0", 13 | "shebang-command": "^2.0.0", 14 | "which": "^2.0.1" 15 | }, 16 | "engines": { 17 | "node": ">= 8" 18 | } 19 | }, 20 | "node_modules/isexe": { 21 | "version": "2.0.0", 22 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 23 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" 24 | }, 25 | "node_modules/path-key": { 26 | "version": "3.1.1", 27 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 28 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 29 | "engines": { 30 | "node": ">=8" 31 | } 32 | }, 33 | "node_modules/shebang-command": { 34 | "version": "2.0.0", 35 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 36 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 37 | "dependencies": { 38 | "shebang-regex": "^3.0.0" 39 | }, 40 | "engines": { 41 | "node": ">=8" 42 | } 43 | }, 44 | "node_modules/shebang-regex": { 45 | "version": "3.0.0", 46 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 47 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 48 | "engines": { 49 | "node": ">=8" 50 | } 51 | }, 52 | "node_modules/which": { 53 | "version": "2.0.2", 54 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 55 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 56 | "dependencies": { 57 | "isexe": "^2.0.0" 58 | }, 59 | "bin": { 60 | "node-which": "bin/node-which" 61 | }, 62 | "engines": { 63 | "node": ">= 8" 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=45", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "haconiwa" 7 | version = "0.6.3" 8 | description = "AI協調開発支援Python CLIツール - 箱庭での開発を支援" 9 | readme = "README.md" 10 | authors = [ 11 | {name = "Daisuke Motoki", email = "kanri@kandaquantum.co.jp"} 12 | ] 13 | requires-python = ">=3.10" 14 | classifiers = [ 15 | "Development Status :: 3 - Alpha", 16 | "Environment :: Console", 17 | "Intended Audience :: Developers", 18 | "Operating System :: OS Independent", 19 | "Programming Language :: Python :: 3.10", 20 | "Programming Language :: Python :: 3.11", 21 | "Programming Language :: Python :: 3.12", 22 | "Topic :: Software Development :: Libraries :: Python Modules", 23 | ] 24 | dependencies = [ 25 | "typer>=0.9.0", 26 | "libtmux>=0.23.2", 27 | "gitpython>=3.1.40", 28 | "prometheus-client>=0.17.1", 29 | "pyyaml>=6.0.1", 30 | "rich>=13.7.0", 31 | "click>=8.1.7", 32 | "pydantic>=2.0.0", 33 | "claude-code-sdk>=0.0.10", 34 | "psutil>=5.9.0", 35 | "anyio>=3.7.0", 36 | "python-dotenv>=1.0.0", 37 | "watchdog>=3.0.0", 38 | "cryptography>=3.0.0", 39 | "pandas>=1.0.0", 40 | "matplotlib>=3.0.0", 41 | "sqlalchemy>=1.4.0", 42 | "packaging>=20.0", 43 | ] 44 | 45 | [project.optional-dependencies] 46 | docker = ["docker>=6.1.3"] 47 | dev = [ 48 | "pytest>=7.4.3", 49 | "pytest-cov>=4.1.0", 50 | "black>=23.11.0", 51 | "flake8>=6.1.0", 52 | "mypy>=1.7.1", 53 | "bandit>=1.7.5", 54 | "isort>=5.12.0", 55 | "pre-commit>=3.5.0", 56 | ] 57 | 58 | [project.urls] 59 | Homepage = "https://github.com/haconiwa/haconiwa" 60 | Documentation = "https://haconiwa.readthedocs.io" 61 | Repository = "https://github.com/haconiwa/haconiwa.git" 62 | Issues = "https://github.com/haconiwa/haconiwa/issues" 63 | 64 | [project.scripts] 65 | haconiwa = "haconiwa.cli:app" 66 | haconiwa-test = "haconiwa.scripts.test_runner:run_tests" 67 | haconiwa-prerelease = "haconiwa.scripts.prerelease:run_prerelease_checks" 68 | 69 | [tool.setuptools] 70 | package-dir = {"" = "src"} 71 | 72 | [tool.setuptools.packages.find] 73 | where = ["src"] 74 | 75 | [tool.black] 76 | line-length = 88 77 | target-version = ["py312"] 78 | 79 | [tool.isort] 80 | profile = "black" 81 | multi_line_output = 3 82 | 83 | [tool.mypy] 84 | python_version = "3.12" 85 | strict = true 86 | ignore_missing_imports = true 87 | 88 | [tool.pytest.ini_options] 89 | minversion = "6.0" 90 | addopts = "-ra -q --cov=haconiwa" 91 | testpaths = ["tests"] -------------------------------------------------------------------------------- /src/haconiwa/core/upgrade.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import subprocess 4 | from packaging import version 5 | from haconiwa.core.config import Config 6 | from haconiwa.core.state import StateManager 7 | 8 | class Upgrader: 9 | def __init__(self, config_path="config.yaml"): 10 | self.config = Config(config_path) 11 | self.state = StateManager(config_path) 12 | 13 | def get_current_version(self): 14 | """Get current haconiwa version""" 15 | try: 16 | from haconiwa import __version__ 17 | return __version__ 18 | except ImportError: 19 | return "0.1.0" 20 | 21 | def get_latest_version(self): 22 | """Get latest version from PyPI""" 23 | # Simplified - in real implementation would check PyPI 24 | return "0.1.0" 25 | 26 | def check_version_compatibility(self, current_version, new_version): 27 | return version.parse(new_version) > version.parse(current_version) 28 | 29 | def backup(self, backup_path): 30 | if os.path.exists(backup_path): 31 | shutil.rmtree(backup_path) 32 | os.makedirs(backup_path) 33 | print(f"Backup created at {backup_path}") 34 | 35 | def restore(self, backup_path): 36 | print(f"State restored from {backup_path}") 37 | 38 | def migrate(self): 39 | # Placeholder for migration logic 40 | print("Migrating settings and database...") 41 | 42 | def update_dependencies(self): 43 | subprocess.run(["pip", "install", "-r", "requirements.txt", "--upgrade"]) 44 | print("Dependencies updated") 45 | 46 | def verify_upgrade(self): 47 | # Placeholder for verification logic 48 | print("Verifying upgrade...") 49 | 50 | def upgrade(self, new_version=None): 51 | current_version = self.get_current_version() 52 | if new_version is None: 53 | new_version = self.get_latest_version() 54 | 55 | if not self.check_version_compatibility(current_version, new_version): 56 | print("New version is not compatible") 57 | return 58 | 59 | backup_path = "backup" 60 | self.backup(backup_path) 61 | 62 | try: 63 | self.migrate() 64 | self.update_dependencies() 65 | self.verify_upgrade() 66 | print(f"Upgraded to version {new_version}") 67 | except Exception as e: 68 | print(f"Upgrade failed: {e}") 69 | self.restore(backup_path) 70 | print("Rolled back to previous state") 71 | finally: 72 | if os.path.exists(backup_path): 73 | shutil.rmtree(backup_path) 74 | print("Cleanup completed") -------------------------------------------------------------------------------- /docs/quickstart.md: -------------------------------------------------------------------------------- 1 | pip install haconiwa 2 | 3 | # 初期化 4 | haconiwa core init 5 | 6 | # 設定確認 7 | haconiwa core status 8 | 9 | # ローカル開発環境の作成 10 | haconiwa world create local-dev 11 | 12 | # 環境に入る 13 | haconiwa world enter local-dev 14 | 15 | # tmuxセッションの作成 16 | haconiwa space create dev-space 17 | 18 | # レイアウトの設定 19 | haconiwa space resize --layout=grid 20 | 21 | # Bossエージェントの起動 22 | haconiwa agent spawn boss-1 --type=boss 23 | 24 | # Workerエージェントの起動 25 | haconiwa agent spawn worker-a --type=worker --skill=frontend 26 | haconiwa agent spawn worker-b --type=worker --skill=backend 27 | 28 | # 新規タスクブランチの作成 29 | haconiwa task new "実装: ログイン機能" 30 | 31 | # タスクブランチの割り当て 32 | haconiwa task assign TASK-001 worker-a 33 | 34 | # 進捗確認 35 | haconiwa task show TASK-001 36 | 37 | # サンプルプロジェクトのクローン 38 | git clone https://github.com/haconiwa/example-todo-app.git 39 | cd example-todo-app 40 | 41 | # haconiwa環境のセットアップ 42 | haconiwa core init 43 | haconiwa world create todo-dev 44 | haconiwa space create todo-space 45 | 46 | # AIエージェントによる開発支援 47 | haconiwa agent spawn boss-1 --type=boss 48 | haconiwa task new "タスクブランチ: TODOリスト表示機能の実装" 49 | 50 | # セッション一覧の確認 51 | haconiwa space list 52 | 53 | # 強制終了と再作成 54 | haconiwa space kill dev-space 55 | haconiwa space create dev-space 56 | 57 | # エージェントの状態確認 58 | haconiwa agent ps 59 | 60 | # エージェントの再起動 61 | haconiwa agent stop worker-a 62 | haconiwa agent spawn worker-a --type=worker 63 | 64 | # worktreeの状態確認 65 | haconiwa task prune --dry-run 66 | 67 | # 孤立worktreeの削除 68 | haconiwa task prune --force 69 | 70 | from haconiwa.core import haconiwaCore 71 | from haconiwa.agent import BossAgent, WorkerAgent 72 | 73 | # haconiwaコアの初期化 74 | core = haconiwaCore() 75 | core.initialize() 76 | 77 | # エージェントの設定 78 | boss = BossAgent("boss-1") 79 | worker = WorkerAgent("worker-a", skill="frontend") 80 | 81 | # タスクブランチの作成と割り当て 82 | task = core.create_task("新機能の実装") 83 | boss.assign_task(task, worker) 84 | 85 | # 進捗監視 86 | for status in worker.watch_progress(): 87 | print(f"タスクブランチ進捗: {status.progress}%") 88 | 89 | from haconiwa.agent import BaseAgent 90 | 91 | class CustomAgent(BaseAgent): 92 | def __init__(self, name, **kwargs): 93 | super().__init__(name, **kwargs) 94 | 95 | async def process_task(self, task): 96 | # タスクブランチ処理ロジックの実装 97 | result = await self.execute_custom_logic(task) 98 | return result 99 | 100 | from haconiwa.core import hooks 101 | 102 | @hooks.on_task_complete 103 | def handle_task_complete(task): 104 | print(f"タスクブランチ完了: {task.id}") 105 | 106 | @hooks.on_agent_error 107 | def handle_agent_error(agent, error): 108 | print(f"エージェントエラー: {agent.name} - {error}"); -------------------------------------------------------------------------------- /voice-systems/command-permission/test_keywords.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | 音声認識キーワードテスト用デモスクリプト 4 | """ 5 | 6 | def test_keyword_recognition(): 7 | """音声認識キーワードをテスト""" 8 | 9 | test_phrases = [ 10 | # Python実行のキーワード 11 | ("はい", "python"), 12 | ("OK", "python"), 13 | ("オーケー", "python"), 14 | ("実行", "python"), 15 | ("python", "python"), 16 | ("パイソン", "python"), 17 | ("やる", "python"), 18 | 19 | # Claude実行のキーワード 20 | ("claude", "claude"), 21 | ("クロード", "claude"), 22 | ("claude code", "claude"), 23 | ("クロードコード", "claude"), 24 | 25 | # 実行しないのキーワード 26 | ("no", "no"), 27 | ("やめ", "no"), 28 | ("だめ", "no"), 29 | ("怖い", "no"), 30 | ("EA", "no"), 31 | ("キャンセル", "no"), 32 | ("いいえ", "no"), 33 | 34 | # 曖昧なケース 35 | ("ちょっとpythonで", "python"), 36 | ("claudeにお任せ", "claude"), 37 | ("やめておこう", "no"), 38 | ("怖いのでclaude", "no"), # 怖い が優先されて no になる 39 | 40 | # 音声認識誤認識パターン 41 | ("配送", "python"), # Python → 配送 42 | ("配配", "python"), # Python → 配配 43 | ("くらうど", "claude"), # Claude → くらうど 44 | ("ハイ", "python"), # はい → ハイ 45 | ] 46 | 47 | def classify_response(text): 48 | """音声認識結果を分類(実際のロジックと同じ)""" 49 | text = text.lower() 50 | 51 | # ネガティブワードを最優先でチェック 52 | if any(word in text for word in ['no', 'ノー', 'やめ', '中止', 'やめる', 'キャンセル', 'きゃんせる', 'いいえ', 'だめ', 'ダメ', 'cia', 'ea', 'えー', 'えい', '怖い', 'こわい']): 53 | return "no" 54 | elif any(word in text for word in ['claude', 'クロード', 'くろーど', 'claude code', 'クロードコード', 'くらうど', 'cloud', 'クラウド']): 55 | return "claude" 56 | elif any(word in text for word in ['はい', 'ok', 'オーケー', '実行', 'python', 'パイソン', 'ぱいそん', '実行する', 'やる', '配送', 'はいそん', 'パイ', 'pie', 'ハイ', 'hai', 'yes', '配配', '配']): 57 | return "python" 58 | else: 59 | return "unknown" 60 | 61 | print("🎯 音声認識キーワードテスト") 62 | print("=" * 50) 63 | 64 | correct = 0 65 | total = len(test_phrases) 66 | 67 | for phrase, expected in test_phrases: 68 | result = classify_response(phrase) 69 | status = "✅" if result == expected else "❌" 70 | 71 | print(f"{status} '{phrase}' → {result} (期待: {expected})") 72 | 73 | if result == expected: 74 | correct += 1 75 | 76 | print("=" * 50) 77 | print(f"📊 テスト結果: {correct}/{total} ({correct/total*100:.1f}%)") 78 | 79 | if correct == total: 80 | print("🎉 全テストケースが正常に動作しています!") 81 | else: 82 | print("⚠️ 一部のテストケースで問題があります。") 83 | 84 | if __name__ == "__main__": 85 | test_keyword_recognition() -------------------------------------------------------------------------------- /haconiwa-npm/bin/haconiwa: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const spawn = require('cross-spawn'); 4 | const path = require('path'); 5 | 6 | // Check if haconiwa is installed via pip 7 | function checkHaconiwaInstallation() { 8 | try { 9 | const result = spawn.sync('haconiwa', ['--version'], { stdio: 'pipe' }); 10 | if (result.status === 0) { 11 | return true; 12 | } 13 | } catch (error) { 14 | // Command not found 15 | } 16 | 17 | // Try python -m haconiwa 18 | try { 19 | const result = spawn.sync('python', ['-m', 'haconiwa', '--version'], { stdio: 'pipe' }); 20 | if (result.status === 0) { 21 | return 'python-module'; 22 | } 23 | } catch (error) { 24 | // Command not found 25 | } 26 | 27 | // Try python3 -m haconiwa 28 | try { 29 | const result = spawn.sync('python3', ['-m', 'haconiwa', '--version'], { stdio: 'pipe' }); 30 | if (result.status === 0) { 31 | return 'python3-module'; 32 | } 33 | } catch (error) { 34 | // Command not found 35 | } 36 | 37 | return false; 38 | } 39 | 40 | function showInstallInstructions() { 41 | console.error(` 42 | ❌ Haconiwa Python package is not installed. 43 | 44 | 📦 Please install haconiwa via pip: 45 | 46 | pip install haconiwa --upgrade 47 | 48 | Or if you prefer pip3: 49 | 50 | pip3 install haconiwa --upgrade 51 | 52 | 🔗 More information: 53 | - PyPI: https://pypi.org/project/haconiwa/ 54 | - GitHub: https://github.com/dai-motoki/haconiwa 55 | 56 | After installation, try running 'haconiwa --help' again. 57 | `); 58 | } 59 | 60 | function main() { 61 | const installationType = checkHaconiwaInstallation(); 62 | 63 | if (!installationType) { 64 | showInstallInstructions(); 65 | process.exit(1); 66 | } 67 | 68 | // Prepare command and arguments 69 | let command; 70 | let args; 71 | 72 | if (installationType === 'python-module') { 73 | command = 'python'; 74 | args = ['-m', 'haconiwa'].concat(process.argv.slice(2)); 75 | } else if (installationType === 'python3-module') { 76 | command = 'python3'; 77 | args = ['-m', 'haconiwa'].concat(process.argv.slice(2)); 78 | } else { 79 | // Direct haconiwa command 80 | command = 'haconiwa'; 81 | args = process.argv.slice(2); 82 | } 83 | 84 | // Execute haconiwa with all arguments 85 | const child = spawn(command, args, { 86 | stdio: 'inherit', 87 | shell: false 88 | }); 89 | 90 | child.on('exit', (code, signal) => { 91 | if (signal) { 92 | process.kill(process.pid, signal); 93 | } else { 94 | process.exit(code); 95 | } 96 | }); 97 | 98 | child.on('error', (error) => { 99 | console.error('Error executing haconiwa:', error.message); 100 | process.exit(1); 101 | }); 102 | } 103 | 104 | if (require.main === module) { 105 | main(); 106 | } 107 | 108 | module.exports = { checkHaconiwaInstallation, main }; -------------------------------------------------------------------------------- /haconiwa-npm/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "haconiwa", 3 | "version": "0.4.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "haconiwa", 9 | "version": "0.4.0", 10 | "license": "MIT", 11 | "os": [ 12 | "darwin", 13 | "linux", 14 | "win32" 15 | ], 16 | "dependencies": { 17 | "cross-spawn": "^7.0.3" 18 | }, 19 | "bin": { 20 | "haconiwa": "bin/haconiwa" 21 | }, 22 | "devDependencies": {}, 23 | "engines": { 24 | "node": ">=12.0.0" 25 | } 26 | }, 27 | "node_modules/cross-spawn": { 28 | "version": "7.0.6", 29 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", 30 | "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", 31 | "dependencies": { 32 | "path-key": "^3.1.0", 33 | "shebang-command": "^2.0.0", 34 | "which": "^2.0.1" 35 | }, 36 | "engines": { 37 | "node": ">= 8" 38 | } 39 | }, 40 | "node_modules/isexe": { 41 | "version": "2.0.0", 42 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 43 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" 44 | }, 45 | "node_modules/path-key": { 46 | "version": "3.1.1", 47 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 48 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 49 | "engines": { 50 | "node": ">=8" 51 | } 52 | }, 53 | "node_modules/shebang-command": { 54 | "version": "2.0.0", 55 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 56 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 57 | "dependencies": { 58 | "shebang-regex": "^3.0.0" 59 | }, 60 | "engines": { 61 | "node": ">=8" 62 | } 63 | }, 64 | "node_modules/shebang-regex": { 65 | "version": "3.0.0", 66 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 67 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 68 | "engines": { 69 | "node": ">=8" 70 | } 71 | }, 72 | "node_modules/which": { 73 | "version": "2.0.2", 74 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 75 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 76 | "dependencies": { 77 | "isexe": "^2.0.0" 78 | }, 79 | "bin": { 80 | "node-which": "bin/node-which" 81 | }, 82 | "engines": { 83 | "node": ">= 8" 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /organizations/org-01/config.yaml: -------------------------------------------------------------------------------- 1 | organization_id: org-01 2 | 3 | boss: 4 | model: gemini-2.0-flash-exp 5 | parameters: 6 | temperature: 0.7 7 | max_tokens: 4096 8 | top_p: 0.95 9 | capabilities: 10 | task_decomposition: true 11 | progress_tracking: true 12 | quality_control: true 13 | resource_optimization: true 14 | learning: 15 | enabled: true 16 | model_update_interval: 24h 17 | performance_metrics_window: 7d 18 | 19 | workers: 20 | frontend: 21 | model: claude-3-5-sonnet 22 | specialization: ui_ux 23 | capabilities: 24 | - react_development 25 | - vue_development 26 | - angular_development 27 | - web_accessibility 28 | skill_level: expert 29 | 30 | backend: 31 | model: gpt-4o 32 | specialization: server_side 33 | capabilities: 34 | - api_development 35 | - database_design 36 | - system_architecture 37 | - security_implementation 38 | skill_level: expert 39 | 40 | qa: 41 | model: gemini-2.0-flash-exp 42 | specialization: testing 43 | capabilities: 44 | - automated_testing 45 | - performance_testing 46 | - security_testing 47 | - regression_testing 48 | skill_level: expert 49 | 50 | task_management: 51 | priority_levels: 52 | - critical 53 | - high 54 | - medium 55 | - low 56 | assignment_rules: 57 | - skill_match_weight: 0.4 58 | - workload_balance_weight: 0.3 59 | - urgency_weight: 0.3 60 | max_concurrent_tasks_per_worker: 3 61 | review_required: true 62 | 63 | communication: 64 | protocol: grpc 65 | message_format: protobuf 66 | retry_policy: 67 | max_attempts: 3 68 | backoff_multiplier: 1.5 69 | log_level: info 70 | metrics_enabled: true 71 | 72 | resources: 73 | cpu: 74 | limit_per_worker: 2 75 | total_limit: 8 76 | memory: 77 | limit_per_worker: 2Gi 78 | total_limit: 8Gi 79 | storage: 80 | limit_per_worker: 10Gi 81 | total_limit: 50Gi 82 | network: 83 | bandwidth_limit: 100Mbps 84 | 85 | optimization: 86 | auto_scaling: true 87 | load_balancing: true 88 | performance_monitoring: true 89 | resource_allocation_strategy: dynamic 90 | 91 | security: 92 | authentication: 93 | method: jwt 94 | token_expiry: 8h 95 | authorization: 96 | role_based: true 97 | roles: 98 | - admin 99 | - developer 100 | - viewer 101 | encryption: 102 | at_rest: aes-256-gcm 103 | in_transit: tls-1.3 104 | audit: 105 | enabled: true 106 | retention_period: 90d 107 | 108 | backup: 109 | schedule: "0 0 * * *" 110 | retention: 111 | count: 7 112 | duration: 30d 113 | type: incremental 114 | 115 | monitoring: 116 | metrics_interval: 60s 117 | health_check_interval: 30s 118 | alert_thresholds: 119 | cpu_usage: 80 120 | memory_usage: 85 121 | error_rate: 5 122 | notification_channels: 123 | - slack 124 | - email -------------------------------------------------------------------------------- /voice-systems/experimental/test_streaming_tts.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Gemini TTS ストリーミング テスト 4 | """ 5 | 6 | import os 7 | import pyaudio 8 | from google import genai 9 | from google.genai import types 10 | from dotenv import load_dotenv 11 | 12 | load_dotenv() 13 | 14 | def test_streaming_tts(): 15 | """Gemini TTS ストリーミングをテスト""" 16 | api_key = os.environ.get("GEMINI_API_KEY") 17 | if not api_key: 18 | print("エラー: GEMINI_API_KEYが設定されていません") 19 | return 20 | 21 | # PyAudio設定 22 | FORMAT = pyaudio.paInt16 23 | CHANNELS = 1 24 | RECEIVE_SAMPLE_RATE = 24000 25 | 26 | # PyAudioの初期化 27 | pya = pyaudio.PyAudio() 28 | 29 | try: 30 | # 音声ストリームを開く 31 | stream = pya.open( 32 | format=FORMAT, 33 | channels=CHANNELS, 34 | rate=RECEIVE_SAMPLE_RATE, 35 | output=True 36 | ) 37 | 38 | print("ストリーミング開始...") 39 | 40 | client = genai.Client(api_key=api_key) 41 | model = "gemini-2.5-flash-preview-tts" 42 | 43 | # テストメッセージ 44 | test_message = "ストリーミングTTSのテストです。リアルタイムで音声が再生されているか確認します。" 45 | enhanced_text = f"以下のメッセージを冷静で落ち着いたトーンで、早口で話してください。プロフェッショナルで集中した雰囲気を保ちながら、テンポよく読み上げてください:\n\n{test_message}" 46 | 47 | contents = [ 48 | types.Content( 49 | role="user", 50 | parts=[ 51 | types.Part.from_text(text=enhanced_text), 52 | ], 53 | ), 54 | ] 55 | 56 | generate_content_config = types.GenerateContentConfig( 57 | temperature=1, 58 | response_modalities=["audio"], 59 | speech_config=types.SpeechConfig( 60 | voice_config=types.VoiceConfig( 61 | prebuilt_voice_config=types.PrebuiltVoiceConfig( 62 | voice_name="Zephyr" 63 | ) 64 | ) 65 | ), 66 | ) 67 | 68 | # ストリーミング生成と再生 69 | for chunk in client.models.generate_content_stream( 70 | model=model, 71 | contents=contents, 72 | config=generate_content_config, 73 | ): 74 | if ( 75 | chunk.candidates and 76 | chunk.candidates[0].content and 77 | chunk.candidates[0].content.parts and 78 | chunk.candidates[0].content.parts[0].inline_data and 79 | chunk.candidates[0].content.parts[0].inline_data.data 80 | ): 81 | # 音声データを直接ストリームに書き込み 82 | audio_data = chunk.candidates[0].content.parts[0].inline_data.data 83 | print(".", end="", flush=True) # 進行状況表示 84 | stream.write(audio_data) 85 | 86 | print("\nストリーミング完了") 87 | 88 | except Exception as e: 89 | print(f"ストリーミングエラー: {e}") 90 | 91 | finally: 92 | # クリーンアップ 93 | if 'stream' in locals(): 94 | stream.stop_stream() 95 | stream.close() 96 | pya.terminate() 97 | 98 | if __name__ == "__main__": 99 | test_streaming_tts() -------------------------------------------------------------------------------- /docs/ai/core-engine/claude_code_sdk_documentation.md: -------------------------------------------------------------------------------- 1 | # Claude Code SDK ドキュメント 2 | 3 | ## 概要 4 | 5 | Claude Code SDKは、Claude Codeをアプリケーションにプログラマティックに統合するためのツールです。このSDKを使用することで、AIパワードのコーディングアシスタントやツールを構築できます。 6 | 7 | ## 利用可能なSDK 8 | 9 | ### 1. Python SDK 10 | - **パッケージ名**: `claude-code-sdk` 11 | - **インストール**: `pip install claude-code-sdk` 12 | 13 | ### 2. TypeScript/JavaScript SDK 14 | - **パッケージ名**: `@anthropic-ai/claude-code` 15 | - **インストール**: `npm install @anthropic-ai/claude-code` 16 | 17 | ### 3. コマンドラインSDK 18 | - ターミナルから直接利用可能 19 | 20 | ## 基本的な使用例 21 | 22 | ### Python SDK 23 | 24 | ```python 25 | import anyio 26 | from claude_code_sdk import query, ClaudeCodeOptions, Message 27 | 28 | async def main(): 29 | messages: list[Message] = [] 30 | async for message in query( 31 | prompt="Write a haiku about foo.py", 32 | options=ClaudeCodeOptions(max_turns=3) 33 | ): 34 | messages.append(message) 35 | print(message) 36 | 37 | anyio.run(main) 38 | ``` 39 | 40 | ### TypeScript SDK 41 | 42 | ```typescript 43 | import { query } from "@anthropic-ai/claude-code"; 44 | 45 | async function main() { 46 | for await (const message of query({ 47 | prompt: "Write a haiku about foo.py", 48 | options: { maxTurns: 3 } 49 | })) { 50 | console.log(message); 51 | } 52 | } 53 | 54 | main(); 55 | ``` 56 | 57 | ## 主な設定オプション (ClaudeCodeOptions) 58 | 59 | - **`max_turns`**: 会話の最大ターン数 60 | - **`system_prompt`**: カスタムシステムプロンプト 61 | - **`cwd`**: 作業ディレクトリ(文字列またはPathオブジェクト) 62 | - **`allowed_tools`**: 許可するツールのリスト(例: "Read", "Write", "Bash") 63 | - **`permission_mode`**: 権限処理モード(例: "acceptEdits") 64 | 65 | ## 主な機能 66 | 67 | ### 1. 非インタラクティブな実行 68 | プログラムからClaude Codeを呼び出し、結果を取得 69 | 70 | ### 2. マルチターン会話 71 | 複数回のやり取りを通じた対話的なコーディング支援 72 | 73 | ### 3. MCP (Model Context Protocol) サーバー統合 74 | 外部コンテキストプロバイダーとの連携 75 | 76 | ### 4. ツール権限の細かい制御 77 | 使用可能なツールを明示的に指定 78 | 79 | ### 5. 出力形式の選択 80 | - テキスト形式 81 | - JSON形式 82 | - ストリーミング形式 83 | 84 | ## 高度な機能 85 | 86 | ### 前回の会話の再開 87 | ```python 88 | async for message in query( 89 | prompt="Continue from where we left off", 90 | options=ClaudeCodeOptions( 91 | resume_conversation_id="previous-conversation-id" 92 | ) 93 | ): 94 | print(message) 95 | ``` 96 | 97 | ### カスタムシステムプロンプトの追加 98 | ```python 99 | options = ClaudeCodeOptions( 100 | system_prompt="Always write clean, well-documented code" 101 | ) 102 | ``` 103 | 104 | ### 権限プロンプトツールのカスタマイズ 105 | 独自の権限確認フローを実装可能 106 | 107 | ## 統合例 108 | 109 | ### GitHub Actions 110 | Claude Code GitHub Actionsを使用することで、以下が可能: 111 | - 自動コードレビュー 112 | - PR作成 113 | - イシュートリアージ 114 | 115 | ### IDE統合 116 | - VS Code拡張機能(ベータ版) 117 | - JetBrains IDE拡張機能(ベータ版) 118 | 119 | ## リソース 120 | 121 | - **公式ドキュメント**: https://docs.anthropic.com/en/docs/claude-code/sdk 122 | - **GitHubリポジトリ**: https://github.com/anthropics/claude-code 123 | - **PyPI (Python)**: https://pypi.org/project/claude-code-sdk/ 124 | - **npm (TypeScript)**: https://www.npmjs.com/package/@anthropic-ai/claude-code 125 | 126 | ## 注意事項 127 | 128 | - Anthropic APIキーが必要 129 | - Node.js環境が必要(TypeScript SDK使用時) 130 | - 適切なエラーハンドリングを実装することを推奨 -------------------------------------------------------------------------------- /docs/backend/performance/tool_parallel_dev_command_design.md: -------------------------------------------------------------------------------- 1 | # Tool Parallel-Dev コマンド設計案(改訂版) 2 | 3 | ## 概要 4 | 5 | 既存の`tool`コマンドグループにClaude Code SDKを使用した並列開発機能を追加します。 6 | 7 | ## コマンド構造 8 | 9 | ### メインコマンド 10 | ```bash 11 | haconiwa tool parallel-dev 12 | ``` 13 | 14 | ### サブコマンド構造 15 | ```bash 16 | haconiwa tool parallel-dev claude # Claude Code SDKでの並列実行 17 | haconiwa tool parallel-dev status # 実行状況確認 18 | haconiwa tool parallel-dev cancel # タスクブランチキャンセル 19 | haconiwa tool parallel-dev history # 実行履歴表示 20 | ``` 21 | 22 | ## `haconiwa tool parallel-dev claude` の詳細 23 | 24 | ### 必須フラグ 25 | 26 | 1. **ファイル指定**(いずれか1つ) 27 | - `-f, --files`: カンマ区切りのファイルパスリスト 28 | - `--file-list`: ファイルパスを含むテキストファイル 29 | - `--from-yaml`: YAML設定ファイル 30 | 31 | 2. **プロンプト指定**(--filesの場合は必須) 32 | - `-p, --prompts`: カンマ区切りのプロンプトリスト 33 | - `--prompt-file`: プロンプトを含むテキストファイル(1行1プロンプト) 34 | 35 | ### オプションフラグ 36 | 37 | - `-m, --max-concurrent`: 同時実行数(デフォルト: 3、最大: 10) 38 | - `-t, --timeout`: タイムアウト時間(秒)(デフォルト: 60) 39 | - `--dry-run`: 実行前の確認表示 40 | - `-o, --output-dir`: 結果出力ディレクトリ 41 | - `--permission-mode`: 権限モード(acceptEdits等) 42 | - `--allowed-tools`: 許可するツールのリスト 43 | 44 | ## 使用例 45 | 46 | ### 例1: 基本的な使用 47 | ```bash 48 | haconiwa tool parallel-dev claude \ 49 | -f src/main.py,src/utils.py,src/api.py \ 50 | -p "Add type hints","Refactor functions","Add error handling" 51 | ``` 52 | 53 | ### 例2: 10ファイル一斉修正 54 | ```bash 55 | haconiwa tool parallel-dev claude \ 56 | --file-list files.txt \ 57 | --prompt-file prompts.txt \ 58 | -m 5 \ 59 | -t 120 60 | ``` 61 | 62 | ### 例3: YAML設定ファイル使用 63 | ```yaml 64 | # parallel-dev.yaml 65 | provider: claude 66 | tasks: 67 | - file: src/models/user.py 68 | prompt: Add validation methods and type hints 69 | - file: src/models/product.py 70 | prompt: Implement inventory tracking 71 | # ... 最大10タスクブランチまで 72 | options: 73 | max_concurrent: 5 74 | timeout: 90 75 | allowed_tools: [Read, Write, Edit, MultiEdit] 76 | ``` 77 | 78 | ```bash 79 | haconiwa tool parallel-dev claude --from-yaml parallel-dev.yaml 80 | ``` 81 | 82 | ### 例4: 状態確認とキャンセル 83 | ```bash 84 | # 実行状態確認 85 | haconiwa tool parallel-dev status 86 | 87 | # 特定タスクブランチのキャンセル 88 | haconiwa tool parallel-dev cancel task-123 89 | 90 | # 実行履歴表示 91 | haconiwa tool parallel-dev history --limit 10 92 | ``` 93 | 94 | ## 他のtoolコマンドとの統合 95 | 96 | 既存の`tool`コマンドグループ: 97 | ```bash 98 | haconiwa tool list # 利用可能なツール一覧 99 | haconiwa tool install # ツールのインストール 100 | haconiwa tool configure # ツールの設定 101 | haconiwa tool parallel-dev # 並列開発機能(新規) 102 | ``` 103 | 104 | ## 将来の拡張案 105 | 106 | ```bash 107 | # 他のAIプロバイダー対応 108 | haconiwa tool parallel-dev github-copilot ... 109 | haconiwa tool parallel-dev chatgpt ... 110 | haconiwa tool parallel-dev gemini ... 111 | 112 | # バッチ処理 113 | haconiwa tool parallel-dev batch --schedule "0 2 * * *" 114 | 115 | # テンプレート機能 116 | haconiwa tool parallel-dev template create refactor-python 117 | haconiwa tool parallel-dev template apply refactor-python --target src/ 118 | ``` 119 | 120 | ## メリット 121 | 122 | 1. **既存構造との一貫性** - `haconiwa <カテゴリ> <アクション>`パターンに準拠 123 | 2. **拡張性** - 他のAIツールやSDKを追加しやすい 124 | 3. **明確な役割** - `tool`は外部ツール連携を扱うカテゴリとして適切 125 | 4. **サブコマンド構造** - status、cancel、historyなどの管理機能も自然に追加可能 -------------------------------------------------------------------------------- /test_cases/error_case_test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: haconiwa.dev/v1 2 | kind: Organization 3 | metadata: 4 | name: error-test-org 5 | spec: 6 | companyName: "Error Test Company" 7 | industry: "Testing" 8 | basePath: "./test_output/error_cases" 9 | hierarchy: 10 | departments: 11 | - id: "executive" 12 | name: "Executive Leadership" 13 | roles: 14 | - roleType: "executive" 15 | title: "CEO" 16 | - id: "frontend" 17 | name: "Frontend" 18 | roles: 19 | - roleType: "management" 20 | title: "Lead" 21 | - id: "backend" 22 | name: "Backend" 23 | roles: 24 | - roleType: "management" 25 | title: "Lead" 26 | - id: "devops" 27 | name: "DevOps" 28 | roles: 29 | - roleType: "management" 30 | title: "Lead" 31 | - id: "qa" 32 | name: "QA" 33 | roles: 34 | - roleType: "management" 35 | title: "Lead" 36 | 37 | --- 38 | apiVersion: haconiwa.dev/v1 39 | kind: Space 40 | metadata: 41 | name: error-test-space 42 | spec: 43 | nations: 44 | - id: jp 45 | name: Japan 46 | cities: 47 | - id: tokyo 48 | name: Tokyo 49 | villages: 50 | - id: test-village 51 | name: Test Village 52 | companies: 53 | - name: error-test-company 54 | grid: 8x4 55 | organizationRef: "error-test-org" 56 | gitRepo: 57 | url: "https://github.com/dai-motoki/haconiwa" 58 | defaultBranch: "main" 59 | auth: "https" 60 | buildings: 61 | - id: headquarters 62 | name: HQ 63 | floors: 64 | - id: floor-1 65 | name: Floor 1 66 | rooms: 67 | - id: room-01 68 | name: Alpha Room 69 | - id: room-02 70 | name: Beta Room 71 | - id: floor-2 72 | name: Floor 2 73 | rooms: 74 | - id: room-executive 75 | name: Executive Room 76 | 77 | --- 78 | # Test case: Task assigned to non-existent agent 79 | apiVersion: haconiwa.dev/v1 80 | kind: Task 81 | metadata: 82 | name: invalid_agent_task 83 | spec: 84 | branch: invalid_agent_task 85 | worktree: true 86 | assignee: org99-invalid-agent 87 | spaceRef: error-test-company 88 | description: "Task assigned to invalid agent" 89 | 90 | --- 91 | # Test case: Task assigned to valid agent 92 | apiVersion: haconiwa.dev/v1 93 | kind: Task 94 | metadata: 95 | name: valid_agent_task 96 | spec: 97 | branch: valid_agent_task 98 | worktree: true 99 | assignee: org05-ceo-re 100 | spaceRef: error-test-company 101 | description: "Task assigned to valid executive agent" 102 | 103 | --- 104 | # Test case: Duplicate task assignment 105 | apiVersion: haconiwa.dev/v1 106 | kind: Task 107 | metadata: 108 | name: duplicate_task_1 109 | spec: 110 | branch: duplicate_task_1 111 | worktree: true 112 | assignee: org01-pm-r1 113 | spaceRef: error-test-company 114 | description: "First duplicate task" 115 | 116 | --- 117 | apiVersion: haconiwa.dev/v1 118 | kind: Task 119 | metadata: 120 | name: duplicate_task_2 121 | spec: 122 | branch: duplicate_task_2 123 | worktree: true 124 | assignee: org01-pm-r1 125 | spaceRef: error-test-company 126 | description: "Second duplicate task (should override)" -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/which/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changes 2 | 3 | 4 | ## 2.0.2 5 | 6 | * Rename bin to `node-which` 7 | 8 | ## 2.0.1 9 | 10 | * generate changelog and publish on version bump 11 | * enforce 100% test coverage 12 | * Promise interface 13 | 14 | ## 2.0.0 15 | 16 | * Parallel tests, modern JavaScript, and drop support for node < 8 17 | 18 | ## 1.3.1 19 | 20 | * update deps 21 | * update travis 22 | 23 | ## v1.3.0 24 | 25 | * Add nothrow option to which.sync 26 | * update tap 27 | 28 | ## v1.2.14 29 | 30 | * appveyor: drop node 5 and 0.x 31 | * travis-ci: add node 6, drop 0.x 32 | 33 | ## v1.2.13 34 | 35 | * test: Pass missing option to pass on windows 36 | * update tap 37 | * update isexe to 2.0.0 38 | * neveragain.tech pledge request 39 | 40 | ## v1.2.12 41 | 42 | * Removed unused require 43 | 44 | ## v1.2.11 45 | 46 | * Prevent changelog script from being included in package 47 | 48 | ## v1.2.10 49 | 50 | * Use env.PATH only, not env.Path 51 | 52 | ## v1.2.9 53 | 54 | * fix for paths starting with ../ 55 | * Remove unused `is-absolute` module 56 | 57 | ## v1.2.8 58 | 59 | * bullet items in changelog that contain (but don't start with) # 60 | 61 | ## v1.2.7 62 | 63 | * strip 'update changelog' changelog entries out of changelog 64 | 65 | ## v1.2.6 66 | 67 | * make the changelog bulleted 68 | 69 | ## v1.2.5 70 | 71 | * make a changelog, and keep it up to date 72 | * don't include tests in package 73 | * Properly handle relative-path executables 74 | * appveyor 75 | * Attach error code to Not Found error 76 | * Make tests pass on Windows 77 | 78 | ## v1.2.4 79 | 80 | * Fix typo 81 | 82 | ## v1.2.3 83 | 84 | * update isexe, fix regression in pathExt handling 85 | 86 | ## v1.2.2 87 | 88 | * update deps, use isexe module, test windows 89 | 90 | ## v1.2.1 91 | 92 | * Sometimes windows PATH entries are quoted 93 | * Fixed a bug in the check for group and user mode bits. This bug was introduced during refactoring for supporting strict mode. 94 | * doc cli 95 | 96 | ## v1.2.0 97 | 98 | * Add support for opt.all and -as cli flags 99 | * test the bin 100 | * update travis 101 | * Allow checking for multiple programs in bin/which 102 | * tap 2 103 | 104 | ## v1.1.2 105 | 106 | * travis 107 | * Refactored and fixed undefined error on Windows 108 | * Support strict mode 109 | 110 | ## v1.1.1 111 | 112 | * test +g exes against secondary groups, if available 113 | * Use windows exe semantics on cygwin & msys 114 | * cwd should be first in path on win32, not last 115 | * Handle lower-case 'env.Path' on Windows 116 | * Update docs 117 | * use single-quotes 118 | 119 | ## v1.1.0 120 | 121 | * Add tests, depend on is-absolute 122 | 123 | ## v1.0.9 124 | 125 | * which.js: root is allowed to execute files owned by anyone 126 | 127 | ## v1.0.8 128 | 129 | * don't use graceful-fs 130 | 131 | ## v1.0.7 132 | 133 | * add license to package.json 134 | 135 | ## v1.0.6 136 | 137 | * isc license 138 | 139 | ## 1.0.5 140 | 141 | * Awful typo 142 | 143 | ## 1.0.4 144 | 145 | * Test for path absoluteness properly 146 | * win: Allow '' as a pathext if cmd has a . in it 147 | 148 | ## 1.0.3 149 | 150 | * Remove references to execPath 151 | * Make `which.sync()` work on Windows by honoring the PATHEXT variable. 152 | * Make `isExe()` always return true on Windows. 153 | * MIT 154 | 155 | ## 1.0.2 156 | 157 | * Only files can be exes 158 | 159 | ## 1.0.1 160 | 161 | * Respect the PATHEXT env for win32 support 162 | * should 0755 the bin 163 | * binary 164 | * guts 165 | * package 166 | * 1st 167 | -------------------------------------------------------------------------------- /docs/architecture.md: -------------------------------------------------------------------------------- 1 | # haconiwa アーキテクチャ設計 2 | 3 | ## はじめに 4 | 5 | 本ドキュメントは、AI協調開発支援CLIツール「haconiwa」のアーキテクチャ設計について記述します。haconiwaは、Python製CLIツールとして、AIエージェント(Boss/Worker/Manager)による協調開発を支援し、tmux区画管理、git-worktree連動、監視機能を統合します。 6 | 7 | ## システム全体構成 8 | 9 | haconiwaは、複数のモジュールが連携して動作する分散システムを想定しています。主要なコンポーネントは以下の通りです。 10 | 11 | - **CLI**: ユーザーインターフェースとなるコマンドラインツール。Typerフレームワークを使用。 12 | - **Core**: システムの基盤となる設定、状態、ログ、アップグレード管理。 13 | - **World**: 開発環境(ローカル、Docker、LXCなど)を抽象化し管理。 14 | - **Space**: tmuxを利用した開発作業空間の管理。 15 | - **Resource**: ファイルシステムやデータベースなどのリソースへのアクセス管理。 16 | - **Agent**: AIエージェント(Boss, Worker, Manager)の実装と管理。 17 | - **Task**: git-worktreeを利用した開発タスクブランチの管理。 18 | - **Watch**: システムやエージェントの監視、メトリクス収集、アラート。 19 | - **Utils**: 各モジュールで共通利用されるユーティリティ機能。 20 | 21 | これらのモジュールは、Coreモジュールを介して設定や状態を共有し、CLIを通じて操作されます。 22 | 23 | ## 7層アーキテクチャ 24 | 25 | haconiwaのアーキテクチャは、以下の7つの主要な層(モジュール)で構成されます。 26 | 27 | 1. **Core**: システムの核。設定、状態、ログ、アップグレードを管理。 28 | 2. **World**: 開発環境(仮想環境、コンテナなど)を管理。プロバイダーパターンで抽象化。 29 | 3. **Space**: 作業空間(tmuxセッション/ペイン)を管理。 30 | 4. **Resource**: 開発に必要なリソース(コード、データなど)へのアクセスを提供。 31 | 5. **Agent**: AIエージェントのロジックとライフサイクルを管理。 32 | 6. **Task**: 開発タスクブランチとそれに対応するgit-worktreeを管理。 33 | 7. **Watch**: システム全体の監視とメトリクス収集。 34 | 35 | これらの層は、下位層が上位層にサービスを提供する形で依存関係を持ちます。例えば、AgentはTaskやResourceを利用し、TaskやResourceはWorldやSpaceのコンテキストで実行されます。Coreは全ての層から参照される基盤となります。 36 | 37 | ## AIエージェント協調メカニズム (Boss-Worker-Manager パターン) 38 | 39 | haconiwaの中心的な機能は、AIエージェントによる協調開発です。以下の3種類のエージェントが連携します。 40 | 41 | - **Boss Agent**: 全体計画、タスクブランチ分解、Workerへのタスクブランチ割り当て、進捗管理、品質レビューを担当します。プロジェクト全体の目標達成を指揮します。 42 | - **Worker Agent**: Bossから割り当てられた特定のタスクブランチ(コーディング、テスト、ドキュメント作成など)を実行します。専門分野(フロントエンド、バックエンド、QAなど)に特化できます。 43 | - **Manager Agent**: エージェント間の調整、リソース競合の解決、全体最適化、コミュニケーション促進を担当します。円滑な開発フローを支援します。 44 | 45 | エージェント間の通信は、メッセージキューや共有状態を通じて非同期に行われることを想定しています。BaseAgentクラスが共通インターフェースとライフサイクルを提供します。 46 | 47 | ## 主要機能連携設計 48 | 49 | ### tmux区画管理とSpaceモジュール 50 | 51 | Spaceモジュールは、`tmux`コマンドをPythonから操作することで、開発作業用のセッション、ウィンドウ、ペインを動的に管理します。これにより、エージェントやユーザーは、タスクブランチごとに分離された作業空間で並行して作業できます。各ペインは特定のタスクブランチやエージェントに割り当てられ、コマンド実行やログ表示に使用されます。 52 | 53 | ### git-worktree連動とTaskモジュール 54 | 55 | Taskモジュールは、`git worktree`コマンドをPythonから操作することで、開発タスクブランチごとに独立した作業ディレクトリ(worktree)を作成・管理します。各worktreeは特定のタスクブランチに対応し、エージェントは他のタスクブランチに影響を与えることなく、自身のworktree内でコード変更、コミット、プッシュなどのGit操作を行います。タスクブランチ完了時にはworktreeの清理を行います。 56 | 57 | ## 分散実行アーキテクチャ 58 | 59 | haconiwaは、複数の「World」(開発環境)を同時に管理し、それぞれ異なるプロジェクトやタスクブランチを並列で開発することを想定しています。各Worldは完全に分離された環境(ローカルディレクトリ、Dockerコンテナ、LXCコンテナなど)であり、独自のSpace、Agent、Task、Resourceインスタンスを持ちます。Coreモジュールは、これらのWorldの状態を一元管理し、World間の連携やリソース共有のメカニズムを提供します。 60 | 61 | ## セキュリティ設計 62 | 63 | 各Worldは、プロバイダーの機能(Docker/LXCのnamespace分離、ローカル環境の権限管理)を利用して互いに分離されます。エージェントの実行権限は最小限に制限され、機密情報へのアクセスは厳密に制御されます。設定ファイルや状態ファイルは、必要に応じて暗号化やアクセス制御が適用されます。 64 | 65 | ## 拡張性設計 66 | 67 | haconiwaは、プラグインシステムとカスタムプロバイダーを通じて拡張可能です。 68 | 69 | - **World Provider**: 新しい仮想化技術(Kubernetes, Vagrantなど)に対応するためのプロバイダーを追加できます。 70 | - **Resource Provider**: 新しいデータソース(外部API、クラウドストレージなど)に対応するためのプロバイダーを追加できます。 71 | - **Agent**: 特定の専門分野に特化した新しいWorkerエージェントを開発・追加できます。 72 | - **Task Strategy**: 新しいタスクブランチ管理ワークフローやGit操作戦略を実装できます。 73 | - **Watch Integration**: 新しい監視システムや通知サービスと連携できます。 74 | 75 | これらの拡張は、定義されたインターフェースに従ってPythonモジュールとして実装され、Coreモジュールに登録されることで利用可能になります。 76 | 77 | ## Pythonクラス設計とインターフェース定義 78 | 79 | 各モジュールは、責務に応じたクラス群で構成されます。主要なクラスは抽象基底クラス(ABC)としてインターフェースを定義し、具体的な実装はサブクラスで行います。例えば、`agent.base.BaseAgent`、`world.provider.BaseProvider`などがこれにあたります。依存性の注入やファクトリパターンを活用し、モジュール間の結合度を低く保ちます。非同期処理にはPythonの`asyncio`を活用し、並行処理には`threading`や`multiprocessing`を適切に使い分けます。 -------------------------------------------------------------------------------- /scripts/README.md: -------------------------------------------------------------------------------- 1 | # Haconiwa バージョン管理スクリプト 2 | 3 | ## 概要 4 | 5 | Haconiwaプロジェクトのバージョンを一括で更新するスクリプトです。 6 | 7 | ## 使用方法 8 | 9 | ### 1. 基本的な使用方法 10 | 11 | ```bash 12 | # 特定のバージョンに更新 13 | python scripts/bump_version.py --version 0.7.0 --type release 14 | 15 | # 開発版バージョンに更新 16 | python scripts/bump_version.py --version 0.7.1-dev --type development 17 | ``` 18 | 19 | ### 2. 自動インクリメント 20 | 21 | ```bash 22 | # パッチバージョンをインクリメント (0.6.3 → 0.6.4) 23 | python scripts/bump_version.py --patch 24 | 25 | # マイナーバージョンをインクリメント (0.6.3 → 0.7.0) 26 | python scripts/bump_version.py --minor 27 | 28 | # メジャーバージョンをインクリメント (0.6.3 → 1.0.0) 29 | python scripts/bump_version.py --major 30 | ``` 31 | 32 | ### 3. バージョンタイプ指定 33 | 34 | ```bash 35 | # リリース版 36 | python scripts/bump_version.py --version 1.0.0 --type release 37 | 38 | # 開発版 39 | python scripts/bump_version.py --version 1.1.0-dev --type development 40 | 41 | # パッチリリース 42 | python scripts/bump_version.py --patch --type patch 43 | ``` 44 | 45 | ## 更新されるファイル 46 | 47 | スクリプトは以下のファイルを自動的に更新します: 48 | 49 | 1. **`pyproject.toml`** - パッケージバージョン 50 | 2. **`.github/workflows/ci.yml`** - CI/CDでのPyPIバージョン指定 51 | 3. **`src/haconiwa/__init__.py`** - `__version__` 変数 52 | 4. **`CHANGELOG.md`** - 新しいリリースセクション追加 53 | 5. **`README.md`** - インストール例のバージョン更新 54 | 55 | ## 実行例 56 | 57 | ```bash 58 | $ python scripts/bump_version.py --version 0.7.0 --type release 59 | 60 | 🔄 バージョン更新: 0.6.3 → 0.7.0 61 | 📝 更新タイプ: release 62 | 63 | ✅ pyproject.toml: 0.7.0 64 | ✅ ci.yml: haconiwa==0.7.0 65 | ✅ __init__.py: __version__ = "0.7.0" 66 | ✅ CHANGELOG.md: [0.7.0] セクション追加 67 | ✅ README.md: インストール例を 0.7.0 に更新 68 | 69 | 🎉 バージョン 0.7.0 への更新が完了しました! 70 | 71 | 次のステップ: 72 | 1. git add . 73 | 2. git commit -m "bump: version 0.6.3 → 0.7.0" 74 | 3. git tag v0.7.0 75 | 4. git push origin main --tags 76 | ``` 77 | 78 | ## リリースワークフロー 79 | 80 | ### 通常リリース 81 | 82 | ```bash 83 | # 1. バージョン更新 84 | python scripts/bump_version.py --version 0.7.0 --type release 85 | 86 | # 2. コミット・タグ作成 87 | git add . 88 | git commit -m "bump: version 0.6.3 → 0.7.0" 89 | git tag v0.7.0 90 | 91 | # 3. プッシュ 92 | git push origin main --tags 93 | 94 | # 4. PyPI デプロイ(GitHub Actionsで自動実行) 95 | ``` 96 | 97 | ### 開発版リリース 98 | 99 | ```bash 100 | # 1. 開発版バージョン更新 101 | python scripts/bump_version.py --version 0.7.1-dev --type development 102 | 103 | # 2. コミット 104 | git add . 105 | git commit -m "bump: version 0.7.0 → 0.7.1-dev" 106 | git push origin dev 107 | ``` 108 | 109 | ### パッチリリース 110 | 111 | ```bash 112 | # 1. パッチバージョン自動インクリメント 113 | python scripts/bump_version.py --patch --type patch 114 | 115 | # 2. コミット・タグ 116 | git add . 117 | git commit -m "bump: patch version $(git describe --tags --abbrev=0) → $(git describe --tags --abbrev=0 | sed 's/v//')" 118 | git tag v$(cat pyproject.toml | grep version | cut -d'"' -f2) 119 | git push origin main --tags 120 | ``` 121 | 122 | ## エラー対応 123 | 124 | ### よくあるエラー 125 | 126 | 1. **バージョン形式エラー** 127 | ``` 128 | ValueError: 無効なバージョン形式: invalid.version 129 | ``` 130 | → セマンティックバージョニング形式 (`x.y.z`) で指定してください 131 | 132 | 2. **ファイルが見つからない** 133 | ``` 134 | FileNotFoundError: pyproject.toml が見つかりません 135 | ``` 136 | → プロジェクトルートで実行してください 137 | 138 | 3. **権限エラー** 139 | ``` 140 | PermissionError: ファイルへの書き込み権限がありません 141 | ``` 142 | → ファイルが読み取り専用になっていないか確認してください 143 | 144 | ## カスタマイズ 145 | 146 | スクリプトの動作をカスタマイズしたい場合は、`VersionBumper` クラスの以下のメソッドを編集してください: 147 | 148 | - `update_pyproject_toml()` - pyproject.toml更新ロジック 149 | - `update_ci_workflow()` - CI/CD設定更新ロジック 150 | - `update_changelog()` - CHANGELOG生成ロジック 151 | 152 | ## 注意事項 153 | 154 | - バックアップを取ってから実行することをお勧めします 155 | - Git作業ディレクトリが清潔な状態で実行してください 156 | - CI/CDパイプラインが正常に動作することを確認してください -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/which/which.js: -------------------------------------------------------------------------------- 1 | const isWindows = process.platform === 'win32' || 2 | process.env.OSTYPE === 'cygwin' || 3 | process.env.OSTYPE === 'msys' 4 | 5 | const path = require('path') 6 | const COLON = isWindows ? ';' : ':' 7 | const isexe = require('isexe') 8 | 9 | const getNotFoundError = (cmd) => 10 | Object.assign(new Error(`not found: ${cmd}`), { code: 'ENOENT' }) 11 | 12 | const getPathInfo = (cmd, opt) => { 13 | const colon = opt.colon || COLON 14 | 15 | // If it has a slash, then we don't bother searching the pathenv. 16 | // just check the file itself, and that's it. 17 | const pathEnv = cmd.match(/\//) || isWindows && cmd.match(/\\/) ? [''] 18 | : ( 19 | [ 20 | // windows always checks the cwd first 21 | ...(isWindows ? [process.cwd()] : []), 22 | ...(opt.path || process.env.PATH || 23 | /* istanbul ignore next: very unusual */ '').split(colon), 24 | ] 25 | ) 26 | const pathExtExe = isWindows 27 | ? opt.pathExt || process.env.PATHEXT || '.EXE;.CMD;.BAT;.COM' 28 | : '' 29 | const pathExt = isWindows ? pathExtExe.split(colon) : [''] 30 | 31 | if (isWindows) { 32 | if (cmd.indexOf('.') !== -1 && pathExt[0] !== '') 33 | pathExt.unshift('') 34 | } 35 | 36 | return { 37 | pathEnv, 38 | pathExt, 39 | pathExtExe, 40 | } 41 | } 42 | 43 | const which = (cmd, opt, cb) => { 44 | if (typeof opt === 'function') { 45 | cb = opt 46 | opt = {} 47 | } 48 | if (!opt) 49 | opt = {} 50 | 51 | const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt) 52 | const found = [] 53 | 54 | const step = i => new Promise((resolve, reject) => { 55 | if (i === pathEnv.length) 56 | return opt.all && found.length ? resolve(found) 57 | : reject(getNotFoundError(cmd)) 58 | 59 | const ppRaw = pathEnv[i] 60 | const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw 61 | 62 | const pCmd = path.join(pathPart, cmd) 63 | const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd 64 | : pCmd 65 | 66 | resolve(subStep(p, i, 0)) 67 | }) 68 | 69 | const subStep = (p, i, ii) => new Promise((resolve, reject) => { 70 | if (ii === pathExt.length) 71 | return resolve(step(i + 1)) 72 | const ext = pathExt[ii] 73 | isexe(p + ext, { pathExt: pathExtExe }, (er, is) => { 74 | if (!er && is) { 75 | if (opt.all) 76 | found.push(p + ext) 77 | else 78 | return resolve(p + ext) 79 | } 80 | return resolve(subStep(p, i, ii + 1)) 81 | }) 82 | }) 83 | 84 | return cb ? step(0).then(res => cb(null, res), cb) : step(0) 85 | } 86 | 87 | const whichSync = (cmd, opt) => { 88 | opt = opt || {} 89 | 90 | const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt) 91 | const found = [] 92 | 93 | for (let i = 0; i < pathEnv.length; i ++) { 94 | const ppRaw = pathEnv[i] 95 | const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw 96 | 97 | const pCmd = path.join(pathPart, cmd) 98 | const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd 99 | : pCmd 100 | 101 | for (let j = 0; j < pathExt.length; j ++) { 102 | const cur = p + pathExt[j] 103 | try { 104 | const is = isexe.sync(cur, { pathExt: pathExtExe }) 105 | if (is) { 106 | if (opt.all) 107 | found.push(cur) 108 | else 109 | return cur 110 | } 111 | } catch (ex) {} 112 | } 113 | } 114 | 115 | if (opt.all && found.length) 116 | return found 117 | 118 | if (opt.nothrow) 119 | return null 120 | 121 | throw getNotFoundError(cmd) 122 | } 123 | 124 | module.exports = which 125 | which.sync = whichSync 126 | -------------------------------------------------------------------------------- /tools/security-check/install_hook.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Git pre-commit フックインストーラー 4 | """ 5 | 6 | import os 7 | import sys 8 | import stat 9 | from pathlib import Path 10 | 11 | def install_pre_commit_hook(): 12 | """pre-commitフックをインストール""" 13 | 14 | # Gitリポジトリのルートを検出 15 | current_dir = Path.cwd() 16 | git_dir = None 17 | 18 | for parent in [current_dir] + list(current_dir.parents): 19 | if (parent / '.git').exists(): 20 | git_dir = parent / '.git' 21 | repo_root = parent 22 | break 23 | 24 | if not git_dir: 25 | print("❌ Gitリポジトリが見つかりません") 26 | return False 27 | 28 | print(f"📁 Gitリポジトリ: {repo_root}") 29 | 30 | # hooks ディレクトリを作成 31 | hooks_dir = git_dir / 'hooks' 32 | hooks_dir.mkdir(exist_ok=True) 33 | 34 | # pre-commit フックファイルのパス 35 | hook_file = hooks_dir / 'pre-commit' 36 | 37 | # セキュリティチェックスクリプトのパス 38 | security_script = repo_root / 'tools' / 'security-check' / 'commit_security_check.py' 39 | 40 | if not security_script.exists(): 41 | print(f"❌ セキュリティチェックスクリプトが見つかりません: {security_script}") 42 | return False 43 | 44 | # pre-commit フックの内容 45 | hook_content = f'''#!/bin/bash 46 | # Auto-generated pre-commit hook for security checking 47 | 48 | echo "🔐 コミット前セキュリティチェック実行中..." 49 | 50 | # Python スクリプトを実行 51 | python3 "{security_script}" --ci 52 | 53 | exit_code=$? 54 | 55 | if [ $exit_code -eq 0 ]; then 56 | echo "✅ セキュリティチェック合格" 57 | else 58 | echo "❌ セキュリティチェック失敗 - コミットをブロックしました" 59 | echo "修正後に再度コミットしてください" 60 | fi 61 | 62 | exit $exit_code 63 | ''' 64 | 65 | # 既存のフックをバックアップ 66 | if hook_file.exists(): 67 | backup_file = hook_file.with_suffix('.backup') 68 | hook_file.rename(backup_file) 69 | print(f"📋 既存フックをバックアップ: {backup_file}") 70 | 71 | # 新しいフックを作成 72 | with open(hook_file, 'w') as f: 73 | f.write(hook_content) 74 | 75 | # 実行権限を付与 76 | hook_file.chmod(hook_file.stat().st_mode | stat.S_IEXEC) 77 | 78 | print(f"✅ pre-commit フックをインストール: {hook_file}") 79 | print("これで、コミット時に自動的にセキュリティチェックが実行されます") 80 | 81 | return True 82 | 83 | def uninstall_pre_commit_hook(): 84 | """pre-commitフックをアンインストール""" 85 | 86 | current_dir = Path.cwd() 87 | git_dir = None 88 | 89 | for parent in [current_dir] + list(current_dir.parents): 90 | if (parent / '.git').exists(): 91 | git_dir = parent / '.git' 92 | break 93 | 94 | if not git_dir: 95 | print("❌ Gitリポジトリが見つかりません") 96 | return False 97 | 98 | hook_file = git_dir / 'hooks' / 'pre-commit' 99 | backup_file = git_dir / 'hooks' / 'pre-commit.backup' 100 | 101 | if hook_file.exists(): 102 | hook_file.unlink() 103 | print(f"🗑️ pre-commit フックを削除: {hook_file}") 104 | 105 | if backup_file.exists(): 106 | backup_file.rename(hook_file) 107 | print(f"📋 バックアップを復元: {backup_file} → {hook_file}") 108 | 109 | print("✅ pre-commit フックをアンインストールしました") 110 | return True 111 | 112 | def main(): 113 | if len(sys.argv) > 1 and sys.argv[1] == 'uninstall': 114 | uninstall_pre_commit_hook() 115 | else: 116 | print("🔧 Git pre-commit セキュリティフックインストーラー") 117 | print("=" * 50) 118 | 119 | if install_pre_commit_hook(): 120 | print("\n📖 使用方法:") 121 | print(" 手動チェック: python tools/security-check/commit_security_check.py") 122 | print(" フック無効化: python tools/security-check/install_hook.py uninstall") 123 | else: 124 | print("❌ インストールに失敗しました") 125 | sys.exit(1) 126 | 127 | if __name__ == "__main__": 128 | main() -------------------------------------------------------------------------------- /src/haconiwa/resource/db_fetcher.py: -------------------------------------------------------------------------------- 1 | import sqlalchemy 2 | from sqlalchemy import create_engine 3 | from sqlalchemy.orm import sessionmaker 4 | import pandas as pd 5 | import json 6 | import yaml 7 | from sqlalchemy.exc import SQLAlchemyError 8 | from haconiwa.core.config import Config 9 | import logging 10 | from typing import Dict, Any, List 11 | 12 | logger = logging.getLogger(__name__) 13 | 14 | class DBFetcher: 15 | def __init__(self): 16 | self.config = Config("config.yaml") 17 | # Default SQLite database for now 18 | self.engine = create_engine("sqlite:///haconiwa.db", pool_size=10, max_overflow=20) 19 | self.Session = sessionmaker(bind=self.engine) 20 | 21 | def execute_query(self, query, params=None): 22 | session = self.Session() 23 | try: 24 | result = session.execute(query, params) 25 | return result.fetchall() 26 | except SQLAlchemyError as e: 27 | session.rollback() 28 | raise e 29 | finally: 30 | session.close() 31 | 32 | def fetch_as_dataframe(self, query, params=None): 33 | try: 34 | result = self.execute_query(query, params) 35 | return pd.DataFrame(result) 36 | except Exception as e: 37 | print(f"Error fetching data: {e}") 38 | return None 39 | 40 | def fetch_as_json(self, query, params=None): 41 | df = self.fetch_as_dataframe(query, params) 42 | if df is not None: 43 | return df.to_json(orient='records') 44 | return None 45 | 46 | def fetch_as_yaml(self, query, params=None): 47 | df = self.fetch_as_dataframe(query, params) 48 | if df is not None: 49 | return yaml.dump(df.to_dict(orient='records')) 50 | return None 51 | 52 | def fetch_as_csv(self, query, params=None): 53 | df = self.fetch_as_dataframe(query, params) 54 | if df is not None: 55 | return df.to_csv(index=False) 56 | return None 57 | 58 | def retry_query(self, query, params=None, retries=3): 59 | for attempt in range(retries): 60 | try: 61 | return self.execute_query(query, params) 62 | except SQLAlchemyError as e: 63 | if attempt < retries - 1: 64 | continue 65 | else: 66 | raise e 67 | 68 | class DatabaseManager: 69 | """Database scanner and connection manager""" 70 | 71 | _configs = {} 72 | 73 | def __init__(self): 74 | pass 75 | 76 | @classmethod 77 | def register_config(cls, name: str, config: Dict[str, Any]): 78 | """Register Database configuration""" 79 | cls._configs[name] = config 80 | logger.info(f"Registered Database config: {name}") 81 | 82 | def scan(self, config_name: str) -> Dict[str, Any]: 83 | """Scan database using configuration""" 84 | config = self._configs.get(config_name) 85 | if not config: 86 | logger.error(f"Database config not found: {config_name}") 87 | return {} 88 | 89 | # Mock implementation - would use actual database connection 90 | dsn = config.get("dsn") 91 | use_ssl = config.get("use_ssl", False) 92 | 93 | logger.info(f"Scanning database with DSN: {dsn}, SSL: {use_ssl}") 94 | 95 | # Return mock results 96 | return { 97 | "tables": ["users", "posts", "comments", "tags"], 98 | "views": ["user_posts", "comment_counts"], 99 | "indexes": ["idx_users_email", "idx_posts_created_at"] 100 | } 101 | 102 | # Example usage: 103 | # db_fetcher = DBFetcher() 104 | # result = db_fetcher.fetch_as_json("SELECT * FROM users") 105 | # print(result) -------------------------------------------------------------------------------- /src/haconiwa/agent/base.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | import asyncio 3 | import threading 4 | import time 5 | from typing import Any, Dict, Optional 6 | 7 | from ..core.config import Config 8 | from ..core.logging import get_logger 9 | 10 | class BaseAgent(ABC): 11 | def __init__(self, agent_id: str, config: Config): 12 | self.agent_id = agent_id 13 | self.config = config 14 | self.logger = get_logger(f"agent.{agent_id}") 15 | self.state: Dict[str, Any] = {} 16 | self._running = False 17 | self._lock = threading.Lock() 18 | self._metrics: Dict[str, float] = {} 19 | self._plugins: Dict[str, Any] = {} 20 | self._message_queue: asyncio.Queue = asyncio.Queue() 21 | 22 | async def start(self): 23 | with self._lock: 24 | if self._running: 25 | return 26 | self._running = True 27 | self.logger.info(f"Starting agent {self.agent_id}") 28 | await self._initialize() 29 | asyncio.create_task(self._run_loop()) 30 | asyncio.create_task(self._monitor_metrics()) 31 | 32 | async def stop(self): 33 | with self._lock: 34 | if not self._running: 35 | return 36 | self._running = False 37 | self.logger.info(f"Stopping agent {self.agent_id}") 38 | await self._cleanup() 39 | 40 | async def send_message(self, message: Dict[str, Any]): 41 | await self._message_queue.put(message) 42 | self._update_metric("messages_sent", 1) 43 | 44 | def register_plugin(self, name: str, plugin: Any): 45 | if name in self._plugins: 46 | raise ValueError(f"Plugin {name} already registered") 47 | self._plugins[name] = plugin 48 | self.logger.info(f"Registered plugin: {name}") 49 | 50 | def get_metric(self, name: str) -> float: 51 | return self._metrics.get(name, 0.0) 52 | 53 | @abstractmethod 54 | async def _initialize(self): 55 | pass 56 | 57 | @abstractmethod 58 | async def _process_message(self, message: Dict[str, Any]): 59 | pass 60 | 61 | @abstractmethod 62 | async def _cleanup(self): 63 | pass 64 | 65 | async def _run_loop(self): 66 | try: 67 | while self._running: 68 | message = await self._message_queue.get() 69 | start_time = time.time() 70 | try: 71 | await self._process_message(message) 72 | except Exception as e: 73 | self.logger.error(f"Error processing message: {e}") 74 | self._update_metric("message_errors", 1) 75 | finally: 76 | processing_time = time.time() - start_time 77 | self._update_metric("message_processing_time", processing_time) 78 | self._message_queue.task_done() 79 | except Exception as e: 80 | self.logger.error(f"Agent run loop error: {e}") 81 | self._running = False 82 | 83 | async def _monitor_metrics(self): 84 | while self._running: 85 | self._update_metric("queue_size", self._message_queue.qsize()) 86 | self._update_metric("uptime", time.time() - self._start_time) 87 | await asyncio.sleep(self.config.get("metrics_interval", 60)) 88 | 89 | def _update_metric(self, name: str, value: float): 90 | with self._lock: 91 | self._metrics[name] = value 92 | 93 | @property 94 | def is_running(self) -> bool: 95 | return self._running 96 | 97 | @property 98 | def plugins(self) -> Dict[str, Any]: 99 | return self._plugins.copy() 100 | 101 | @property 102 | def metrics(self) -> Dict[str, float]: 103 | return self._metrics.copy() -------------------------------------------------------------------------------- /tools/security-check/setup_personal_config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | 個人用セキュリティ設定セットアップスクリプト 4 | """ 5 | 6 | import json 7 | import os 8 | import getpass 9 | from pathlib import Path 10 | 11 | def setup_personal_nglist(): 12 | """個人用NGリストを対話的にセットアップ""" 13 | 14 | script_dir = Path(__file__).parent 15 | nglist_file = script_dir / 'nglist.json' 16 | example_file = script_dir / 'nglist.json.example' 17 | 18 | print("🔧 個人用セキュリティ設定セットアップ") 19 | print("=" * 50) 20 | 21 | # 既存ファイルの確認 22 | if nglist_file.exists(): 23 | print(f"⚠️ 既存の設定ファイルが見つかりました: {nglist_file}") 24 | if input("上書きしますか? [y/N]: ").lower() != 'y': 25 | print("セットアップをキャンセルしました") 26 | return 27 | 28 | # テンプレートを読み込み 29 | if not example_file.exists(): 30 | print(f"❌ テンプレートファイルが見つかりません: {example_file}") 31 | return 32 | 33 | with open(example_file, 'r', encoding='utf-8') as f: 34 | config = json.load(f) 35 | 36 | print("\n📝 個人情報を設定します(この情報はローカルにのみ保存されます)") 37 | 38 | # ユーザー名取得 39 | current_user = getpass.getuser() 40 | print(f"\n👤 現在のユーザー名: {current_user}") 41 | 42 | # フルパス設定 43 | home_dir = str(Path.home()) 44 | print(f"🏠 ホームディレクトリ: {home_dir}") 45 | 46 | personal_paths = [ 47 | home_dir, 48 | f"/Users/{current_user}", 49 | f"/home/{current_user}", 50 | f"C:\\\\Users\\\\{current_user}" 51 | ] 52 | 53 | # メールアドレス設定 54 | print("\n📧 メールアドレスを設定してください") 55 | email = input("メールアドレス(空Enter でスキップ): ").strip() 56 | 57 | personal_emails = [] 58 | if email: 59 | # エスケープして正規表現用に変換 60 | escaped_email = email.replace(".", "\\.").replace("@", "@") 61 | personal_emails.append(escaped_email) 62 | 63 | # 組織ドメイン設定 64 | print("\n🏢 組織固有のドメインがあれば設定してください") 65 | domain = input("内部ドメイン(例: internal.company.com)(空Enter でスキップ): ").strip() 66 | 67 | personal_domains = [] 68 | if domain: 69 | escaped_domain = domain.replace(".", "\\.") 70 | personal_domains.append(escaped_domain) 71 | 72 | # 設定を更新 73 | config['user_specific_patterns']['personal_paths']['patterns'] = personal_paths 74 | 75 | if personal_emails: 76 | config['user_specific_patterns']['personal_emails']['patterns'] = personal_emails 77 | else: 78 | # メールアドレスが設定されていない場合は削除 79 | del config['user_specific_patterns']['personal_emails'] 80 | 81 | if personal_domains: 82 | config['user_specific_patterns']['personal_domains']['patterns'] = personal_domains 83 | else: 84 | # ドメインが設定されていない場合は削除 85 | del config['user_specific_patterns']['personal_domains'] 86 | 87 | # ホワイトリストにユーザー名を追加 88 | config['whitelist_patterns']['safe_placeholders'].extend([ 89 | current_user, 90 | current_user.lower(), 91 | "username", 92 | "your_username" 93 | ]) 94 | 95 | # 重複を除去 96 | config['whitelist_patterns']['safe_placeholders'] = list(set( 97 | config['whitelist_patterns']['safe_placeholders'] 98 | )) 99 | 100 | # ファイルに保存 101 | with open(nglist_file, 'w', encoding='utf-8') as f: 102 | json.dump(config, f, ensure_ascii=False, indent=2) 103 | 104 | print(f"\n✅ 個人用設定を保存しました: {nglist_file}") 105 | print("\n📋 設定内容:") 106 | print(f" 🚫 チェック対象パス: {len(personal_paths)}件") 107 | print(f" 📧 チェック対象メール: {len(personal_emails)}件") 108 | print(f" 🌐 チェック対象ドメイン: {len(personal_domains)}件") 109 | print(f" ✅ 許可プレースホルダー: {len(config['whitelist_patterns']['safe_placeholders'])}件") 110 | 111 | print("\n🔐 この設定ファイルは .gitignore に含まれており、コミットされません") 112 | print("🧪 テスト実行: python tools/security-check/commit_security_check.py") 113 | 114 | def main(): 115 | try: 116 | setup_personal_nglist() 117 | except KeyboardInterrupt: 118 | print("\n\n🛑 セットアップが中断されました") 119 | except Exception as e: 120 | print(f"\n❌ エラーが発生しました: {e}") 121 | 122 | if __name__ == "__main__": 123 | main() -------------------------------------------------------------------------------- /haconiwa-simple-dev.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: haconiwa.dev/v1 2 | kind: Organization 3 | metadata: 4 | name: simple-dev-org 5 | spec: 6 | companyName: "Simple Dev Company" 7 | industry: "Software Development" 8 | basePath: "./simple-dev-world" 9 | hierarchy: 10 | departments: 11 | - id: "dev" 12 | name: "Development" 13 | description: "Simple development team" 14 | roles: 15 | - roleType: "engineering" 16 | title: "Developer" 17 | responsibilities: 18 | - "Development" 19 | reportsTo: "Lead" 20 | 21 | --- 22 | apiVersion: haconiwa.dev/v1 23 | kind: Space 24 | metadata: 25 | name: simple-dev-world 26 | spec: 27 | nations: 28 | - id: jp 29 | name: Japan 30 | cities: 31 | - id: tokyo 32 | name: Tokyo 33 | villages: 34 | - id: dev-village 35 | name: Dev Village 36 | companies: 37 | - name: simple-dev-company 38 | grid: 1x3 39 | organizationRef: "simple-dev-org" 40 | gitRepo: 41 | url: "https://github.com/dai-motoki/haconiwa" 42 | defaultBranch: "dev" 43 | auth: "https" 44 | buildings: 45 | - id: hq 46 | name: HQ 47 | floors: 48 | - id: floor-1 49 | name: Dev Floor 50 | rooms: 51 | - id: room-dev 52 | name: Dev Room 53 | description: "Development room with 3 desks" 54 | 55 | --- 56 | apiVersion: haconiwa.dev/v1 57 | kind: Task 58 | metadata: 59 | name: task_auto_claude_01 60 | spec: 61 | branch: task_auto_claude_01 62 | worktree: true 63 | assignee: dev01-dev-r1-d1 64 | spaceRef: simple-dev-company 65 | description: | 66 | ## タスク: Claude自動実行機能の実装 67 | 68 | ### 概要 69 | haconiwaで開発タスクを割り当ててapplyすると、tmuxのペインにてclaudeコマンドが自動で打ち込まれ、 70 | タスクディスクリプションのmdファイル(YAMLからコピーされる)を読み取って実装する機能を開発する。 71 | 72 | ### 要件 73 | 1. タスク割り当て時にタスクディスクリプションをmdファイルとして生成 74 | 2. tmuxペインでclaude-codeコマンドを自動実行 75 | 3. mdファイルをclaudeに読み込ませて実装を開始 76 | 77 | ### 実装場所 78 | - src/haconiwa/agent/claude_integration.py 79 | - src/haconiwa/task/manager.py 80 | - src/haconiwa/space/manager.py 81 | 82 | --- 83 | apiVersion: haconiwa.dev/v1 84 | kind: Task 85 | metadata: 86 | name: task_order_command_02 87 | spec: 88 | branch: task_order_command_02 89 | worktree: true 90 | assignee: dev01-dev-r1-d2 91 | spaceRef: simple-dev-company 92 | description: | 93 | ## タスク: 会社へのタスク発注コマンドの実装 94 | 95 | ### 概要 96 | 会社にタスクを発注するコマンドを実装する。 97 | 98 | ### 要件 99 | 1. `haconiwa task order`コマンドの新規作成 100 | 2. 会社を指定してタスクを発注できる機能 101 | 3. タスクの自動割り当てロジック 102 | 103 | ### コマンド例 104 | ```bash 105 | haconiwa task order --company simple-dev-company --description "新機能の実装" 106 | haconiwa task order -c simple-dev-company -d "バグ修正" --priority high 107 | ``` 108 | 109 | ### 実装場所 110 | - src/haconiwa/task/cli.py 111 | - src/haconiwa/task/manager.py 112 | - src/haconiwa/organization/manager.py 113 | 114 | --- 115 | apiVersion: haconiwa.dev/v1 116 | kind: Task 117 | metadata: 118 | name: task_space_info_03 119 | spec: 120 | branch: task_space_info_03 121 | worktree: true 122 | assignee: dev01-dev-r1-d3 123 | spaceRef: simple-dev-company 124 | description: | 125 | ## タスク: Space情報表示コマンドの実装 126 | 127 | ### 概要 128 | haconiwa applyをすると作成のログが出てくるが、その際の組織図などの情報を 129 | 会社やワールド単位でhaconiwaコマンドで確認できるようにする。 130 | 131 | ### 要件 132 | 1. `haconiwa space info`コマンドの拡張 133 | 2. フラグで表示内容を切り替え 134 | 3. 組織図、階層構造、タスク状況などの表示 135 | 136 | ### コマンド例 137 | ```bash 138 | haconiwa space info --company simple-dev-company --show-org 139 | haconiwa space info -c simple-dev-company --show-hierarchy 140 | haconiwa space info -c simple-dev-company --show-tasks 141 | haconiwa space info -c simple-dev-company --full 142 | ``` 143 | 144 | ### 実装場所 145 | - src/haconiwa/space/cli.py 146 | - src/haconiwa/space/manager.py 147 | - src/haconiwa/core/state.py -------------------------------------------------------------------------------- /src/haconiwa/utils/typer_ext.py: -------------------------------------------------------------------------------- 1 | import functools 2 | import typing 3 | from typing import Any, Callable, Dict, List, Optional, Type, TypeVar, Union 4 | 5 | import click 6 | import rich.console 7 | import rich.progress 8 | import rich.table 9 | import typer 10 | from rich.style import Style 11 | from typer import Option, Typer 12 | from typer.models import CommandInfo, Context, ParamInfo 13 | 14 | T = TypeVar("T") 15 | console = rich.console.Console() 16 | 17 | def common_options(f: Callable) -> Callable: 18 | @functools.wraps(f) 19 | def wrapper(*args, **kwargs): 20 | return f(*args, **kwargs) 21 | 22 | options = [ 23 | Option(["--verbose"], is_flag=True, help="詳細なログ出力を有効化"), 24 | Option(["--quiet"], is_flag=True, help="ログ出力を最小限に抑制"), 25 | Option(["--config"], help="設定ファイルのパス"), 26 | Option(["--no-color"], is_flag=True, help="カラー出力を無効化"), 27 | ] 28 | 29 | for option in reversed(options): 30 | wrapper = option(wrapper) 31 | return wrapper 32 | 33 | def validate_input(type_: Type[T], min_value: Optional[T] = None, max_value: Optional[T] = None): 34 | def decorator(f: Callable) -> Callable: 35 | @functools.wraps(f) 36 | def wrapper(*args, **kwargs): 37 | for arg in args: 38 | if isinstance(arg, type_): 39 | if min_value is not None and arg < min_value: 40 | raise typer.BadParameter(f"値は {min_value} 以上である必要があります") 41 | if max_value is not None and arg > max_value: 42 | raise typer.BadParameter(f"値は {max_value} 以下である必要があります") 43 | return f(*args, **kwargs) 44 | return wrapper 45 | return decorator 46 | 47 | def progress_bar(desc: str = "処理中..."): 48 | def decorator(f: Callable) -> Callable: 49 | @functools.wraps(f) 50 | def wrapper(*args, **kwargs): 51 | with rich.progress.Progress() as progress: 52 | task = progress.add_task(desc, total=100) 53 | result = f(*args, progress=progress, task_id=task, **kwargs) 54 | progress.update(task, completed=100) 55 | return result 56 | return wrapper 57 | return decorator 58 | 59 | def format_output(data: Union[List, Dict], table: bool = False): 60 | if table and isinstance(data, List): 61 | table = rich.table.Table() 62 | if data: 63 | for key in data[0].keys(): 64 | table.add_column(str(key)) 65 | for row in data: 66 | table.add_row(*[str(v) for v in row.values()]) 67 | console.print(table) 68 | else: 69 | console.print(data) 70 | 71 | def error_handler(f: Callable) -> Callable: 72 | @functools.wraps(f) 73 | def wrapper(*args, **kwargs): 74 | try: 75 | return f(*args, **kwargs) 76 | except Exception as e: 77 | console.print(f"[red]エラー: {str(e)}[/red]") 78 | raise typer.Exit(1) 79 | return wrapper 80 | 81 | def command_group(name: str) -> Typer: 82 | app = Typer(name=name) 83 | 84 | @app.callback() 85 | def callback(): 86 | """haconiwa コマンドグループ""" 87 | pass 88 | 89 | return app 90 | 91 | def confirm_action(message: str = "続行しますか?"): 92 | def decorator(f: Callable) -> Callable: 93 | @functools.wraps(f) 94 | def wrapper(*args, **kwargs): 95 | if typer.confirm(message): 96 | return f(*args, **kwargs) 97 | raise typer.Abort() 98 | return wrapper 99 | return decorator 100 | 101 | def style_text(text: str, style: str) -> str: 102 | return f"[{style}]{text}[/{style}]" 103 | 104 | def success(message: str): 105 | console.print(f"[green]✓ {message}[/green]") 106 | 107 | def warning(message: str): 108 | console.print(f"[yellow]! {message}[/yellow]") 109 | 110 | def error(message: str): 111 | console.print(f"[red]✗ {message}[/red]") 112 | 113 | def debug(message: str): 114 | if typer.get_current_context().obj.get("verbose"): 115 | console.print(f"[dim]{message}[/dim]") -------------------------------------------------------------------------------- /voice-systems/command-permission/test_gpt4o.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | GPT-4o API接続テスト 4 | """ 5 | 6 | import os 7 | from dotenv import load_dotenv 8 | 9 | # .envファイルを読み込み 10 | load_dotenv() 11 | 12 | def test_api_key(): 13 | """APIキーの確認""" 14 | api_key = os.environ.get("OPENAI_API_KEY") 15 | if api_key: 16 | print(f"✅ OPENAI_API_KEY が見つかりました") 17 | print(f"🔑 APIキー(先頭10文字): {api_key[:10]}...") 18 | print(f"📏 APIキー長: {len(api_key)} 文字") 19 | return True 20 | else: 21 | print("❌ OPENAI_API_KEY が見つかりません") 22 | return False 23 | 24 | def test_openai_import(): 25 | """OpenAIライブラリのインポートテスト""" 26 | try: 27 | import openai 28 | print(f"✅ openai ライブラリインポート成功") 29 | print(f"📦 openai バージョン: {openai.__version__}") 30 | return True 31 | except ImportError as e: 32 | print(f"❌ openai ライブラリインポートエラー: {e}") 33 | return False 34 | 35 | def test_gpt4o_simple(): 36 | """GPT-4o 簡単なテスト""" 37 | try: 38 | import openai 39 | client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY")) 40 | 41 | print("🌐 GPT-4o テストリクエスト送信中...") 42 | 43 | response = client.chat.completions.create( 44 | model="gpt-4o", 45 | messages=[ 46 | {"role": "system", "content": "あなたは数字分類の専門家です。ユーザーの入力を1、2、3のいずれかで答えてください。"}, 47 | {"role": "user", "content": "「Python実行」と言われたら何番ですか?1=Python、2=Claude、3=やめる"} 48 | ], 49 | max_tokens=5, 50 | temperature=0 51 | ) 52 | 53 | result = response.choices[0].message.content.strip() 54 | print(f"✅ GPT-4o レスポンス成功: '{result}'") 55 | 56 | return True 57 | 58 | except Exception as e: 59 | print(f"❌ GPT-4o テストエラー: {e}") 60 | return False 61 | 62 | def test_voice_classification(): 63 | """音声分類機能のテスト""" 64 | try: 65 | import openai 66 | client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY")) 67 | 68 | test_text = "Python、Python、Python、Pythonだってばー" 69 | 70 | system_prompt = """あなたは音声コマンド分類の専門家です。 71 | ユーザーの音声入力を正確に以下の4つのカテゴリに分類してください。 72 | 73 | **分類ルール:** 74 | 1 = Python実行を意味する発言 75 | 2 = Claude実行を意味する発言 76 | 3 = 実行拒否を意味する発言 77 | 0 = 判断不可能な発言 78 | 79 | **重要:** 必ず数字1つ(1, 2, 3, 0のいずれか)のみで回答してください。説明は不要です。""" 80 | 81 | print(f"🎯 分類テスト: '{test_text}'") 82 | 83 | response = client.chat.completions.create( 84 | model="gpt-4o", 85 | messages=[ 86 | {"role": "system", "content": system_prompt}, 87 | {"role": "user", "content": f"次の発言を分類してください: 「{test_text}」"} 88 | ], 89 | max_tokens=10, 90 | temperature=0 91 | ) 92 | 93 | result = response.choices[0].message.content.strip() 94 | print(f"✅ 分類結果: '{result}' (期待値: 1)") 95 | 96 | return True 97 | 98 | except Exception as e: 99 | print(f"❌ 音声分類テストエラー: {e}") 100 | return False 101 | 102 | if __name__ == "__main__": 103 | print("🔧 GPT-4o API接続診断開始") 104 | print("=" * 50) 105 | 106 | # 1. APIキー確認 107 | print("\n1️⃣ APIキー確認") 108 | api_ok = test_api_key() 109 | 110 | # 2. OpenAIライブラリ確認 111 | print("\n2️⃣ OpenAIライブラリ確認") 112 | import_ok = test_openai_import() 113 | 114 | if api_ok and import_ok: 115 | # 3. GPT-4o簡単テスト 116 | print("\n3️⃣ GPT-4o基本テスト") 117 | basic_ok = test_gpt4o_simple() 118 | 119 | if basic_ok: 120 | # 4. 音声分類テスト 121 | print("\n4️⃣ 音声分類テスト") 122 | classification_ok = test_voice_classification() 123 | 124 | if classification_ok: 125 | print("\n🎉 すべてのテストが成功しました!") 126 | else: 127 | print("\n⚠️ 音声分類テストで問題があります") 128 | else: 129 | print("\n⚠️ GPT-4o基本テストで問題があります") 130 | else: 131 | print("\n❌ 基本設定に問題があります") 132 | 133 | print("\n" + "=" * 50) 134 | print("🔧 診断完了") -------------------------------------------------------------------------------- /tests/unit/test_task.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from unittest.mock import Mock, patch 3 | from pathlib import Path 4 | from git import Repo, GitCommandError 5 | from haconiwa.task.worktree import WorktreeManager 6 | from haconiwa.core.config import Config 7 | 8 | @pytest.fixture 9 | def config(): 10 | return Config(repo_path=Path("/tmp/test-repo")) 11 | 12 | @pytest.fixture 13 | def mock_repo(): 14 | repo = Mock(spec=Repo) 15 | repo.git = Mock() 16 | repo.working_dir = "/tmp/test-repo" 17 | return repo 18 | 19 | @pytest.fixture 20 | def worktree_manager(config, mock_repo): 21 | with patch("git.Repo") as mock_repo_class: 22 | mock_repo_class.return_value = mock_repo 23 | manager = WorktreeManager(config) 24 | yield manager 25 | 26 | def test_create_worktree(worktree_manager, mock_repo): 27 | task_id = "task-123" 28 | branch_name = f"feature/{task_id}" 29 | 30 | worktree_manager.create_worktree(task_id) 31 | 32 | mock_repo.git.worktree.assert_called_once_with("add", f"/tmp/test-repo/tasks/{task_id}", "-b", branch_name) 33 | 34 | def test_delete_worktree(worktree_manager, mock_repo): 35 | task_id = "task-123" 36 | worktree_path = f"/tmp/test-repo/tasks/{task_id}" 37 | 38 | worktree_manager.delete_worktree(task_id) 39 | 40 | mock_repo.git.worktree.assert_called_once_with("remove", "-f", worktree_path) 41 | 42 | def test_merge_worktree(worktree_manager, mock_repo): 43 | task_id = "task-123" 44 | branch_name = f"feature/{task_id}" 45 | 46 | worktree_manager.merge_worktree(task_id) 47 | 48 | mock_repo.git.checkout.assert_called_once_with("main") 49 | mock_repo.git.merge.assert_called_once_with(branch_name, "--no-ff") 50 | 51 | def test_list_worktrees(worktree_manager, mock_repo): 52 | mock_repo.git.worktree.return_value = """ 53 | /tmp/test-repo 12345678 [main] 54 | /tmp/test-repo/tasks/task-1 87654321 [feature/task-1] 55 | /tmp/test-repo/tasks/task-2 11223344 [feature/task-2] 56 | """ 57 | 58 | worktrees = worktree_manager.list_worktrees() 59 | 60 | assert len(worktrees) == 3 61 | assert worktrees[1]["task_id"] == "task-1" 62 | assert worktrees[2]["task_id"] == "task-2" 63 | 64 | def test_handle_merge_conflict(worktree_manager, mock_repo): 65 | task_id = "task-123" 66 | mock_repo.git.merge.side_effect = GitCommandError("merge", "Merge conflict") 67 | 68 | with pytest.raises(GitCommandError): 69 | worktree_manager.merge_worktree(task_id) 70 | 71 | mock_repo.git.merge.assert_called_once() 72 | mock_repo.git.merge.abort.assert_called_once() 73 | 74 | def test_concurrent_worktrees(worktree_manager, mock_repo): 75 | task_ids = [f"task-{i}" for i in range(3)] 76 | 77 | for task_id in task_ids: 78 | worktree_manager.create_worktree(task_id) 79 | 80 | mock_repo.git.worktree.call_count == 3 81 | 82 | for task_id in task_ids: 83 | branch_name = f"feature/{task_id}" 84 | assert any(call.args[3] == branch_name for call in mock_repo.git.worktree.call_args_list) 85 | 86 | def test_recover_from_broken_state(worktree_manager, mock_repo): 87 | task_id = "task-123" 88 | mock_repo.git.worktree.side_effect = [GitCommandError("worktree", "Broken state"), None] 89 | 90 | worktree_manager.create_worktree(task_id) 91 | 92 | assert mock_repo.git.worktree.call_count == 2 93 | mock_repo.git.worktree.assert_called_with("prune") 94 | 95 | def test_validate_task_id(worktree_manager): 96 | with pytest.raises(ValueError): 97 | worktree_manager.create_worktree("invalid/task/id") 98 | 99 | with pytest.raises(ValueError): 100 | worktree_manager.create_worktree("") 101 | 102 | def test_cleanup_stale_worktrees(worktree_manager, mock_repo): 103 | mock_repo.git.worktree.return_value = """ 104 | /tmp/test-repo/tasks/task-1 87654321 [feature/task-1] 105 | /tmp/test-repo/tasks/task-2 11223344 [gone] 106 | """ 107 | 108 | worktree_manager.cleanup_stale_worktrees() 109 | 110 | mock_repo.git.worktree.assert_any_call("remove", "-f", "/tmp/test-repo/tasks/task-2") -------------------------------------------------------------------------------- /test_32pane.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Test script for 32-pane Space CRD application 4 | """ 5 | 6 | import sys 7 | import os 8 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src')) 9 | 10 | from haconiwa.core.crd.parser import CRDParser 11 | from haconiwa.core.applier import CRDApplier 12 | from haconiwa.space.manager import SpaceManager 13 | 14 | # Test YAML for 32-pane Space CRD 15 | yaml_content = ''' 16 | apiVersion: haconiwa.dev/v1 17 | kind: Space 18 | metadata: 19 | name: test-world 20 | spec: 21 | nations: 22 | - id: jp 23 | name: Japan 24 | cities: 25 | - id: tokyo 26 | name: Tokyo 27 | villages: 28 | - id: test 29 | name: Test Village 30 | companies: 31 | - name: test-company 32 | grid: 8x4 33 | basePath: /tmp/test-desks 34 | organizations: 35 | - {id: "01", name: "Frontend Dept"} 36 | - {id: "02", name: "Backend Dept"} 37 | - {id: "03", name: "Database Dept"} 38 | - {id: "04", name: "DevOps Dept"} 39 | buildings: 40 | - id: hq 41 | name: Headquarters 42 | floors: 43 | - level: 1 44 | rooms: 45 | - {id: "room-01", name: "Alpha Room"} 46 | - {id: "room-02", name: "Beta Room"} 47 | ''' 48 | 49 | def main(): 50 | print('🚀 Testing YAML Apply → 32 Pane Creation...') 51 | 52 | try: 53 | # Parse CRD 54 | parser = CRDParser() 55 | crd = parser.parse_yaml(yaml_content) 56 | print(f'✅ CRD Parsed: {crd.metadata.name}') 57 | 58 | # Generate desk mappings to verify 59 | space_manager = SpaceManager() 60 | mappings = space_manager.generate_desk_mappings() 61 | print(f'✅ Generated {len(mappings)} desk mappings') 62 | 63 | # Display first few mappings 64 | print('📋 Desk Mappings:') 65 | for i, mapping in enumerate(mappings[:8]): 66 | print(f' {i:2d}: {mapping["desk_id"]} → {mapping["org_id"]}/{mapping["directory_name"]} ({mapping["room_id"]})') 67 | 68 | print(f' ... and {len(mappings)-8} more desks') 69 | 70 | # Display room-02 mappings 71 | print('\n📋 Room-02 Sample:') 72 | room2_mappings = [m for m in mappings if m["room_id"] == "room-02"] 73 | for i, mapping in enumerate(room2_mappings[:4]): 74 | print(f' {i+16:2d}: {mapping["desk_id"]} → {mapping["org_id"]}/{mapping["directory_name"]} ({mapping["room_id"]})') 75 | 76 | print(f'\n✅ Total: {len(mappings)} desks (expected: 32)') 77 | print(f' Room-01: {len([m for m in mappings if m["room_id"] == "room-01"])} desks') 78 | print(f' Room-02: {len([m for m in mappings if m["room_id"] == "room-02"])} desks') 79 | 80 | # Test config conversion 81 | config = space_manager.convert_crd_to_config(crd) 82 | print(f'\n✅ Config converted: {config["name"]} with {len(config.get("organizations", []))} orgs') 83 | print(f' Base path: {config["base_path"]}') 84 | print(f' Grid: {config["grid"]}') 85 | 86 | # Test directory structure (dry run) 87 | print('\n📁 Expected Directory Structure:') 88 | for i, mapping in enumerate(mappings[:4]): 89 | org_id = mapping["org_id"] 90 | dir_name = mapping["directory_name"] 91 | print(f' {config["base_path"]}/{org_id}/{dir_name}/') 92 | print(' ...') 93 | 94 | print('\n🎯 Phase 1 Test Results:') 95 | print(' ✅ CRD Parser: Working') 96 | print(' ✅ Desk Mappings: 32 desks generated') 97 | print(' ✅ Room Distribution: 16 + 16 desks') 98 | print(' ✅ Directory Naming: Correct format') 99 | print(' ✅ Config Conversion: Working') 100 | 101 | return True 102 | 103 | except Exception as e: 104 | print(f'❌ Error: {e}') 105 | import traceback 106 | traceback.print_exc() 107 | return False 108 | 109 | if __name__ == "__main__": 110 | success = main() 111 | sys.exit(0 if success else 1) -------------------------------------------------------------------------------- /voice-systems/command-permission/test_voice_simple.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | シンプルな音声認識テスト 4 | """ 5 | 6 | import pyaudio 7 | import wave 8 | import tempfile 9 | import os 10 | import openai 11 | from dotenv import load_dotenv 12 | 13 | load_dotenv() 14 | 15 | def simple_voice_test(): 16 | """シンプルな音声認識テスト""" 17 | print("🎙️ 5秒間の音声認識テスト開始") 18 | print("「はい」「Python」「クロード」「やめ」などを話してください") 19 | 20 | # より高品質な録音設定 21 | CHUNK = 4096 # より大きなチャンク 22 | FORMAT = pyaudio.paInt16 23 | CHANNELS = 1 24 | RATE = 48000 # ネイティブレート 25 | RECORD_SECONDS = 5 # 長めに録音 26 | 27 | p = pyaudio.PyAudio() 28 | 29 | try: 30 | # マイクの情報を表示 31 | default_mic = p.get_default_input_device_info() 32 | print(f"使用マイク: {default_mic['name']}") 33 | 34 | stream = p.open(format=FORMAT, 35 | channels=CHANNELS, 36 | rate=RATE, 37 | input=True, 38 | frames_per_buffer=CHUNK) 39 | 40 | print("録音開始...") 41 | frames = [] 42 | 43 | import numpy as np 44 | max_level = 0 45 | 46 | for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)): 47 | data = stream.read(CHUNK, exception_on_overflow=False) 48 | frames.append(data) 49 | 50 | # リアルタイムで音量レベルを表示 51 | audio_data = np.frombuffer(data, dtype=np.int16) 52 | if len(audio_data) > 0: 53 | level = np.max(np.abs(audio_data)) 54 | max_level = max(max_level, level) 55 | bars = int(level / 1000) 56 | bar = "█" * min(bars, 30) 57 | print(f"\r音量: [{bar:<30}] {level:5d} (最大: {max_level})", end="", flush=True) 58 | 59 | print("\n録音完了!") 60 | 61 | stream.stop_stream() 62 | stream.close() 63 | 64 | # WAVファイルに保存 65 | with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as temp_file: 66 | wf = wave.open(temp_file.name, 'wb') 67 | wf.setnchannels(CHANNELS) 68 | wf.setsampwidth(p.get_sample_size(FORMAT)) 69 | wf.setframerate(RATE) 70 | wf.writeframes(b''.join(frames)) 71 | wf.close() 72 | 73 | print(f"📁 音声ファイル保存: {temp_file.name}") 74 | 75 | # OpenAI Whisperで音声認識 76 | try: 77 | client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY")) 78 | 79 | with open(temp_file.name, "rb") as audio_file: 80 | transcript = client.audio.transcriptions.create( 81 | model="whisper-1", 82 | file=audio_file, 83 | language="ja", 84 | prompt="はい、Python、クロード、やめ、だめ、怖い、EA、実行、キャンセル、OK、Claude Code" 85 | ) 86 | 87 | recognized_text = transcript.text 88 | print(f"🎯 音声認識結果: '{recognized_text}'") 89 | 90 | # キーワード判定 91 | text_lower = recognized_text.lower() 92 | if any(word in text_lower for word in ['はい', 'ok', '実行', 'python', 'パイソン', 'やる']): 93 | print("✅ Python実行キーワードを検出") 94 | elif any(word in text_lower for word in ['claude', 'クロード', 'claude code']): 95 | print("✅ Claude実行キーワードを検出") 96 | elif any(word in text_lower for word in ['やめ', 'だめ', 'no', 'キャンセル', '怖い']): 97 | print("✅ キャンセルキーワードを検出") 98 | else: 99 | print("❓ 不明なキーワード") 100 | 101 | except Exception as e: 102 | print(f"❌ 音声認識エラー: {e}") 103 | 104 | # 一時ファイルを削除 105 | try: 106 | os.unlink(temp_file.name) 107 | except: 108 | pass 109 | 110 | except Exception as e: 111 | print(f"❌ 録音エラー: {e}") 112 | finally: 113 | p.terminate() 114 | 115 | if __name__ == "__main__": 116 | simple_voice_test() -------------------------------------------------------------------------------- /docs/VERSION_MANAGEMENT.md: -------------------------------------------------------------------------------- 1 | # Haconiwa バージョン管理ガイド 2 | 3 | このドキュメントは、haconiwaプロジェクトのバージョン管理プロセスについて説明します。 4 | 5 | ## 📋 バージョニング体系 6 | 7 | このプロジェクトは[Semantic Versioning (SemVer)](https://semver.org/lang/ja/)に従います: 8 | 9 | - **MAJOR** (`1.0.0`): 後方互換性のない変更 10 | - **MINOR** (`0.1.0`): 後方互換性のある新機能追加 11 | - **PATCH** (`0.0.1`): 後方互換性のあるバグ修正 12 | 13 | ## 🚀 リリースプロセス 14 | 15 | ### 自動リリース(推奨) 16 | 17 | ```bash 18 | # 1. リリーススクリプトを使用 19 | ./scripts/release.sh 0.1.5 20 | 21 | # 2. GitHubでRelease作成 22 | # https://github.com/dai-motoki/haconiwa/releases/new 23 | ``` 24 | 25 | ### 手動リリース 26 | 27 | ```bash 28 | # 1. バージョン更新 29 | # pyproject.toml の version を更新 30 | # README_JA.md と README.md の最新バージョンを更新 31 | 32 | # 2. CHANGELOG.md 更新 33 | # 新しいバージョンのセクションを追加 34 | 35 | # 3. パッケージビルド・アップロード 36 | python -m build 37 | python -m twine upload dist/* 38 | 39 | # 4. Git操作 40 | git add . 41 | git commit -m "chore: release v0.1.5" 42 | git tag -a "v0.1.5" -m "Release v0.1.5" 43 | git push origin main 44 | git push origin v0.1.5 45 | 46 | # 5. GitHub Release作成 47 | # https://github.com/dai-motoki/haconiwa/releases/new でリリース作成 48 | ``` 49 | 50 | ## 📝 CHANGELOG更新 51 | 52 | 新しいリリースのたびに[CHANGELOG.md](../CHANGELOG.md)を更新: 53 | 54 | ```markdown 55 | ## [0.1.5] - 2025-01-07 56 | 57 | ### Added 58 | - 新機能の説明 59 | 60 | ### Changed 61 | - 変更された機能の説明 62 | 63 | ### Fixed 64 | - 修正されたバグの説明 65 | 66 | ### Deprecated 67 | - 非推奨になった機能 68 | 69 | ### Removed 70 | - 削除された機能 71 | 72 | ### Security 73 | - セキュリティに関する修正 74 | ``` 75 | 76 | ## 🏷️ Git タグ規則 77 | 78 | - タグ形式: `v{MAJOR}.{MINOR}.{PATCH}` (例: `v0.1.4`) 79 | - 注釈付きタグを使用: `git tag -a "v0.1.4" -m "Release v0.1.4"` 80 | - タグメッセージには簡潔な変更概要を含める 81 | 82 | ## 📦 PyPI リリース 83 | 84 | 1. **テスト環境での確認**(推奨) 85 | ```bash 86 | python -m twine upload --repository testpypi dist/* 87 | ``` 88 | 89 | 2. **本番環境へのアップロード** 90 | ```bash 91 | python -m twine upload dist/* 92 | ``` 93 | 94 | ## 🔄 バージョン管理ファイル 95 | 96 | ### 更新が必要なファイル 97 | - `pyproject.toml` - パッケージバージョン 98 | - `README_JA.md` - 最新バージョン表示 99 | - `README.md` - 最新バージョン表示 100 | - `CHANGELOG.md` - 変更履歴 101 | 102 | ### 自動生成ファイル 103 | - `dist/` - ビルド成果物(`.gitignore`で除外済み) 104 | - `build/` - ビルド一時ファイル(`.gitignore`で除外済み) 105 | 106 | ## 🔧 トラブルシューティング 107 | 108 | ### PyPIアップロード時のメタデータエラー 109 | 110 | **エラー:** `InvalidDistribution: Metadata is missing required fields: Name, Version` 111 | 112 | ```bash 113 | ERROR InvalidDistribution: Metadata is missing required fields: Name, Version. 114 | Make sure the distribution includes the files where those fields are specified, and 115 | is using a supported Metadata-Version: 1.0, 1.1, 1.2, 2.0, 2.1, 2.2, 2.3. 116 | ``` 117 | 118 | **原因:** `pkginfo`ライブラリが古いバージョンの場合、メタデータの解析に問題が発生することがある 119 | 120 | **解決方法:** 121 | ```bash 122 | # pkginfoライブラリをアップグレード 123 | pip install --upgrade pkginfo 124 | 125 | # 再度ビルドしてアップロード 126 | rm -rf dist/* 127 | python -m build 128 | twine upload dist/* 129 | ``` 130 | 131 | ### src/レイアウトでのビルドエラー 132 | 133 | **問題:** pyproject.tomlでsrc/ベースのプロジェクト構造を使用している場合のパッケージ認識エラー 134 | 135 | **解決方法:** pyproject.tomlに以下の設定を追加: 136 | 137 | ```toml 138 | [tool.setuptools] 139 | package-dir = {"" = "src"} 140 | 141 | [tool.setuptools.packages.find] 142 | where = ["src"] 143 | ``` 144 | 145 | ### その他の一般的なエラー 146 | 147 | 1. **twineの認証エラー** 148 | ```bash 149 | # PyPIのAPIトークンを使用する場合 150 | twine upload --username __token__ --password YOUR_API_TOKEN dist/* 151 | ``` 152 | 153 | 2. **ビルドファイルの競合** 154 | ```bash 155 | # 古いビルドファイルをクリーン 156 | rm -rf dist/* build/* 157 | python -m build 158 | ``` 159 | 160 | ## 📋 チェックリスト 161 | 162 | リリース前の確認事項: 163 | 164 | - [ ] 全てのテストがパス 165 | - [ ] `CHANGELOG.md` が更新済み 166 | - [ ] バージョン番号が正しく更新済み 167 | - [ ] 必要な依存パッケージが最新(特に`pkginfo`, `twine`, `build`) 168 | - [ ] PyPIアップロードが成功 169 | - [ ] Gitタグが作成・プッシュ済み 170 | - [ ] GitHub Releaseが作成済み 171 | - [ ] 実際のインストールテスト完了 172 | 173 | ## 🔗 関連リンク 174 | 175 | - 📄 [CHANGELOG.md](../CHANGELOG.md) 176 | - 📦 [PyPI - haconiwa](https://pypi.org/project/haconiwa/) 177 | - 🔖 [GitHub Releases](https://github.com/dai-motoki/haconiwa/releases) 178 | - 📐 [Semantic Versioning](https://semver.org/lang/ja/) 179 | - 📝 [Keep a Changelog](https://keepachangelog.com/ja/1.0.0/) -------------------------------------------------------------------------------- /src/haconiwa/core/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | import yaml 3 | from pathlib import Path 4 | from typing import Any, Dict, Optional 5 | from pydantic import BaseModel, Field, validator 6 | from watchdog.observers import Observer 7 | from watchdog.events import FileSystemEventHandler 8 | from cryptography.fernet import Fernet 9 | 10 | class SecuritySettings(BaseModel): 11 | encryption_key: Optional[str] = None 12 | access_control: Dict[str, list] = Field(default_factory=dict) 13 | 14 | class GlobalSettings(BaseModel): 15 | debug: bool = False 16 | log_level: str = "INFO" 17 | security: SecuritySettings = Field(default_factory=SecuritySettings) 18 | 19 | class OrganizationSettings(BaseModel): 20 | org_id: str 21 | boss_model: str = "gpt-4" 22 | worker_models: Dict[str, str] = Field(default_factory=dict) 23 | task_rules: Dict[str, Any] = Field(default_factory=dict) 24 | 25 | class Config: 26 | def __init__(self, config_path: str): 27 | self.config_path = Path(config_path) 28 | self.global_config = GlobalSettings() 29 | self.org_configs: Dict[str, OrganizationSettings] = {} 30 | self._fernet = None 31 | self._observer = None 32 | self._load_config() 33 | self._setup_hot_reload() 34 | 35 | def _load_config(self) -> None: 36 | if not self.config_path.exists(): 37 | return 38 | 39 | with open(self.config_path) as f: 40 | config_data = yaml.safe_load(f) 41 | 42 | if self._fernet and config_data.get("encrypted"): 43 | config_data = yaml.safe_load( 44 | self._fernet.decrypt(config_data["data"].encode()).decode() 45 | ) 46 | 47 | self.global_config = GlobalSettings(**config_data.get("global", {})) 48 | 49 | for org_id, org_data in config_data.get("organizations", {}).items(): 50 | self.org_configs[org_id] = OrganizationSettings( 51 | org_id=org_id, **org_data 52 | ) 53 | 54 | def _setup_hot_reload(self) -> None: 55 | config_path = self.config_path 56 | load_config = self._load_config 57 | 58 | class ConfigFileHandler(FileSystemEventHandler): 59 | def on_modified(self, event): 60 | if event.src_path == str(config_path): 61 | load_config() 62 | 63 | self._observer = Observer() 64 | self._observer.schedule( 65 | ConfigFileHandler(), str(self.config_path.parent), recursive=False 66 | ) 67 | self._observer.start() 68 | 69 | def get_org_config(self, org_id: str) -> Optional[OrganizationSettings]: 70 | return self.org_configs.get(org_id) 71 | 72 | def update_org_config(self, org_id: str, **updates) -> None: 73 | if org_id not in self.org_configs: 74 | self.org_configs[org_id] = OrganizationSettings(org_id=org_id) 75 | 76 | current_config = self.org_configs[org_id].dict() 77 | current_config.update(updates) 78 | self.org_configs[org_id] = OrganizationSettings(**current_config) 79 | self._save_config() 80 | 81 | def enable_encryption(self, key: Optional[str] = None) -> None: 82 | if not key: 83 | key = Fernet.generate_key() 84 | self._fernet = Fernet(key) 85 | self.global_config.security.encryption_key = key.decode() 86 | self._save_config() 87 | 88 | def _save_config(self) -> None: 89 | config_data = { 90 | "global": self.global_config.dict(), 91 | "organizations": { 92 | org_id: config.dict() 93 | for org_id, config in self.org_configs.items() 94 | } 95 | } 96 | 97 | if self._fernet: 98 | encrypted_data = self._fernet.encrypt( 99 | yaml.dump(config_data).encode() 100 | ).decode() 101 | config_data = { 102 | "encrypted": True, 103 | "data": encrypted_data 104 | } 105 | 106 | with open(self.config_path, "w") as f: 107 | yaml.dump(config_data, f) 108 | 109 | def __del__(self): 110 | if self._observer: 111 | self._observer.stop() 112 | self._observer.join(); -------------------------------------------------------------------------------- /docs/parallel-dev-usage.md: -------------------------------------------------------------------------------- 1 | # Haconiwa Tool Parallel-Dev 使用ガイド 2 | 3 | ## 概要 4 | 5 | `haconiwa tool parallel-dev`は、Claude Code SDKを使用して複数のファイルを並列で編集する機能を提供します。最大10ファイルの同時編集が可能で、各ファイルに対して個別のプロンプトを指定できます。 6 | 7 | ## インストール 8 | 9 | ```bash 10 | # Haconiwaのインストール 11 | pip install haconiwa 12 | 13 | # Claude Code SDKの確認 14 | haconiwa tool install claude-code 15 | ``` 16 | 17 | ## 基本的な使い方 18 | 19 | ### 1. コマンドライン引数での実行 20 | 21 | ```bash 22 | # 3つのファイルを並列編集 23 | haconiwa tool parallel-dev claude \ 24 | -f src/main.py,src/utils.py,src/api.py \ 25 | -p "Add type hints to all functions","Refactor helper functions","Add error handling" 26 | ``` 27 | 28 | ### 2. ファイルリストを使った実行 29 | 30 | ```bash 31 | # ファイルとプロンプトを別ファイルで管理 32 | haconiwa tool parallel-dev claude \ 33 | --file-list examples/files.txt \ 34 | --prompt-file examples/prompts.txt \ 35 | -m 5 \ 36 | -t 120 37 | ``` 38 | 39 | ### 3. YAML設定ファイルでの実行 40 | 41 | ```yaml 42 | # parallel-dev.yaml 43 | provider: claude 44 | tasks: 45 | - file: src/models/user.py 46 | prompt: Add validation methods and type hints 47 | - file: src/models/product.py 48 | prompt: Implement inventory tracking 49 | - file: src/models/order.py 50 | prompt: Add status management 51 | options: 52 | max_concurrent: 5 53 | timeout: 90 54 | allowed_tools: [Read, Write, Edit, MultiEdit] 55 | ``` 56 | 57 | ```bash 58 | # YAML設定で実行 59 | haconiwa tool parallel-dev claude --from-yaml parallel-dev.yaml 60 | ``` 61 | 62 | ## 詳細オプション 63 | 64 | | オプション | 短縮形 | 説明 | デフォルト | 65 | |-----------|--------|------|------------| 66 | | `--files` | `-f` | カンマ区切りのファイルパスリスト | - | 67 | | `--prompts` | `-p` | カンマ区切りのプロンプトリスト | - | 68 | | `--file-list` | - | ファイルパスを含むテキストファイル | - | 69 | | `--prompt-file` | - | プロンプトを含むテキストファイル | - | 70 | | `--from-yaml` | - | YAML設定ファイル | - | 71 | | `--max-concurrent` | `-m` | 同時実行数 | 3 | 72 | | `--timeout` | `-t` | タスクブランチごとのタイムアウト(秒) | 60 | 73 | | `--dry-run` | - | 実行内容の確認のみ | False | 74 | | `--output-dir` | `-o` | 結果出力ディレクトリ | ./parallel-dev-results | 75 | | `--permission-mode` | - | 権限モード | acceptEdits | 76 | | `--allowed-tools` | - | 許可するツールのリスト | Read,Write,Edit | 77 | 78 | ## 実行例 79 | 80 | ### 10ファイルの一斉修正 81 | 82 | ```bash 83 | haconiwa tool parallel-dev claude \ 84 | -f src/models/user.py,src/models/product.py,src/models/order.py,src/services/auth.py,src/services/payment.py,src/api/routes/users.py,src/api/routes/products.py,src/utils/validators.py,src/utils/formatters.py,src/config/settings.py \ 85 | -p "Add validation and type hints","Implement inventory tracking","Add status management","Implement JWT auth","Add payment gateway","Add CRUD endpoints","Implement search","Create validation functions","Add formatting utilities","Update configuration" \ 86 | -m 5 \ 87 | -t 120 88 | ``` 89 | 90 | ### ドライラン(実行確認) 91 | 92 | ```bash 93 | haconiwa tool parallel-dev claude \ 94 | -f src/main.py,src/test.py \ 95 | -p "Add docstrings","Add unit tests" \ 96 | --dry-run 97 | ``` 98 | 99 | ## 管理コマンド 100 | 101 | ### 実行状態の確認 102 | 103 | ```bash 104 | # アクティブなタスクブランチの状態を表示 105 | haconiwa tool parallel-dev status 106 | ``` 107 | 108 | ### 実行履歴の表示 109 | 110 | ```bash 111 | # 最近の実行履歴を表示 112 | haconiwa tool parallel-dev history 113 | 114 | # 表示件数を指定 115 | haconiwa tool parallel-dev history --limit 20 116 | ``` 117 | 118 | ### タスクブランチのキャンセル(将来実装予定) 119 | 120 | ```bash 121 | # 特定のタスクブランチをキャンセル 122 | haconiwa tool parallel-dev cancel task-001 123 | ``` 124 | 125 | ## 出力結果 126 | 127 | 実行結果は以下の形式で保存されます: 128 | 129 | ``` 130 | parallel-dev-results/ 131 | ├── summary_20240613_150230.json # 実行サマリー 132 | ├── logs/ # 個別ログ 133 | │ ├── src_models_user.py_20240613_150230.log 134 | │ ├── src_models_product.py_20240613_150230.log 135 | │ └── ... 136 | └── errors/ # エラーログ 137 | └── src_services_payment.py_20240613_150230.error 138 | ``` 139 | 140 | ## エラーハンドリング 141 | 142 | - ファイル数とプロンプト数が一致しない場合はエラー 143 | - APIキーが設定されていない場合は環境変数`ANTHROPIC_API_KEY`を確認 144 | - 個別のタスクブランチが失敗しても他のタスクブランチは継続実行 145 | - タイムアウトしたタスクブランチは`timeout`ステータスで記録 146 | 147 | ## ベストプラクティス 148 | 149 | 1. **同時実行数の調整**: API制限を考慮して3-5程度に設定 150 | 2. **タイムアウトの設定**: 複雑な編集には長めのタイムアウトを設定 151 | 3. **ドライラン**: 大量のファイルを編集する前に`--dry-run`で確認 152 | 4. **YAML設定の活用**: 繰り返し実行する編集はYAMLファイルで管理 153 | 5. **エラーログの確認**: 失敗したタスクブランチはログで詳細を確認 -------------------------------------------------------------------------------- /haconiwa-npm/node_modules/cross-spawn/README.md: -------------------------------------------------------------------------------- 1 | # cross-spawn 2 | 3 | [![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][ci-image]][ci-url] [![Build status][appveyor-image]][appveyor-url] 4 | 5 | [npm-url]:https://npmjs.org/package/cross-spawn 6 | [downloads-image]:https://img.shields.io/npm/dm/cross-spawn.svg 7 | [npm-image]:https://img.shields.io/npm/v/cross-spawn.svg 8 | [ci-url]:https://github.com/moxystudio/node-cross-spawn/actions/workflows/ci.yaml 9 | [ci-image]:https://github.com/moxystudio/node-cross-spawn/actions/workflows/ci.yaml/badge.svg 10 | [appveyor-url]:https://ci.appveyor.com/project/satazor/node-cross-spawn 11 | [appveyor-image]:https://img.shields.io/appveyor/ci/satazor/node-cross-spawn/master.svg 12 | 13 | A cross platform solution to node's spawn and spawnSync. 14 | 15 | ## Installation 16 | 17 | Node.js version 8 and up: 18 | `$ npm install cross-spawn` 19 | 20 | Node.js version 7 and under: 21 | `$ npm install cross-spawn@6` 22 | 23 | ## Why 24 | 25 | Node has issues when using spawn on Windows: 26 | 27 | - It ignores [PATHEXT](https://github.com/joyent/node/issues/2318) 28 | - It does not support [shebangs](https://en.wikipedia.org/wiki/Shebang_(Unix)) 29 | - Has problems running commands with [spaces](https://github.com/nodejs/node/issues/7367) 30 | - Has problems running commands with posix relative paths (e.g.: `./my-folder/my-executable`) 31 | - Has an [issue](https://github.com/moxystudio/node-cross-spawn/issues/82) with command shims (files in `node_modules/.bin/`), where arguments with quotes and parenthesis would result in [invalid syntax error](https://github.com/moxystudio/node-cross-spawn/blob/e77b8f22a416db46b6196767bcd35601d7e11d54/test/index.test.js#L149) 32 | - No `options.shell` support on node `` where `` must not contain any arguments. 76 | If you would like to have the shebang support improved, feel free to contribute via a pull-request. 77 | 78 | Remember to always test your code on Windows! 79 | 80 | 81 | ## Tests 82 | 83 | `$ npm test` 84 | `$ npm test -- --watch` during development 85 | 86 | 87 | ## License 88 | 89 | Released under the [MIT License](https://www.opensource.org/licenses/mit-license.php). 90 | --------------------------------------------------------------------------------