crossby 0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- crossby-0.2.4/.claude/settings.local.json +67 -0
- crossby-0.2.4/.claude/skills/.gitignore +6 -0
- crossby-0.2.4/.gitignore +26 -0
- crossby-0.2.4/.wade/.gitignore +1 -0
- crossby-0.2.4/.wade/.wade-managed +2 -0
- crossby-0.2.4/.wade/wade.db +0 -0
- crossby-0.2.4/.wade.yml +51 -0
- crossby-0.2.4/CONTRIBUTING.md +258 -0
- crossby-0.2.4/LICENSE +21 -0
- crossby-0.2.4/PKG-INFO +260 -0
- crossby-0.2.4/PUBLISH_PLAN.md +161 -0
- crossby-0.2.4/README.md +226 -0
- crossby-0.2.4/pyproject.toml +94 -0
- crossby-0.2.4/scripts/check-all.sh +9 -0
- crossby-0.2.4/scripts/check.sh +24 -0
- crossby-0.2.4/scripts/fmt.sh +5 -0
- crossby-0.2.4/scripts/probe_models.py +553 -0
- crossby-0.2.4/scripts/setup-worktree.sh +20 -0
- crossby-0.2.4/scripts/test.sh +5 -0
- crossby-0.2.4/src/crossby/__init__.py +3 -0
- crossby-0.2.4/src/crossby/ai_tools/__init__.py +17 -0
- crossby-0.2.4/src/crossby/ai_tools/antigravity.py +59 -0
- crossby-0.2.4/src/crossby/ai_tools/base.py +484 -0
- crossby-0.2.4/src/crossby/ai_tools/claude.py +179 -0
- crossby-0.2.4/src/crossby/ai_tools/codex.py +89 -0
- crossby-0.2.4/src/crossby/ai_tools/copilot.py +96 -0
- crossby-0.2.4/src/crossby/ai_tools/cursor.py +157 -0
- crossby-0.2.4/src/crossby/ai_tools/gemini.py +73 -0
- crossby-0.2.4/src/crossby/ai_tools/model_utils.py +49 -0
- crossby-0.2.4/src/crossby/ai_tools/opencode.py +82 -0
- crossby-0.2.4/src/crossby/ai_tools/transcript.py +668 -0
- crossby-0.2.4/src/crossby/ai_tools/vscode.py +58 -0
- crossby-0.2.4/src/crossby/cli/__init__.py +0 -0
- crossby-0.2.4/src/crossby/cli/agents.py +134 -0
- crossby-0.2.4/src/crossby/cli/convert.py +106 -0
- crossby-0.2.4/src/crossby/cli/handoff.py +422 -0
- crossby-0.2.4/src/crossby/cli/init.py +450 -0
- crossby-0.2.4/src/crossby/cli/launch.py +263 -0
- crossby-0.2.4/src/crossby/cli/main.py +180 -0
- crossby-0.2.4/src/crossby/cli/stats.py +82 -0
- crossby-0.2.4/src/crossby/cli/sync.py +748 -0
- crossby-0.2.4/src/crossby/config/__init__.py +17 -0
- crossby-0.2.4/src/crossby/config/allowlist_util.py +81 -0
- crossby-0.2.4/src/crossby/config/claude_allowlist.py +128 -0
- crossby-0.2.4/src/crossby/config/copilot_hooks.py +59 -0
- crossby-0.2.4/src/crossby/config/cursor_allowlist.py +109 -0
- crossby-0.2.4/src/crossby/config/cursor_hooks.py +55 -0
- crossby-0.2.4/src/crossby/config/defaults.py +60 -0
- crossby-0.2.4/src/crossby/config/detection.py +273 -0
- crossby-0.2.4/src/crossby/config/gemini_hooks.py +47 -0
- crossby-0.2.4/src/crossby/config/instructions.py +52 -0
- crossby-0.2.4/src/crossby/config/json_utils.py +41 -0
- crossby-0.2.4/src/crossby/config/linker.py +76 -0
- crossby-0.2.4/src/crossby/config/loader.py +249 -0
- crossby-0.2.4/src/crossby/config/skills.py +63 -0
- crossby-0.2.4/src/crossby/data/__init__.py +18 -0
- crossby-0.2.4/src/crossby/data/models.json +243 -0
- crossby-0.2.4/src/crossby/data/prompts/launch_initial_message.md +1 -0
- crossby-0.2.4/src/crossby/data/prompts/summarize_cc_compact.md +72 -0
- crossby-0.2.4/src/crossby/data/prompts/summarize_default.md +13 -0
- crossby-0.2.4/src/crossby/data/skill/SKILL.md +175 -0
- crossby-0.2.4/src/crossby/data/skill/__init__.py +0 -0
- crossby-0.2.4/src/crossby/data/skill/agents/__init__.py +0 -0
- crossby-0.2.4/src/crossby/data/skill/agents/openai.yaml +4 -0
- crossby-0.2.4/src/crossby/data/skill/references/__init__.py +0 -0
- crossby-0.2.4/src/crossby/data/skill/references/differences.md +108 -0
- crossby-0.2.4/src/crossby/handoff/__init__.py +30 -0
- crossby-0.2.4/src/crossby/handoff/_utils.py +28 -0
- crossby-0.2.4/src/crossby/handoff/models.py +82 -0
- crossby-0.2.4/src/crossby/handoff/picker.py +22 -0
- crossby-0.2.4/src/crossby/handoff/prompts.py +54 -0
- crossby-0.2.4/src/crossby/handoff/readers/__init__.py +7 -0
- crossby-0.2.4/src/crossby/handoff/readers/claude.py +210 -0
- crossby-0.2.4/src/crossby/handoff/readers/codex.py +202 -0
- crossby-0.2.4/src/crossby/handoff/readers/copilot.py +187 -0
- crossby-0.2.4/src/crossby/handoff/readers/cursor.py +177 -0
- crossby-0.2.4/src/crossby/handoff/summarizer.py +343 -0
- crossby-0.2.4/src/crossby/handoff/truncate.py +66 -0
- crossby-0.2.4/src/crossby/handoff/writer.py +97 -0
- crossby-0.2.4/src/crossby/logging/__init__.py +5 -0
- crossby-0.2.4/src/crossby/logging/setup.py +42 -0
- crossby-0.2.4/src/crossby/models/__init__.py +0 -0
- crossby-0.2.4/src/crossby/models/ai.py +105 -0
- crossby-0.2.4/src/crossby/models/config.py +277 -0
- crossby-0.2.4/src/crossby/services/__init__.py +0 -0
- crossby-0.2.4/src/crossby/services/ai_resolution.py +360 -0
- crossby-0.2.4/src/crossby/services/confirm.py +145 -0
- crossby-0.2.4/src/crossby/services/handoff_resolution.py +85 -0
- crossby-0.2.4/src/crossby/services/prompt_delivery.py +37 -0
- crossby-0.2.4/src/crossby/services/sync_resolution.py +74 -0
- crossby-0.2.4/src/crossby/subagents/__init__.py +38 -0
- crossby-0.2.4/src/crossby/subagents/api.py +61 -0
- crossby-0.2.4/src/crossby/subagents/emitters.py +428 -0
- crossby-0.2.4/src/crossby/subagents/ir.py +101 -0
- crossby-0.2.4/src/crossby/subagents/parsers.py +342 -0
- crossby-0.2.4/src/crossby/subagents/tool_map.py +78 -0
- crossby-0.2.4/src/crossby/sync/__init__.py +202 -0
- crossby-0.2.4/src/crossby/sync/agent_models.py +230 -0
- crossby-0.2.4/src/crossby/sync/agents.py +1241 -0
- crossby-0.2.4/src/crossby/sync/base.py +136 -0
- crossby-0.2.4/src/crossby/sync/file_utils.py +55 -0
- crossby-0.2.4/src/crossby/sync/gitignore_utils.py +96 -0
- crossby-0.2.4/src/crossby/sync/hooks.py +600 -0
- crossby-0.2.4/src/crossby/sync/instruction_markers.py +127 -0
- crossby-0.2.4/src/crossby/sync/json_utils.py +83 -0
- crossby-0.2.4/src/crossby/sync/manual_fix.py +130 -0
- crossby-0.2.4/src/crossby/sync/mcp.py +291 -0
- crossby-0.2.4/src/crossby/sync/mcp_discovery.py +137 -0
- crossby-0.2.4/src/crossby/sync/mcp_transports.py +160 -0
- crossby-0.2.4/src/crossby/sync/permissions.py +433 -0
- crossby-0.2.4/src/crossby/sync/plan.py +200 -0
- crossby-0.2.4/src/crossby/sync/plugins.py +164 -0
- crossby-0.2.4/src/crossby/sync/readers.py +730 -0
- crossby-0.2.4/src/crossby/sync/report.py +174 -0
- crossby-0.2.4/src/crossby/sync/rules.py +397 -0
- crossby-0.2.4/src/crossby/sync/skill_install.py +154 -0
- crossby-0.2.4/src/crossby/sync/skills.py +550 -0
- crossby-0.2.4/src/crossby/sync/slash_commands.py +156 -0
- crossby-0.2.4/src/crossby/sync/translation.py +237 -0
- crossby-0.2.4/src/crossby/sync/validate.py +444 -0
- crossby-0.2.4/src/crossby/ui/__init__.py +0 -0
- crossby-0.2.4/src/crossby/ui/console.py +366 -0
- crossby-0.2.4/src/crossby/ui/prompts.py +192 -0
- crossby-0.2.4/src/crossby/utils/__init__.py +0 -0
- crossby-0.2.4/src/crossby/utils/clipboard.py +43 -0
- crossby-0.2.4/src/crossby/utils/process.py +130 -0
- crossby-0.2.4/src/crossby/utils/terminal.py +528 -0
- crossby-0.2.4/steps.md +213 -0
- crossby-0.2.4/tests/__init__.py +0 -0
- crossby-0.2.4/tests/conftest.py +0 -0
- crossby-0.2.4/tests/fixtures/handoff/claude_empty.jsonl +1 -0
- crossby-0.2.4/tests/fixtures/handoff/claude_happy.jsonl +5 -0
- crossby-0.2.4/tests/fixtures/handoff/claude_malformed.jsonl +3 -0
- crossby-0.2.4/tests/fixtures/handoff/codex_empty.jsonl +1 -0
- crossby-0.2.4/tests/fixtures/handoff/codex_happy.jsonl +6 -0
- crossby-0.2.4/tests/fixtures/handoff/codex_malformed.jsonl +4 -0
- crossby-0.2.4/tests/fixtures/handoff/copilot_events.jsonl +5 -0
- crossby-0.2.4/tests/fixtures/handoff/copilot_workspace.yaml +6 -0
- crossby-0.2.4/tests/fixtures/handoff/cursor_chat.json +7 -0
- crossby-0.2.4/tests/fixtures/handoff/cursor_empty.json +1 -0
- crossby-0.2.4/tests/fixtures/handoff/cursor_malformed.json +8 -0
- crossby-0.2.4/tests/fixtures/transcripts/claude_session.txt +57 -0
- crossby-0.2.4/tests/fixtures/transcripts/codex_session.txt +4 -0
- crossby-0.2.4/tests/fixtures/transcripts/copilot_session.txt +48 -0
- crossby-0.2.4/tests/fixtures/transcripts/gemini_session.txt +30 -0
- crossby-0.2.4/tests/fixtures/transcripts/generic_session.txt +10 -0
- crossby-0.2.4/tests/unit/__init__.py +0 -0
- crossby-0.2.4/tests/unit/test_ai_tools/__init__.py +0 -0
- crossby-0.2.4/tests/unit/test_ai_tools/test_allowed_commands.py +138 -0
- crossby-0.2.4/tests/unit/test_ai_tools/test_base_registry.py +243 -0
- crossby-0.2.4/tests/unit/test_ai_tools/test_claude_preserve_session.py +162 -0
- crossby-0.2.4/tests/unit/test_ai_tools/test_cursor_preserve_session.py +143 -0
- crossby-0.2.4/tests/unit/test_ai_tools/test_cursor_resolve_effort_model.py +56 -0
- crossby-0.2.4/tests/unit/test_ai_tools/test_model_registry.py +66 -0
- crossby-0.2.4/tests/unit/test_ai_tools/test_resume_command.py +85 -0
- crossby-0.2.4/tests/unit/test_ai_tools/test_trusted_dirs.py +46 -0
- crossby-0.2.4/tests/unit/test_cli/__init__.py +0 -0
- crossby-0.2.4/tests/unit/test_cli/test_init.py +299 -0
- crossby-0.2.4/tests/unit/test_cli/test_launch.py +515 -0
- crossby-0.2.4/tests/unit/test_cli/test_main_menu.py +264 -0
- crossby-0.2.4/tests/unit/test_cli/test_sync_cmd.py +682 -0
- crossby-0.2.4/tests/unit/test_config/__init__.py +0 -0
- crossby-0.2.4/tests/unit/test_config/test_allowlist_reader.py +82 -0
- crossby-0.2.4/tests/unit/test_config/test_allowlist_util.py +138 -0
- crossby-0.2.4/tests/unit/test_config/test_claude_allowlist.py +238 -0
- crossby-0.2.4/tests/unit/test_config/test_configure_plan_hooks.py +364 -0
- crossby-0.2.4/tests/unit/test_config/test_configure_worktree_hooks.py +324 -0
- crossby-0.2.4/tests/unit/test_config/test_cursor_allowlist.py +168 -0
- crossby-0.2.4/tests/unit/test_config/test_defaults.py +31 -0
- crossby-0.2.4/tests/unit/test_config/test_detection.py +278 -0
- crossby-0.2.4/tests/unit/test_config/test_instructions.py +74 -0
- crossby-0.2.4/tests/unit/test_config/test_linker.py +109 -0
- crossby-0.2.4/tests/unit/test_config/test_loader.py +277 -0
- crossby-0.2.4/tests/unit/test_config/test_pattern_translation.py +165 -0
- crossby-0.2.4/tests/unit/test_config/test_shims.py +148 -0
- crossby-0.2.4/tests/unit/test_config/test_skills_reader.py +76 -0
- crossby-0.2.4/tests/unit/test_handoff/__init__.py +0 -0
- crossby-0.2.4/tests/unit/test_handoff/conftest.py +20 -0
- crossby-0.2.4/tests/unit/test_handoff/test_e2e_cli.py +491 -0
- crossby-0.2.4/tests/unit/test_handoff/test_picker.py +46 -0
- crossby-0.2.4/tests/unit/test_handoff/test_prompts.py +54 -0
- crossby-0.2.4/tests/unit/test_handoff/test_readers_claude.py +95 -0
- crossby-0.2.4/tests/unit/test_handoff/test_readers_codex.py +97 -0
- crossby-0.2.4/tests/unit/test_handoff/test_readers_copilot.py +104 -0
- crossby-0.2.4/tests/unit/test_handoff/test_readers_cursor.py +99 -0
- crossby-0.2.4/tests/unit/test_handoff/test_summarizer.py +277 -0
- crossby-0.2.4/tests/unit/test_handoff/test_truncate.py +96 -0
- crossby-0.2.4/tests/unit/test_handoff/test_writer.py +126 -0
- crossby-0.2.4/tests/unit/test_logging/__init__.py +0 -0
- crossby-0.2.4/tests/unit/test_logging/test_setup.py +17 -0
- crossby-0.2.4/tests/unit/test_models/__init__.py +0 -0
- crossby-0.2.4/tests/unit/test_models/test_ai_models.py +459 -0
- crossby-0.2.4/tests/unit/test_models/test_config_models.py +80 -0
- crossby-0.2.4/tests/unit/test_services/__init__.py +0 -0
- crossby-0.2.4/tests/unit/test_services/test_ai_resolution.py +87 -0
- crossby-0.2.4/tests/unit/test_services/test_confirm.py +327 -0
- crossby-0.2.4/tests/unit/test_services/test_handoff_resolution.py +93 -0
- crossby-0.2.4/tests/unit/test_services/test_sync_resolution.py +77 -0
- crossby-0.2.4/tests/unit/test_subagents/__init__.py +0 -0
- crossby-0.2.4/tests/unit/test_subagents/test_cli.py +109 -0
- crossby-0.2.4/tests/unit/test_subagents/test_emitters.py +165 -0
- crossby-0.2.4/tests/unit/test_subagents/test_parsers.py +167 -0
- crossby-0.2.4/tests/unit/test_subagents/test_round_trip.py +118 -0
- crossby-0.2.4/tests/unit/test_sync/__init__.py +0 -0
- crossby-0.2.4/tests/unit/test_sync/test_agent_models.py +143 -0
- crossby-0.2.4/tests/unit/test_sync/test_agents.py +1570 -0
- crossby-0.2.4/tests/unit/test_sync/test_base.py +135 -0
- crossby-0.2.4/tests/unit/test_sync/test_config_rules.py +62 -0
- crossby-0.2.4/tests/unit/test_sync/test_gitignore.py +170 -0
- crossby-0.2.4/tests/unit/test_sync/test_hooks.py +793 -0
- crossby-0.2.4/tests/unit/test_sync/test_instruction_markers.py +102 -0
- crossby-0.2.4/tests/unit/test_sync/test_manual_fix.py +149 -0
- crossby-0.2.4/tests/unit/test_sync/test_mcp_config.py +65 -0
- crossby-0.2.4/tests/unit/test_sync/test_mcp_discovery.py +158 -0
- crossby-0.2.4/tests/unit/test_sync/test_mcp_transports.py +149 -0
- crossby-0.2.4/tests/unit/test_sync/test_mcp_writers.py +518 -0
- crossby-0.2.4/tests/unit/test_sync/test_permissions.py +563 -0
- crossby-0.2.4/tests/unit/test_sync/test_plan.py +168 -0
- crossby-0.2.4/tests/unit/test_sync/test_plugins.py +109 -0
- crossby-0.2.4/tests/unit/test_sync/test_readers.py +263 -0
- crossby-0.2.4/tests/unit/test_sync/test_report.py +183 -0
- crossby-0.2.4/tests/unit/test_sync/test_rules.py +460 -0
- crossby-0.2.4/tests/unit/test_sync/test_run_sync.py +297 -0
- crossby-0.2.4/tests/unit/test_sync/test_skill_install.py +82 -0
- crossby-0.2.4/tests/unit/test_sync/test_skills.py +798 -0
- crossby-0.2.4/tests/unit/test_sync/test_slash_commands.py +131 -0
- crossby-0.2.4/tests/unit/test_sync/test_sync_integration.py +134 -0
- crossby-0.2.4/tests/unit/test_sync/test_translation.py +183 -0
- crossby-0.2.4/tests/unit/test_sync/test_validate.py +250 -0
- crossby-0.2.4/tests/unit/test_transcript/__init__.py +0 -0
- crossby-0.2.4/tests/unit/test_transcript/test_parser.py +582 -0
- crossby-0.2.4/uv.lock +792 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(git pull:*)",
|
|
5
|
+
"WebFetch(domain:pypi.org)",
|
|
6
|
+
"Bash(wade task:*)",
|
|
7
|
+
"Bash(.venv/bin/python -m pytest tests/ -x -q)",
|
|
8
|
+
"Bash(.venv/bin/python -m pytest tests/unit/test_sync/test_mcp_writers.py::TestCodexMCPWriter -q)",
|
|
9
|
+
"Bash(.venv/bin/python -m pytest tests/ -q --ignore=tests/unit/test_sync/test_mcp_writers.py -k \"not Codex\")",
|
|
10
|
+
"Bash(.venv/bin/python -m pytest tests/ -q -k \"not Codex and not codex\")",
|
|
11
|
+
"Bash(.venv/bin/python -m pytest tests/unit/test_sync/test_sync_integration.py::TestFullSyncMCP::test_syncs_to_all_five_tools -q)",
|
|
12
|
+
"Bash(.venv/bin/python -m pytest tests/ -q -k \"not \\(test_syncs_to_all_five_tools or test_env_vars_preserved_across_all_formats\\)\" --ignore=tests/unit/test_sync/test_mcp_writers.py)",
|
|
13
|
+
"Bash(.venv/bin/python -m ruff check src/ 2>&1)",
|
|
14
|
+
"Bash(.venv/bin/python -m mypy src/crossby/)",
|
|
15
|
+
"Bash(.venv/bin/python -m ruff check src/crossby/config/loader.py --fix 2>&1)",
|
|
16
|
+
"Bash(.venv/bin/python -m ruff check src/crossby/config/loader.py src/crossby/cli/convert.py src/crossby/sync/permissions.py src/crossby/config/detection.py src/crossby/ai_tools/base.py src/crossby/sync/agents.py src/crossby/sync/rules.py 2>&1)",
|
|
17
|
+
"Bash(.venv/bin/python -m pytest tests/unit/test_sync/test_mcp_writers.py -k \"not Codex\" -q)",
|
|
18
|
+
"Bash(git status:*)",
|
|
19
|
+
"Bash(git checkout:*)",
|
|
20
|
+
"Bash(python3 -m pytest tests/ -x -q)",
|
|
21
|
+
"Bash(pip3 list:*)",
|
|
22
|
+
"Bash(uv run:*)",
|
|
23
|
+
"Bash(git add:*)",
|
|
24
|
+
"Bash(gh api:*)",
|
|
25
|
+
"WebSearch",
|
|
26
|
+
"Bash(python -m pytest tests/unit/test_handoff -x)",
|
|
27
|
+
"Bash(git stash *)",
|
|
28
|
+
"Bash(git commit -m ' *)",
|
|
29
|
+
"Bash(./scripts/test.sh tests/unit/test_models/test_ai_models.py::TestPlanModeArgs -v)",
|
|
30
|
+
"Bash(find /Users/ivanviragine/Documents/workspace/crossby/tests -name \"*.py\" -exec grep -l \"launch.*plan\\\\|--plan\" {} \\\\;)",
|
|
31
|
+
"Bash(./scripts/test.sh tests/)",
|
|
32
|
+
"Bash(python3 *)",
|
|
33
|
+
"Bash(find tests *)",
|
|
34
|
+
"Bash(find *)",
|
|
35
|
+
"Bash(python -m pytest tests/unit/test_sync/test_readers.py -x -q)",
|
|
36
|
+
"Bash(uv sync *)",
|
|
37
|
+
"Bash(./scripts/test.sh)",
|
|
38
|
+
"Bash(./scripts/check.sh)",
|
|
39
|
+
"Bash(./scripts/check.sh --types)",
|
|
40
|
+
"Bash(gh pr *)",
|
|
41
|
+
"Read(//tmp/**)",
|
|
42
|
+
"Bash(awk '/^diff --git a\\\\/CONTRIBUTING.md/{found=1} found{print} /^diff --git/ && !/CONTRIBUTING/{if \\(found\\) exit}' /tmp/pr43.diff)",
|
|
43
|
+
"Bash(awk '/^diff --git a\\\\/src\\\\/crossby\\\\/cli\\\\/launch.py/{found=1} found{print} /^diff --git/ && !/launch.py/{if \\(found\\) exit}' /tmp/pr43.diff)",
|
|
44
|
+
"Bash(rtk git *)",
|
|
45
|
+
"Bash(rtk gh *)",
|
|
46
|
+
"Bash(gh repo *)",
|
|
47
|
+
"Bash(rtk grep *)",
|
|
48
|
+
"Bash(bash scripts/check.sh)",
|
|
49
|
+
"Bash(rtk ls *)",
|
|
50
|
+
"Bash(rtk read *)",
|
|
51
|
+
"Bash(env)",
|
|
52
|
+
"Bash(git check-ignore *)",
|
|
53
|
+
"Bash(git rm *)",
|
|
54
|
+
"Bash(./scripts/check-all.sh)",
|
|
55
|
+
"Bash(rm -rf /tmp/crossby-publish-test)",
|
|
56
|
+
"Bash(/tmp/crossby-publish-test/bin/pip install *)",
|
|
57
|
+
"Bash(/tmp/crossby-publish-test/bin/crossby --version)",
|
|
58
|
+
"Bash(/tmp/crossby-publish-test/bin/crossby --help)",
|
|
59
|
+
"Bash(/tmp/crossby-publish-test/bin/crossby sync *)",
|
|
60
|
+
"Bash(rm -rf /tmp/publish-skill-test)",
|
|
61
|
+
"Bash(mkdir -p /tmp/publish-skill-test/.claude)",
|
|
62
|
+
"Bash(/tmp/crossby-publish-test/bin/crossby init *)",
|
|
63
|
+
"Bash(/tmp/crossby-publish-test/bin/crossby convert *)",
|
|
64
|
+
"Bash(uv build *)"
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
}
|
crossby-0.2.4/.gitignore
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*$py.class
|
|
4
|
+
*.egg-info/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
*.egg
|
|
8
|
+
.eggs/
|
|
9
|
+
*.so
|
|
10
|
+
.venv/
|
|
11
|
+
venv/
|
|
12
|
+
.env
|
|
13
|
+
.mypy_cache/
|
|
14
|
+
.pytest_cache/
|
|
15
|
+
.ruff_cache/
|
|
16
|
+
.coverage
|
|
17
|
+
htmlcov/
|
|
18
|
+
*.log
|
|
19
|
+
.commit-msg
|
|
20
|
+
.crossby.yml
|
|
21
|
+
KNOWLEDGE.md
|
|
22
|
+
.agents/
|
|
23
|
+
# wade-managed symlinks (skills sync)
|
|
24
|
+
.cursor/skills
|
|
25
|
+
.gemini/
|
|
26
|
+
.github/skills
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*
|
|
Binary file
|
crossby-0.2.4/.wade.yml
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
project:
|
|
3
|
+
main_branch: main
|
|
4
|
+
issue_label: feature-plan
|
|
5
|
+
worktrees_dir: ../.worktrees
|
|
6
|
+
branch_prefix: feat
|
|
7
|
+
merge_strategy: PR
|
|
8
|
+
ai:
|
|
9
|
+
default_tool: claude
|
|
10
|
+
default_model: claude-sonnet-4.6
|
|
11
|
+
effort: max
|
|
12
|
+
deps:
|
|
13
|
+
tool: copilot
|
|
14
|
+
model: claude-sonnet-4.6
|
|
15
|
+
mode: headless
|
|
16
|
+
review_plan:
|
|
17
|
+
tool: copilot
|
|
18
|
+
model: claude-sonnet-4.6
|
|
19
|
+
mode: headless
|
|
20
|
+
enabled: true
|
|
21
|
+
review_implementation:
|
|
22
|
+
tool: copilot
|
|
23
|
+
model: claude-sonnet-4.6
|
|
24
|
+
mode: headless
|
|
25
|
+
enabled: true
|
|
26
|
+
plan:
|
|
27
|
+
tool: claude
|
|
28
|
+
model: claude-opus-4.7
|
|
29
|
+
review_batch:
|
|
30
|
+
tool: copilot
|
|
31
|
+
model: claude-sonnet-4.6
|
|
32
|
+
mode: interactive
|
|
33
|
+
enabled: true
|
|
34
|
+
models:
|
|
35
|
+
claude:
|
|
36
|
+
easy: claude-sonnet-4.6
|
|
37
|
+
medium: claude-sonnet-4.6
|
|
38
|
+
complex: claude-opus-4.7
|
|
39
|
+
very_complex: claude-opus-4.7
|
|
40
|
+
provider:
|
|
41
|
+
name: github
|
|
42
|
+
hooks:
|
|
43
|
+
post_worktree_create: scripts/setup-worktree.sh
|
|
44
|
+
copy_to_worktree:
|
|
45
|
+
- .env
|
|
46
|
+
- KNOWLEDGE.md
|
|
47
|
+
- .wade.yml
|
|
48
|
+
- KNOWLEDGE.ratings.yml
|
|
49
|
+
knowledge:
|
|
50
|
+
enabled: true
|
|
51
|
+
path: KNOWLEDGE.md
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# Contributing to crossby
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in contributing. This document is the maintainer/developer guide — architecture, conventions, and how to extend crossby safely. If you're looking for usage docs, see [README.md](README.md).
|
|
4
|
+
|
|
5
|
+
## Development Setup
|
|
6
|
+
|
|
7
|
+
Requires Python 3.11+ and [uv](https://docs.astral.sh/uv/).
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
git clone https://github.com/ivanviragine/crossby
|
|
11
|
+
cd crossby
|
|
12
|
+
uv sync --extra dev
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Running Checks
|
|
16
|
+
|
|
17
|
+
| Command | What it does |
|
|
18
|
+
| ---------------------- | -------------------------------------------- |
|
|
19
|
+
| `./scripts/test.sh` | Run the full test suite |
|
|
20
|
+
| `./scripts/check.sh` | Lint (ruff) + type check (mypy strict) |
|
|
21
|
+
| `./scripts/fmt.sh` | Auto-format with ruff |
|
|
22
|
+
| `./scripts/check-all.sh` | Tests + lint + format check + type check |
|
|
23
|
+
|
|
24
|
+
Run `./scripts/check-all.sh` before opening a PR.
|
|
25
|
+
|
|
26
|
+
`tomli-w` is a base dependency (required for Codex MCP sync), so a plain `uv sync` pulls in everything the test suite needs.
|
|
27
|
+
|
|
28
|
+
## Architecture
|
|
29
|
+
|
|
30
|
+
### Directory Layout
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
src/crossby/
|
|
34
|
+
├── cli/ # Typer commands (entry point: cli/main.py:cli_main)
|
|
35
|
+
├── services/ # High-level orchestrators (sync, launch, handoff)
|
|
36
|
+
├── ai_tools/ # Per-tool adapters (Claude, Copilot, Gemini, Codex, …)
|
|
37
|
+
├── sync/ # Sync writers — translate and write config per tool
|
|
38
|
+
├── subagents/ # Subagent format translation (canonical IR + parsers/emitters)
|
|
39
|
+
├── handoff/ # Session readers, summarizer, prompt loader, handoff writer
|
|
40
|
+
├── config/ # .crossby.yml loading and Pydantic models
|
|
41
|
+
├── models/ # Shared data models (AIToolID, capabilities, …)
|
|
42
|
+
├── data/ # Static model catalog and bundled prompt presets
|
|
43
|
+
├── ui/ # Rich/questionary UI components
|
|
44
|
+
└── logging/ # structlog configuration
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Subagent format translation
|
|
48
|
+
|
|
49
|
+
`src/crossby/subagents/` translates a single subagent definition between
|
|
50
|
+
Claude Code, Cursor, Gemini, Copilot, and Codex. The architecture is a
|
|
51
|
+
canonical intermediate representation (`SubagentIR`) with one parser and one
|
|
52
|
+
emitter per tool — no pairwise converters. Tool-specific fields that don't
|
|
53
|
+
generalize live in `SubagentIR.extras` and are only re-emitted when the
|
|
54
|
+
target tool matches the original source.
|
|
55
|
+
|
|
56
|
+
Lossy translations surface as `ConversionWarning(severity=lossy|dropped)`
|
|
57
|
+
rather than silent drops — Cursor (no tool allowlist), Codex (only
|
|
58
|
+
`sandbox_mode`), and Copilot's required `description` are the main offenders.
|
|
59
|
+
|
|
60
|
+
Codex is the asymmetric case: its emitter returns a `CodexEmission`
|
|
61
|
+
containing both the agent `.toml` body and a `[agents.<name>]` fragment for
|
|
62
|
+
`~/.codex/config.toml`. Orchestration features (`/fleet`, `/multitask`,
|
|
63
|
+
Gemini's A2A `kind: remote`, Codex `max_depth`) are out of scope and
|
|
64
|
+
documented as not translatable.
|
|
65
|
+
|
|
66
|
+
CLI: `crossby agents convert --from <tool> --to <tool> <input>`.
|
|
67
|
+
|
|
68
|
+
### Request Flow
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
CLI command
|
|
72
|
+
→ service (e.g. run_sync)
|
|
73
|
+
→ AI tool adapter (AbstractAITool — auto-registered via __init_subclass__)
|
|
74
|
+
→ sync writer (AbstractSyncWriter, keyed by (tool_id, concern) in SyncRegistry)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Key Concepts
|
|
78
|
+
|
|
79
|
+
- **`AIToolID`** (`models/ai.py`) — a `StrEnum`. Works as both an enum member and a string key.
|
|
80
|
+
- **`AbstractAITool`** (`ai_tools/base.py`) — every adapter subclasses this. Setting the `TOOL_ID` class variable auto-registers the adapter via `__init_subclass__` — no other file needs to change.
|
|
81
|
+
- **`SyncRegistry`** (`sync/base.py`) — maps `(tool_id, concern)` → writer instance. Populated in `sync/__init__.py`; `run_sync()` orchestrates matching writers and collects `SyncResult`s.
|
|
82
|
+
- **`SyncConcern`** — enumeration of what a writer handles: `RULES`, `AGENTS`, `SKILLS`, `PERMISSIONS`, `HOOKS`, `MCP`, `PLUGINS`. `PLUGINS` is detect-only — `run_sync()` injects findings via `sync/plugins.py` after the regular writer pass.
|
|
83
|
+
- **Canonical agent IR** lives in `subagents/` (PR #46): `SubagentIR` plus one parser and one emitter per tool. `sync.agents._sync_translate` / `CodexAgentsWriter` delegate to `subagents.api.convert` for cross-tool translation; `ConversionWarning`s with `severity=lossy|dropped` are turned into `<!-- crossby:manual-fix -->` blocks by `_ir_body_with_manual_fix` before emit so the lossy edge surfaces inside the artifact, not just on the terminal.
|
|
84
|
+
- **Canonical skill model** (`sync/agent_models.py`) — `SkillDefinition` is a tool-neutral dataclass plus `parse_markdown_skill` / `render_markdown_skill` / `translate_skill_for_target`. Skills use the same on-disk SKILL.md shape across every tool today, so the canonical layer exists only to attach manual-fix notes for fields the target tool doesn't honour (Claude `allowed-tools` on non-Claude targets).
|
|
85
|
+
- **Manual-fix block** (`sync/manual_fix.py`) — when a writer can't faithfully translate a source field, it embeds a stable `<!-- crossby:manual-fix:start --> ... <!-- crossby:manual-fix:end -->` block in the rendered file. The block survives markdown rendering, sits inside TOML multi-line strings without escaping, and is replaced 1:1 on re-runs (`strip_manual_fix_blocks` + `append_manual_fix_block` + `find_manual_fix_blocks`).
|
|
86
|
+
- **Cross-provider mappings** (`sync/translation.py`) — Claude↔Codex family table for `model`, family-aware `effort` bias, and `permissionMode` ↔ `sandbox_mode`. Used by both the agents writer and `crossby launch`'s `build_launch_command` for cross-provider model translation.
|
|
87
|
+
- **Pre-write inspection** (`sync/plan.py`, `sync/validate.py`) — `--plan` summarizes a dry-run by concern + manual-fix count; `--doctor` adds validation findings and a coarse `high`/`medium`/`low` readiness rating; `--validate-target` re-parses every synced file (TOML / JSON parseability, agent required fields, skill frontmatter, MCP `command` on PATH, instruction file size).
|
|
88
|
+
- **Persistent reports** (`sync/report.py`) — every real (non-dry-run) sync writes `.crossby/sync-report.md` with a portable `| Status | Item | Notes |` table. Statuses: `Added`, `Check before using`, `Not Added` — driven by `(action, file_path)` rather than message-substring matching.
|
|
89
|
+
- **`.crossby.yml`** is loaded by `config/loader.py` into Pydantic v2 models. **Sync does not depend on it** — it reads each tool's native config directly from standard paths. The config is only consulted by `crossby launch` for defaults.
|
|
90
|
+
- **Symlinks are always relative** (`os.path.relpath`, `config/linker.py`) so they survive repo moves.
|
|
91
|
+
- **Sync is idempotent** — re-running on already-linked files is a no-op. Translate writers hash-compare rendered output before deciding `created` / `updated` / `skipped`.
|
|
92
|
+
|
|
93
|
+
### Headless vs. interactive launches
|
|
94
|
+
|
|
95
|
+
`build_launch_command` takes two distinct prompt-related parameters:
|
|
96
|
+
- `prompt` — used for batch/headless invocations (one-shot runs, CI), gated by the tool's `headless_flag`.
|
|
97
|
+
- `initial_message` — used for interactive sessions, placed as the first positional arg before any flags.
|
|
98
|
+
|
|
99
|
+
Keep these separate when adding launch logic.
|
|
100
|
+
|
|
101
|
+
## Adding a New AI Tool
|
|
102
|
+
|
|
103
|
+
The adapter pattern is designed so adding a tool is a single-file change.
|
|
104
|
+
|
|
105
|
+
1. Add the tool ID to `AIToolID` in `src/crossby/models/ai.py`.
|
|
106
|
+
2. Create `src/crossby/ai_tools/<tool>.py` subclassing `AbstractAITool`:
|
|
107
|
+
- Set `TOOL_ID = AIToolID.<TOOL>` (this auto-registers the adapter).
|
|
108
|
+
- Implement `capabilities()` returning an `AIToolCapabilities` with at minimum `binary`, `display_name`, `model_flag`, `supports_*` booleans.
|
|
109
|
+
- Override the optional hooks that apply — e.g. `yolo_args()`, `effort_args()`, `trusted_dirs_args()`, `normalize_model_format()`, `resolve_effort_model()`, `initial_message_args()`.
|
|
110
|
+
3. If the tool should participate in `crossby sync`, add writers under `src/crossby/sync/<concern>.py` for each concern it supports (see below) and register them in `sync/__init__.py`.
|
|
111
|
+
4. If the tool should be a handoff **source**, override `locate_sessions()` and `read_session()` in the adapter.
|
|
112
|
+
5. Add static model entries to `src/crossby/data/` if the tool has a known model catalog.
|
|
113
|
+
6. Add tests under `tests/` — unit tests for the adapter, and integration tests for any sync writers.
|
|
114
|
+
|
|
115
|
+
Adapters are imported via `src/crossby/ai_tools/__init__.py`. Make sure to add your import there so `__init_subclass__` runs.
|
|
116
|
+
|
|
117
|
+
## Adding a New Sync Writer
|
|
118
|
+
|
|
119
|
+
Sync writers live in `src/crossby/sync/<concern>.py` and subclass `AbstractSyncWriter` (see `sync/base.py`). Each writer:
|
|
120
|
+
|
|
121
|
+
1. Sets `tool_id: AIToolID` and `concern: SyncConcern`.
|
|
122
|
+
2. Implements `sync(data, project_root, *, dry_run, force) -> SyncResult`.
|
|
123
|
+
3. Must be idempotent — re-running on unchanged state should return `action="skipped"` (with `file_path` set when the artifact is already in place; `file_path=None` means "nothing was synced for this concern", which the report renderer maps to `Not Added`).
|
|
124
|
+
4. Must respect `dry_run` — compute the intended change but make no filesystem writes.
|
|
125
|
+
5. On write conflicts, honor `force` (backup + overwrite) vs. raising.
|
|
126
|
+
|
|
127
|
+
Register the instance in `src/crossby/sync/__init__.py` alongside the other writers. `SyncRegistry` enforces uniqueness by `(tool_id, concern)`.
|
|
128
|
+
|
|
129
|
+
### Symlink, copy, or translate
|
|
130
|
+
|
|
131
|
+
Writers that own file-tree concerns (rules, agents, skills) support up to three strategies via `SyncData.<concern>_strategy`:
|
|
132
|
+
|
|
133
|
+
- **`symlink`** (default): create relative symlinks. Cheapest; edits propagate everywhere; only works when source and target use the same on-disk schema.
|
|
134
|
+
- **`copy`**: physical copy with optional per-file rewrite (e.g. translate tool names `Bash`→`Shell` for Cursor). Used when the user wants a real file to commit, or when a marker on the source content would otherwise leak across schemas.
|
|
135
|
+
- **`translate`**: agent writers delegate to `subagents.api.convert(from_tool, to_tool, content)` (canonical `SubagentIR` + per-tool parsers/emitters). Skill writers parse via `SkillDefinition` and call `translate_skill_for_target`. Both attach manual-fix notes for fields the target doesn't honour, render back to the target's on-disk shape, hash-compare for idempotency, and remove stale outputs whose source disappeared.
|
|
136
|
+
|
|
137
|
+
When you add a new writer that handles one of these concerns, decide which strategies it supports, plumb each through `_sync_symlink` / `_sync_copy` / `_sync_translate` (see `agents.py` / `skills.py` for the existing pattern), and add tests for each strategy plus the no-op idempotent case.
|
|
138
|
+
|
|
139
|
+
### Adding a manual-fix path
|
|
140
|
+
|
|
141
|
+
If your writer translates a field that the target tool may not enforce or understand:
|
|
142
|
+
|
|
143
|
+
1. Build a `ManualFixNote` with a short `category` (e.g. `permissionMode`, `allowed-tools`) and a user-facing `message`.
|
|
144
|
+
2. Attach the note via `definition.with_notes([note])` on the canonical model.
|
|
145
|
+
3. The renderer (`render_markdown_skill`, `render_markdown_agent`, `render_toml_agent`) appends a `<!-- crossby:manual-fix --> … <!-- /crossby:manual-fix -->` block at the bottom — no extra plumbing needed.
|
|
146
|
+
|
|
147
|
+
Keep notes short and literal. Avoid Crossby-internal terminology in the message; users editing the file shouldn't need to know about `SubagentIR` or `SkillDefinition` to act on the note.
|
|
148
|
+
|
|
149
|
+
## Tool Reference
|
|
150
|
+
|
|
151
|
+
Crossby translates its unified CLI flags into each tool's native syntax. A dash (—) means the tool does not support that feature; crossby raises an error if you pass an explicit flag that the target tool doesn't support (e.g. `--yolo` with OpenCode).
|
|
152
|
+
|
|
153
|
+
### Launch Flags
|
|
154
|
+
|
|
155
|
+
| Crossby Flag | Claude | Copilot | Gemini | Codex | OpenCode | Cursor | VS Code | Antigravity |
|
|
156
|
+
| ------------- | ---------------------------------- | ----------------- | ---------------------------- | ------------------------------------------ | ----------------- | -------------------------- | ------- | ----------- |
|
|
157
|
+
| Binary | `claude` | `copilot` | `gemini` | `codex` | `opencode` | `agent` | `code` | `antigravity` |
|
|
158
|
+
| `--model` | `--model` | `--model` | `--model` | `--model` | `--model` | `--model` | — | — |
|
|
159
|
+
| `--yolo` | `--dangerously-skip-permissions` | `--yolo` | `--yolo` | `--yolo` | — | `--force` | — | — |
|
|
160
|
+
| `--plan` | `--permission-mode plan` | `--plan` | `--approval-mode plan` | — | — | `--mode plan` | — | — |
|
|
161
|
+
| `--effort` | `--effort <level>` | — | — | `-c model_reasoning_effort="…"` | `--variant <level>` | model suffix (`-thinking`) | — | — |
|
|
162
|
+
| `--prompt` | positional | `-i <prompt>` | positional | positional | `--prompt <prompt>` | positional | — | — |
|
|
163
|
+
| `--transcript`| `script` wrapper | `script` wrapper | `script` wrapper | `script` wrapper | `script` wrapper | `script` wrapper | — | — |
|
|
164
|
+
| `--resume` | `--resume <id>` | `--resume=<id>` | `--resume <id>` | `codex resume <id>` (subcommand) | `-s <id>` | — | — | — |
|
|
165
|
+
| `--trusted-dir` | `--add-dir` | `--add-dir` | `--include-directories` | `--sandbox workspace-write --add-dir` | — | — | — | — |
|
|
166
|
+
|
|
167
|
+
### Effort Level Mapping
|
|
168
|
+
|
|
169
|
+
| Crossby Level | Claude | Codex | OpenCode | Cursor |
|
|
170
|
+
| ------------- | -------- | ------- | -------- | ------------------- |
|
|
171
|
+
| `low` | `low` | `low` | `low` | — |
|
|
172
|
+
| `medium` | `medium` | `medium`| `medium` | — |
|
|
173
|
+
| `high` | `high` | `high` | `high` | `<model>-thinking` |
|
|
174
|
+
| `max` | `max` | `xhigh` | `high` | `<model>-thinking` |
|
|
175
|
+
|
|
176
|
+
### Permission & Allowlist Configuration
|
|
177
|
+
|
|
178
|
+
Crossby stores canonical command patterns (e.g. `myapp:*`) and writes them into each tool's native config format.
|
|
179
|
+
|
|
180
|
+
| Feature | Claude | Copilot | Gemini | Cursor |
|
|
181
|
+
| ------------------ | --------------------------- | ------------------------------ | ---------------------- | ----------------------------- |
|
|
182
|
+
| Config file | `.claude/settings.json` | `.github/hooks/hooks.json` | `.gemini/settings.json`| `.cursor/cli.json` |
|
|
183
|
+
| Allowlist format | `Bash(cmd:args)` | `shell(cmd:args)` | `shell(cmd:args)` | `Shell(cmd:args)` |
|
|
184
|
+
| Launch flag | `--allowedTools` | `--allow-tool` | `--allowed-tools` | — (config-file only) |
|
|
185
|
+
| Hook config | `hooks.PreToolUse` | `hooks.preToolUse` | `hooks.BeforeTool` | `preToolUse` in `hooks.json` |
|
|
186
|
+
| Hook guard matcher | `Edit\|Write\|NotebookEdit` | `Write\|Delete` | file-write tools | `Write\|Delete` |
|
|
187
|
+
|
|
188
|
+
### Session Preservation & Resume
|
|
189
|
+
|
|
190
|
+
| Feature | Claude | Copilot | Gemini | Codex | OpenCode | Cursor |
|
|
191
|
+
| ----------------------- | ----------------------- | ------------------- | --------------- | ------------------ | ---------- | ------------------------ |
|
|
192
|
+
| Resume command | `claude --resume <id>` | `copilot --resume=<id>` | `gemini --resume <id>` | `codex resume <id>` | `opencode -s <id>` | — |
|
|
193
|
+
| Session data path | `~/.claude/projects/` | — | — | — | — | `~/.cursor/projects/` |
|
|
194
|
+
| Session data preserved | Yes (worktree → main) | — | — | — | — | Yes (worktree → main) |
|
|
195
|
+
|
|
196
|
+
Session IDs are extracted automatically from transcripts when `--transcript` is used.
|
|
197
|
+
|
|
198
|
+
### Transcript Parsing (`crossby stats`)
|
|
199
|
+
|
|
200
|
+
| Feature | Claude | Copilot | Gemini | Codex |
|
|
201
|
+
| ------------------------ | ------ | ------- | ------ | ----- |
|
|
202
|
+
| Total tokens | Yes | Yes | Yes | Yes |
|
|
203
|
+
| Input / output breakdown | Yes | Yes | Yes | Yes |
|
|
204
|
+
| Cached tokens | Yes | Yes | Yes | Yes |
|
|
205
|
+
| Per-model breakdown | — | Yes | Yes | — |
|
|
206
|
+
| Premium requests | — | Yes | — | — |
|
|
207
|
+
| Session ID extraction | Yes | Yes | Yes | Yes |
|
|
208
|
+
|
|
209
|
+
### Handoff Sources & Targets
|
|
210
|
+
|
|
211
|
+
| Tool | Source (read) | Target (launch) |
|
|
212
|
+
| ------------------------------------- | ---------------------------------------------------- | --------------- |
|
|
213
|
+
| Claude | ✓ (`~/.claude/projects/<encoded>/<id>.jsonl`) | ✓ |
|
|
214
|
+
| Cursor | ✓ (`~/.cursor/projects/<encoded>/chat.json`) | ✓ |
|
|
215
|
+
| Codex | ✓ (`~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl`) | ✓ |
|
|
216
|
+
| Copilot | ✓ (`~/.copilot/session-state/<id>/events.jsonl`) | ✓ |
|
|
217
|
+
| Gemini, OpenCode, Antigravity, VS Code| — | ✓ |
|
|
218
|
+
|
|
219
|
+
### Library API (not exposed via CLI)
|
|
220
|
+
|
|
221
|
+
Available on each adapter for programmatic use:
|
|
222
|
+
|
|
223
|
+
| Feature | Claude | Copilot | Gemini | Codex | OpenCode | Cursor |
|
|
224
|
+
| ----------------- | ---------------------------------------- | ------------------- | ------------------------ | ------------ | ------------------ | --------------- |
|
|
225
|
+
| Trusted dirs | `--add-dir` | `--add-dir` | `--include-directories` | `--add-dir` | — | — |
|
|
226
|
+
| Structured output | `--output-format json --json-schema …` | — | `--output-format json` | — | — | — |
|
|
227
|
+
| Model format | dashed (`claude-haiku-4-5`) | dotted (`claude-haiku-4.5`) | as-is | as-is | `provider/model` | as-is |
|
|
228
|
+
|
|
229
|
+
## Commit Conventions
|
|
230
|
+
|
|
231
|
+
This project uses [Conventional Commits](https://www.conventionalcommits.org/):
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
<type>(<scope>): <short summary>
|
|
235
|
+
|
|
236
|
+
<optional body>
|
|
237
|
+
|
|
238
|
+
<optional footer>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Common types: `feat`, `fix`, `refactor`, `test`, `docs`, `chore`.
|
|
242
|
+
|
|
243
|
+
Examples:
|
|
244
|
+
```
|
|
245
|
+
feat(sync): add allowlist conversion for Gemini
|
|
246
|
+
fix(cli): handle missing .crossby.yml gracefully
|
|
247
|
+
docs: update compatibility table for Codex effort levels
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Breaking changes: append `!` after the type (e.g. `feat!:`) and add a `BREAKING CHANGE:` footer.
|
|
251
|
+
|
|
252
|
+
## Release Process
|
|
253
|
+
|
|
254
|
+
1. Ensure `./scripts/check-all.sh` passes on `main`.
|
|
255
|
+
2. Update the version in `pyproject.toml`.
|
|
256
|
+
3. Commit: `chore: release vX.Y.Z`.
|
|
257
|
+
4. Tag: `git tag vX.Y.Z`.
|
|
258
|
+
5. Push both: `git push origin main && git push origin vX.Y.Z`.
|
crossby-0.2.4/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Ivan Viragine
|
|
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.
|