@blxzer/cursor-trellis 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +124 -5
- package/README.zh-CN.md +170 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +1 -33
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/init.d.ts +0 -13
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +7 -14
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/uninstall.d.ts.map +1 -1
- package/dist/commands/uninstall.js +3 -32
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +7 -84
- package/dist/commands/update.js.map +1 -1
- package/dist/configurators/index.d.ts +7 -8
- package/dist/configurators/index.d.ts.map +1 -1
- package/dist/configurators/index.js +11 -236
- package/dist/configurators/index.js.map +1 -1
- package/dist/configurators/workflow.d.ts.map +1 -1
- package/dist/configurators/workflow.js +5 -1
- package/dist/configurators/workflow.js.map +1 -1
- package/dist/templates/common/bundled-skills/smart-search-cli/SKILL.md +3 -3
- package/dist/templates/common/bundled-skills/trellis-meta/SKILL.md +4 -2
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-agents.md +8 -15
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-hooks.md +7 -7
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-skills-or-commands.md +18 -21
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/overview.md +2 -2
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/generated-files.md +10 -7
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/overview.md +4 -4
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/agents.md +20 -31
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/hooks-and-settings.md +20 -31
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/overview.md +24 -40
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/platform-map.md +28 -59
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/skills-and-commands.md +12 -28
- package/dist/templates/common/bundled-skills/trellis-skill-creator/references/trellis-skill-locations.md +2 -2
- package/dist/templates/cursor/hooks.json +6 -0
- package/dist/templates/cursor/rules/retrieval-routing.mdc +57 -0
- package/dist/templates/extract.d.ts +0 -14
- package/dist/templates/extract.d.ts.map +1 -1
- package/dist/templates/extract.js +0 -34
- package/dist/templates/extract.js.map +1 -1
- package/dist/templates/markdown/agents.md +2 -6
- package/dist/templates/markdown/index.d.ts +1 -0
- package/dist/templates/markdown/index.d.ts.map +1 -1
- package/dist/templates/markdown/index.js +1 -0
- package/dist/templates/markdown/index.js.map +1 -1
- package/dist/templates/markdown/prompts/run-semantic-slice-12.md.txt +41 -0
- package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md.txt +14 -14
- package/dist/templates/markdown/spec/guides/cross-layer-thinking-guide.md.txt +8 -20
- package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +15 -14
- package/dist/templates/markdown/spec/guides/cursor-context-injection-guide.md.txt +2 -1
- package/dist/templates/markdown/spec/guides/cursor-semantic-compliance.md.txt +49 -0
- package/dist/templates/markdown/spec/guides/cursor-subagent-policy.md.txt +2 -2
- package/dist/templates/markdown/spec/guides/retrieval-daily-guide.md.txt +68 -20
- package/dist/templates/shared-hooks/index.d.ts +1 -1
- package/dist/templates/shared-hooks/index.d.ts.map +1 -1
- package/dist/templates/shared-hooks/index.js +1 -0
- package/dist/templates/shared-hooks/index.js.map +1 -1
- package/dist/templates/shared-hooks/inject-retrieval-plan.py +163 -0
- package/dist/templates/shared-hooks/research-end-retrieval-pack.py +2 -11
- package/dist/templates/trellis/index.d.ts +11 -0
- package/dist/templates/trellis/index.d.ts.map +1 -1
- package/dist/templates/trellis/index.js +22 -0
- package/dist/templates/trellis/index.js.map +1 -1
- package/dist/templates/trellis/scripts/aggregate_retrieval_telemetry.py +342 -0
- package/dist/templates/trellis/scripts/batch_plan_envelope.py +105 -0
- package/dist/templates/trellis/scripts/codegraph_session_smoke.py +76 -0
- package/dist/templates/trellis/scripts/common/active_task.py +116 -147
- package/dist/templates/trellis/scripts/common/cli_adapter.py +34 -710
- package/dist/templates/trellis/scripts/common/codebase_retrieval_router.py +49 -106
- package/dist/templates/trellis/scripts/common/git_context.py +17 -2
- package/dist/templates/trellis/scripts/common/project_file_stats.py +91 -0
- package/dist/templates/trellis/scripts/common/retrieval_adapter_metadata.py +9 -11
- package/dist/templates/trellis/scripts/common/retrieval_agent_instructions.py +313 -0
- package/dist/templates/trellis/scripts/common/retrieval_pack.py +0 -6
- package/dist/templates/trellis/scripts/common/retrieval_pack_context.py +0 -4
- package/dist/templates/trellis/scripts/common/retrieval_plan_gate.py +76 -0
- package/dist/templates/trellis/scripts/common/retrieval_result_ranking.py +253 -0
- package/dist/templates/trellis/scripts/common/retrieval_tool_classification.py +157 -0
- package/dist/templates/trellis/scripts/common/semantic_plan_gate.py +52 -0
- package/dist/templates/trellis/scripts/common/workflow_phase.py +3 -24
- package/dist/templates/trellis/scripts/rank_retrieval_candidates.py +80 -0
- package/dist/templates/trellis/scripts/route_codebase_retrieval.py +38 -11
- package/dist/templates/trellis/scripts/score_evidence.py +112 -0
- package/dist/templates/trellis/workflow.md +861 -960
- package/dist/types/ai-tools.d.ts +13 -16
- package/dist/types/ai-tools.d.ts.map +1 -1
- package/dist/types/ai-tools.js +5 -238
- package/dist/types/ai-tools.js.map +1 -1
- package/dist/utils/codebase-retrieval-router.d.ts +1 -8
- package/dist/utils/codebase-retrieval-router.d.ts.map +1 -1
- package/dist/utils/codebase-retrieval-router.js +39 -180
- package/dist/utils/codebase-retrieval-router.js.map +1 -1
- package/dist/utils/project-capabilities.d.ts.map +1 -1
- package/dist/utils/project-capabilities.js +10 -24
- package/dist/utils/project-capabilities.js.map +1 -1
- package/dist/utils/retrieval-agent-instructions.d.ts +14 -0
- package/dist/utils/retrieval-agent-instructions.d.ts.map +1 -0
- package/dist/utils/retrieval-agent-instructions.js +221 -0
- package/dist/utils/retrieval-agent-instructions.js.map +1 -0
- package/dist/utils/retrieval-execution-telemetry.d.ts +43 -85
- package/dist/utils/retrieval-execution-telemetry.d.ts.map +1 -1
- package/dist/utils/retrieval-execution-telemetry.js +289 -22
- package/dist/utils/retrieval-execution-telemetry.js.map +1 -1
- package/dist/utils/retrieval-result-ranking.js +1 -1
- package/dist/utils/retrieval-result-ranking.js.map +1 -1
- package/dist/utils/retrieval-tool-classification.d.ts +32 -0
- package/dist/utils/retrieval-tool-classification.d.ts.map +1 -0
- package/dist/utils/retrieval-tool-classification.js +113 -0
- package/dist/utils/retrieval-tool-classification.js.map +1 -0
- package/dist/utils/uninstall-scrubbers.d.ts +0 -36
- package/dist/utils/uninstall-scrubbers.d.ts.map +1 -1
- package/dist/utils/uninstall-scrubbers.js +0 -184
- package/dist/utils/uninstall-scrubbers.js.map +1 -1
- package/package.json +4 -2
- package/dist/commands/mem.d.ts +0 -30
- package/dist/commands/mem.d.ts.map +0 -1
- package/dist/commands/mem.js +0 -424
- package/dist/commands/mem.js.map +0 -1
- package/dist/configurators/antigravity.d.ts +0 -7
- package/dist/configurators/antigravity.d.ts.map +0 -1
- package/dist/configurators/antigravity.js +0 -19
- package/dist/configurators/antigravity.js.map +0 -1
- package/dist/configurators/claude.d.ts +0 -9
- package/dist/configurators/claude.d.ts.map +0 -1
- package/dist/configurators/claude.js +0 -72
- package/dist/configurators/claude.js.map +0 -1
- package/dist/configurators/codebuddy.d.ts +0 -10
- package/dist/configurators/codebuddy.d.ts.map +0 -1
- package/dist/configurators/codebuddy.js +0 -30
- package/dist/configurators/codebuddy.js.map +0 -1
- package/dist/configurators/codex.d.ts +0 -8
- package/dist/configurators/codex.d.ts.map +0 -1
- package/dist/configurators/codex.js +0 -87
- package/dist/configurators/codex.js.map +0 -1
- package/dist/configurators/copilot.d.ts +0 -10
- package/dist/configurators/copilot.d.ts.map +0 -1
- package/dist/configurators/copilot.js +0 -51
- package/dist/configurators/copilot.js.map +0 -1
- package/dist/configurators/droid.d.ts +0 -10
- package/dist/configurators/droid.d.ts.map +0 -1
- package/dist/configurators/droid.js +0 -30
- package/dist/configurators/droid.js.map +0 -1
- package/dist/configurators/gemini.d.ts +0 -16
- package/dist/configurators/gemini.d.ts.map +0 -1
- package/dist/configurators/gemini.js +0 -38
- package/dist/configurators/gemini.js.map +0 -1
- package/dist/configurators/kilo.d.ts +0 -7
- package/dist/configurators/kilo.d.ts.map +0 -1
- package/dist/configurators/kilo.js +0 -19
- package/dist/configurators/kilo.js.map +0 -1
- package/dist/configurators/kiro.d.ts +0 -8
- package/dist/configurators/kiro.d.ts.map +0 -1
- package/dist/configurators/kiro.js +0 -24
- package/dist/configurators/kiro.js.map +0 -1
- package/dist/configurators/opencode.d.ts +0 -14
- package/dist/configurators/opencode.d.ts.map +0 -1
- package/dist/configurators/opencode.js +0 -96
- package/dist/configurators/opencode.js.map +0 -1
- package/dist/configurators/pi.d.ts +0 -3
- package/dist/configurators/pi.d.ts.map +0 -1
- package/dist/configurators/pi.js +0 -45
- package/dist/configurators/pi.js.map +0 -1
- package/dist/configurators/qoder.d.ts +0 -11
- package/dist/configurators/qoder.d.ts.map +0 -1
- package/dist/configurators/qoder.js +0 -31
- package/dist/configurators/qoder.js.map +0 -1
- package/dist/configurators/windsurf.d.ts +0 -7
- package/dist/configurators/windsurf.d.ts.map +0 -1
- package/dist/configurators/windsurf.js +0 -19
- package/dist/configurators/windsurf.js.map +0 -1
- package/dist/templates/claude/agents/trellis-check.md +0 -124
- package/dist/templates/claude/agents/trellis-implement.md +0 -110
- package/dist/templates/claude/agents/trellis-research.md +0 -137
- package/dist/templates/claude/index.d.ts +0 -22
- package/dist/templates/claude/index.d.ts.map +0 -1
- package/dist/templates/claude/index.js +0 -46
- package/dist/templates/claude/index.js.map +0 -1
- package/dist/templates/claude/settings.json +0 -84
- package/dist/templates/codebuddy/agents/trellis-check.md +0 -115
- package/dist/templates/codebuddy/agents/trellis-implement.md +0 -110
- package/dist/templates/codebuddy/agents/trellis-research.md +0 -137
- package/dist/templates/codebuddy/index.d.ts +0 -15
- package/dist/templates/codebuddy/index.d.ts.map +0 -1
- package/dist/templates/codebuddy/index.js +0 -15
- package/dist/templates/codebuddy/index.js.map +0 -1
- package/dist/templates/codebuddy/settings.json +0 -70
- package/dist/templates/codex/agents/trellis-check.toml +0 -67
- package/dist/templates/codex/agents/trellis-implement.toml +0 -40
- package/dist/templates/codex/agents/trellis-research.toml +0 -73
- package/dist/templates/codex/config.toml +0 -28
- package/dist/templates/codex/hooks/session-start.py +0 -575
- package/dist/templates/codex/hooks.json +0 -15
- package/dist/templates/codex/index.d.ts +0 -39
- package/dist/templates/codex/index.d.ts.map +0 -1
- package/dist/templates/codex/index.js +0 -85
- package/dist/templates/codex/index.js.map +0 -1
- package/dist/templates/codex/skills/before-dev/SKILL.md +0 -40
- package/dist/templates/codex/skills/brainstorm/SKILL.md +0 -112
- package/dist/templates/codex/skills/break-loop/SKILL.md +0 -130
- package/dist/templates/codex/skills/check/SKILL.md +0 -98
- package/dist/templates/codex/skills/check-cross-layer/SKILL.md +0 -158
- package/dist/templates/codex/skills/create-command/SKILL.md +0 -101
- package/dist/templates/codex/skills/finish-work/SKILL.md +0 -90
- package/dist/templates/codex/skills/improve-ut/SKILL.md +0 -69
- package/dist/templates/codex/skills/integrate-skill/SKILL.md +0 -221
- package/dist/templates/codex/skills/onboard/SKILL.md +0 -363
- package/dist/templates/codex/skills/record-session/SKILL.md +0 -67
- package/dist/templates/codex/skills/start/SKILL.md +0 -66
- package/dist/templates/codex/skills/update-spec/SKILL.md +0 -335
- package/dist/templates/copilot/hooks/session-start.py +0 -557
- package/dist/templates/copilot/hooks.json +0 -19
- package/dist/templates/copilot/index.d.ts +0 -23
- package/dist/templates/copilot/index.d.ts.map +0 -1
- package/dist/templates/copilot/index.js +0 -54
- package/dist/templates/copilot/index.js.map +0 -1
- package/dist/templates/copilot/prompts/before-dev.prompt.md +0 -39
- package/dist/templates/copilot/prompts/brainstorm.prompt.md +0 -111
- package/dist/templates/copilot/prompts/break-loop.prompt.md +0 -129
- package/dist/templates/copilot/prompts/check-cross-layer.prompt.md +0 -157
- package/dist/templates/copilot/prompts/check.prompt.md +0 -97
- package/dist/templates/copilot/prompts/create-command.prompt.md +0 -116
- package/dist/templates/copilot/prompts/finish-work.prompt.md +0 -99
- package/dist/templates/copilot/prompts/integrate-skill.prompt.md +0 -223
- package/dist/templates/copilot/prompts/onboard.prompt.md +0 -362
- package/dist/templates/copilot/prompts/parallel.prompt.md +0 -204
- package/dist/templates/copilot/prompts/record-session.prompt.md +0 -66
- package/dist/templates/copilot/prompts/start.prompt.md +0 -63
- package/dist/templates/copilot/prompts/update-spec.prompt.md +0 -358
- package/dist/templates/droid/droids/trellis-check.md +0 -107
- package/dist/templates/droid/droids/trellis-implement.md +0 -102
- package/dist/templates/droid/droids/trellis-research.md +0 -137
- package/dist/templates/droid/index.d.ts +0 -15
- package/dist/templates/droid/index.d.ts.map +0 -1
- package/dist/templates/droid/index.js +0 -15
- package/dist/templates/droid/index.js.map +0 -1
- package/dist/templates/droid/settings.json +0 -70
- package/dist/templates/gemini/agents/trellis-check.md +0 -107
- package/dist/templates/gemini/agents/trellis-implement.md +0 -102
- package/dist/templates/gemini/agents/trellis-research.md +0 -136
- package/dist/templates/gemini/index.d.ts +0 -13
- package/dist/templates/gemini/index.d.ts.map +0 -1
- package/dist/templates/gemini/index.js +0 -13
- package/dist/templates/gemini/index.js.map +0 -1
- package/dist/templates/gemini/settings.json +0 -28
- package/dist/templates/kiro/agents/trellis-check.json +0 -26
- package/dist/templates/kiro/agents/trellis-implement.json +0 -26
- package/dist/templates/kiro/agents/trellis-research.json +0 -30
- package/dist/templates/kiro/index.d.ts +0 -18
- package/dist/templates/kiro/index.d.ts.map +0 -1
- package/dist/templates/kiro/index.js +0 -18
- package/dist/templates/kiro/index.js.map +0 -1
- package/dist/templates/opencode/agents/trellis-check.md +0 -122
- package/dist/templates/opencode/agents/trellis-implement.md +0 -118
- package/dist/templates/opencode/agents/trellis-research.md +0 -145
- package/dist/templates/opencode/lib/session-utils.js +0 -667
- package/dist/templates/opencode/lib/trellis-context.js +0 -336
- package/dist/templates/opencode/package.json +0 -5
- package/dist/templates/opencode/plugins/inject-subagent-context.js +0 -495
- package/dist/templates/opencode/plugins/inject-workflow-state.js +0 -159
- package/dist/templates/opencode/plugins/session-start.js +0 -101
- package/dist/templates/pi/agents/trellis-check.md +0 -37
- package/dist/templates/pi/agents/trellis-implement.md +0 -42
- package/dist/templates/pi/agents/trellis-research.md +0 -25
- package/dist/templates/pi/extensions/trellis/index.ts.txt +0 -1600
- package/dist/templates/pi/index.d.ts +0 -5
- package/dist/templates/pi/index.d.ts.map +0 -1
- package/dist/templates/pi/index.js +0 -12
- package/dist/templates/pi/index.js.map +0 -1
- package/dist/templates/pi/settings.json +0 -12
- package/dist/templates/qoder/agents/trellis-check.md +0 -108
- package/dist/templates/qoder/agents/trellis-implement.md +0 -103
- package/dist/templates/qoder/agents/trellis-research.md +0 -137
- package/dist/templates/qoder/index.d.ts +0 -15
- package/dist/templates/qoder/index.d.ts.map +0 -1
- package/dist/templates/qoder/index.js +0 -15
- package/dist/templates/qoder/index.js.map +0 -1
- package/dist/templates/qoder/settings.json +0 -47
|
@@ -1,34 +1,12 @@
|
|
|
1
1
|
"""
|
|
2
|
-
CLI Adapter for
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
Supported platforms:
|
|
7
|
-
- claude: Claude Code (default)
|
|
8
|
-
- opencode: OpenCode
|
|
9
|
-
- cursor: Cursor IDE
|
|
10
|
-
- iflow: iFlow CLI
|
|
11
|
-
- codex: Codex CLI (skills-based)
|
|
12
|
-
- kilo: Kilo CLI
|
|
13
|
-
- kiro: Kiro Code (skills-based)
|
|
14
|
-
- gemini: Gemini CLI
|
|
15
|
-
- antigravity: Antigravity (workflow-based)
|
|
16
|
-
- windsurf: Windsurf (workflow-based)
|
|
17
|
-
- qoder: Qoder
|
|
18
|
-
- codebuddy: CodeBuddy
|
|
19
|
-
- copilot: GitHub Copilot (VS Code)
|
|
20
|
-
- droid: Factory Droid (commands-based)
|
|
21
|
-
- pi: Pi Agent (extension-backed)
|
|
2
|
+
CLI Adapter for Cursor.
|
|
3
|
+
|
|
4
|
+
Cursor-only fork: abstracts Trellis paths and command layout for Cursor IDE.
|
|
22
5
|
|
|
23
6
|
Usage:
|
|
24
7
|
from common.cli_adapter import CLIAdapter
|
|
25
8
|
|
|
26
|
-
adapter = CLIAdapter("
|
|
27
|
-
cmd = adapter.build_run_command(
|
|
28
|
-
agent="dispatch",
|
|
29
|
-
session_id="abc123",
|
|
30
|
-
prompt="Start the pipeline"
|
|
31
|
-
)
|
|
9
|
+
adapter = CLIAdapter("cursor")
|
|
32
10
|
"""
|
|
33
11
|
|
|
34
12
|
from __future__ import annotations
|
|
@@ -37,280 +15,49 @@ from dataclasses import dataclass
|
|
|
37
15
|
from pathlib import Path
|
|
38
16
|
from typing import ClassVar, Literal
|
|
39
17
|
|
|
40
|
-
Platform = Literal[
|
|
41
|
-
"claude",
|
|
42
|
-
"opencode",
|
|
43
|
-
"cursor",
|
|
44
|
-
"iflow",
|
|
45
|
-
"codex",
|
|
46
|
-
"kilo",
|
|
47
|
-
"kiro",
|
|
48
|
-
"gemini",
|
|
49
|
-
"antigravity",
|
|
50
|
-
"windsurf",
|
|
51
|
-
"qoder",
|
|
52
|
-
"codebuddy",
|
|
53
|
-
"copilot",
|
|
54
|
-
"droid",
|
|
55
|
-
"pi",
|
|
56
|
-
]
|
|
18
|
+
Platform = Literal["cursor"]
|
|
57
19
|
|
|
58
20
|
|
|
59
21
|
@dataclass
|
|
60
22
|
class CLIAdapter:
|
|
61
|
-
"""Adapter for
|
|
23
|
+
"""Adapter for Cursor IDE integration."""
|
|
62
24
|
|
|
63
25
|
platform: Platform
|
|
64
26
|
|
|
65
|
-
# =========================================================================
|
|
66
|
-
# Agent Name Mapping
|
|
67
|
-
# =========================================================================
|
|
68
|
-
|
|
69
|
-
# OpenCode has built-in agents that cannot be overridden
|
|
70
|
-
# See: https://github.com/sst/opencode/issues/4271
|
|
71
|
-
# Note: Class-level constant, not a dataclass field
|
|
72
27
|
_AGENT_NAME_MAP: ClassVar[dict[Platform, dict[str, str]]] = {
|
|
73
|
-
"
|
|
74
|
-
"opencode": {
|
|
75
|
-
"plan": "trellis-plan", # 'plan' is built-in in OpenCode
|
|
76
|
-
},
|
|
28
|
+
"cursor": {},
|
|
77
29
|
}
|
|
78
30
|
|
|
79
31
|
def get_agent_name(self, agent: str) -> str:
|
|
80
|
-
"""Get platform-specific agent name.
|
|
81
|
-
|
|
82
|
-
Args:
|
|
83
|
-
agent: Original agent name (e.g., 'plan', 'dispatch')
|
|
84
|
-
|
|
85
|
-
Returns:
|
|
86
|
-
Platform-specific agent name (e.g., 'trellis-plan' for OpenCode)
|
|
87
|
-
"""
|
|
88
32
|
mapping = self._AGENT_NAME_MAP.get(self.platform, {})
|
|
89
33
|
return mapping.get(agent, agent)
|
|
90
34
|
|
|
91
|
-
# =========================================================================
|
|
92
|
-
# Agent Path
|
|
93
|
-
# =========================================================================
|
|
94
|
-
|
|
95
35
|
@property
|
|
96
36
|
def config_dir_name(self) -> str:
|
|
97
|
-
""
|
|
98
|
-
|
|
99
|
-
Returns:
|
|
100
|
-
Directory name ('.claude', '.opencode', '.cursor', '.iflow', '.codex', '.kilocode', '.kiro', '.gemini', '.agent', '.windsurf', '.qoder', '.codebuddy', '.github/copilot', '.factory', or '.pi')
|
|
101
|
-
"""
|
|
102
|
-
if self.platform == "opencode":
|
|
103
|
-
return ".opencode"
|
|
104
|
-
elif self.platform == "cursor":
|
|
105
|
-
return ".cursor"
|
|
106
|
-
elif self.platform == "iflow":
|
|
107
|
-
return ".iflow"
|
|
108
|
-
elif self.platform == "codex":
|
|
109
|
-
return ".codex"
|
|
110
|
-
elif self.platform == "kilo":
|
|
111
|
-
return ".kilocode"
|
|
112
|
-
elif self.platform == "kiro":
|
|
113
|
-
return ".kiro"
|
|
114
|
-
elif self.platform == "gemini":
|
|
115
|
-
return ".gemini"
|
|
116
|
-
elif self.platform == "antigravity":
|
|
117
|
-
return ".agent"
|
|
118
|
-
elif self.platform == "windsurf":
|
|
119
|
-
return ".windsurf"
|
|
120
|
-
elif self.platform == "qoder":
|
|
121
|
-
return ".qoder"
|
|
122
|
-
elif self.platform == "codebuddy":
|
|
123
|
-
return ".codebuddy"
|
|
124
|
-
elif self.platform == "copilot":
|
|
125
|
-
return ".github/copilot"
|
|
126
|
-
elif self.platform == "droid":
|
|
127
|
-
return ".factory"
|
|
128
|
-
elif self.platform == "pi":
|
|
129
|
-
return ".pi"
|
|
130
|
-
else:
|
|
131
|
-
return ".claude"
|
|
37
|
+
return ".cursor"
|
|
132
38
|
|
|
133
39
|
def get_config_dir(self, project_root: Path) -> Path:
|
|
134
|
-
"""Get platform-specific config directory.
|
|
135
|
-
|
|
136
|
-
Args:
|
|
137
|
-
project_root: Project root directory
|
|
138
|
-
|
|
139
|
-
Returns:
|
|
140
|
-
Path to config directory (.claude, .opencode, .cursor, .iflow, .codex, .kilocode, .kiro, .gemini, .agent, .windsurf, .qoder, .codebuddy, .github/copilot, .factory, or .pi)
|
|
141
|
-
"""
|
|
142
40
|
return project_root / self.config_dir_name
|
|
143
41
|
|
|
144
42
|
def get_agent_path(self, agent: str, project_root: Path) -> Path:
|
|
145
|
-
"""Get path to agent definition file.
|
|
146
|
-
|
|
147
|
-
Args:
|
|
148
|
-
agent: Agent name (original, before mapping)
|
|
149
|
-
project_root: Project root directory
|
|
150
|
-
|
|
151
|
-
Returns:
|
|
152
|
-
Path to agent definition file (.md for most platforms, .toml for Codex)
|
|
153
|
-
"""
|
|
154
43
|
mapped_name = self.get_agent_name(agent)
|
|
155
|
-
if self.platform == "codex":
|
|
156
|
-
return self.get_config_dir(project_root) / "agents" / f"{mapped_name}.toml"
|
|
157
44
|
return self.get_config_dir(project_root) / "agents" / f"{mapped_name}.md"
|
|
158
45
|
|
|
159
46
|
def get_commands_path(self, project_root: Path, *parts: str) -> Path:
|
|
160
|
-
"""Get path to commands directory or specific command file.
|
|
161
|
-
|
|
162
|
-
Args:
|
|
163
|
-
project_root: Project root directory
|
|
164
|
-
*parts: Additional path parts (e.g., 'trellis', 'finish-work.md')
|
|
165
|
-
|
|
166
|
-
Returns:
|
|
167
|
-
Path to commands directory or file
|
|
168
|
-
|
|
169
|
-
Note:
|
|
170
|
-
Cursor uses prefix naming: .cursor/commands/trellis-<name>.md
|
|
171
|
-
Antigravity uses workflow directory: .agent/workflows/<name>.md
|
|
172
|
-
Windsurf uses workflow directory: .windsurf/workflows/trellis-<name>.md
|
|
173
|
-
Copilot uses prompt files: .github/prompts/<name>.prompt.md
|
|
174
|
-
Pi uses prompt templates: .pi/prompts/trellis-<name>.md
|
|
175
|
-
Claude/OpenCode use subdirectory: .claude/commands/trellis/<name>.md
|
|
176
|
-
"""
|
|
177
|
-
if self.platform == "pi":
|
|
178
|
-
prompts_dir = self.get_config_dir(project_root) / "prompts"
|
|
179
|
-
if not parts:
|
|
180
|
-
return prompts_dir
|
|
181
|
-
if len(parts) >= 2 and parts[0] == "trellis":
|
|
182
|
-
filename = parts[-1]
|
|
183
|
-
if filename.endswith(".md"):
|
|
184
|
-
filename = filename[:-3]
|
|
185
|
-
return prompts_dir / f"trellis-{filename}.md"
|
|
186
|
-
return prompts_dir / Path(*parts)
|
|
187
|
-
|
|
188
|
-
if self.platform == "windsurf":
|
|
189
|
-
workflow_dir = self.get_config_dir(project_root) / "workflows"
|
|
190
|
-
if not parts:
|
|
191
|
-
return workflow_dir
|
|
192
|
-
if len(parts) >= 2 and parts[0] == "trellis":
|
|
193
|
-
filename = parts[-1]
|
|
194
|
-
return workflow_dir / f"trellis-{filename}"
|
|
195
|
-
return workflow_dir / Path(*parts)
|
|
196
|
-
|
|
197
|
-
if self.platform in ("antigravity", "kilo"):
|
|
198
|
-
workflow_dir = self.get_config_dir(project_root) / "workflows"
|
|
199
|
-
if not parts:
|
|
200
|
-
return workflow_dir
|
|
201
|
-
if len(parts) >= 2 and parts[0] == "trellis":
|
|
202
|
-
filename = parts[-1]
|
|
203
|
-
return workflow_dir / filename
|
|
204
|
-
return workflow_dir / Path(*parts)
|
|
205
|
-
|
|
206
|
-
if self.platform == "copilot":
|
|
207
|
-
prompts_dir = project_root / ".github" / "prompts"
|
|
208
|
-
if not parts:
|
|
209
|
-
return prompts_dir
|
|
210
|
-
if len(parts) >= 2 and parts[0] == "trellis":
|
|
211
|
-
filename = parts[-1]
|
|
212
|
-
if filename.endswith(".md"):
|
|
213
|
-
filename = filename[:-3]
|
|
214
|
-
return prompts_dir / f"{filename}.prompt.md"
|
|
215
|
-
return prompts_dir / Path(*parts)
|
|
216
|
-
|
|
217
47
|
if not parts:
|
|
218
48
|
return self.get_config_dir(project_root) / "commands"
|
|
219
|
-
|
|
220
|
-
# Cursor uses prefix naming instead of subdirectory
|
|
221
|
-
if self.platform == "cursor" and len(parts) >= 2 and parts[0] == "trellis":
|
|
222
|
-
# Convert trellis/<name>.md to trellis-<name>.md
|
|
49
|
+
if len(parts) >= 2 and parts[0] == "trellis":
|
|
223
50
|
filename = parts[-1]
|
|
224
51
|
return (
|
|
225
52
|
self.get_config_dir(project_root) / "commands" / f"trellis-{filename}"
|
|
226
53
|
)
|
|
227
|
-
|
|
228
54
|
return self.get_config_dir(project_root) / "commands" / Path(*parts)
|
|
229
55
|
|
|
230
56
|
def get_trellis_command_path(self, name: str) -> str:
|
|
231
|
-
"
|
|
232
|
-
|
|
233
|
-
Args:
|
|
234
|
-
name: Command name without extension (e.g., 'finish-work', 'check')
|
|
235
|
-
|
|
236
|
-
Returns:
|
|
237
|
-
Relative path string for use in JSONL entries
|
|
238
|
-
|
|
239
|
-
Note:
|
|
240
|
-
Cursor: .cursor/commands/trellis-<name>.md
|
|
241
|
-
Codex: .agents/skills/trellis-<name>/SKILL.md
|
|
242
|
-
Kiro: .kiro/skills/trellis-<name>/SKILL.md
|
|
243
|
-
Gemini: .gemini/commands/trellis/<name>.toml
|
|
244
|
-
Antigravity: .agent/workflows/<name>.md
|
|
245
|
-
Windsurf: .windsurf/workflows/trellis-<name>.md
|
|
246
|
-
Pi: .pi/prompts/trellis-<name>.md
|
|
247
|
-
Others: .{platform}/commands/trellis/<name>.md
|
|
248
|
-
"""
|
|
249
|
-
if self.platform == "cursor":
|
|
250
|
-
return f".cursor/commands/trellis-{name}.md"
|
|
251
|
-
elif self.platform == "codex":
|
|
252
|
-
# 0.5.0-beta.0 renamed all skill dirs to add the `trellis-` prefix
|
|
253
|
-
# (see that release's manifest for the 60+ rename entries).
|
|
254
|
-
return f".agents/skills/trellis-{name}/SKILL.md"
|
|
255
|
-
elif self.platform == "kiro":
|
|
256
|
-
return f".kiro/skills/trellis-{name}/SKILL.md"
|
|
257
|
-
elif self.platform == "gemini":
|
|
258
|
-
return f".gemini/commands/trellis/{name}.toml"
|
|
259
|
-
elif self.platform == "antigravity":
|
|
260
|
-
return f".agent/workflows/{name}.md"
|
|
261
|
-
elif self.platform == "windsurf":
|
|
262
|
-
return f".windsurf/workflows/trellis-{name}.md"
|
|
263
|
-
elif self.platform == "kilo":
|
|
264
|
-
return f".kilocode/workflows/{name}.md"
|
|
265
|
-
elif self.platform == "copilot":
|
|
266
|
-
return f".github/prompts/{name}.prompt.md"
|
|
267
|
-
elif self.platform == "droid":
|
|
268
|
-
return f".factory/commands/trellis/{name}.md"
|
|
269
|
-
elif self.platform == "pi":
|
|
270
|
-
return f".pi/prompts/trellis-{name}.md"
|
|
271
|
-
else:
|
|
272
|
-
return f"{self.config_dir_name}/commands/trellis/{name}.md"
|
|
273
|
-
|
|
274
|
-
# =========================================================================
|
|
275
|
-
# Environment Variables
|
|
276
|
-
# =========================================================================
|
|
57
|
+
return f".cursor/commands/trellis-{name}.md"
|
|
277
58
|
|
|
278
59
|
def get_non_interactive_env(self) -> dict[str, str]:
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
Returns:
|
|
282
|
-
Dict of environment variables to set
|
|
283
|
-
"""
|
|
284
|
-
if self.platform == "opencode":
|
|
285
|
-
return {"OPENCODE_NON_INTERACTIVE": "1"}
|
|
286
|
-
elif self.platform == "iflow":
|
|
287
|
-
return {"IFLOW_NON_INTERACTIVE": "1"}
|
|
288
|
-
elif self.platform == "codex":
|
|
289
|
-
return {"CODEX_NON_INTERACTIVE": "1"}
|
|
290
|
-
elif self.platform == "kiro":
|
|
291
|
-
return {"KIRO_NON_INTERACTIVE": "1"}
|
|
292
|
-
elif self.platform == "gemini":
|
|
293
|
-
return {} # Gemini CLI doesn't have a non-interactive env var
|
|
294
|
-
elif self.platform == "antigravity":
|
|
295
|
-
return {}
|
|
296
|
-
elif self.platform == "windsurf":
|
|
297
|
-
return {}
|
|
298
|
-
elif self.platform == "qoder":
|
|
299
|
-
return {}
|
|
300
|
-
elif self.platform == "codebuddy":
|
|
301
|
-
return {}
|
|
302
|
-
elif self.platform == "copilot":
|
|
303
|
-
return {}
|
|
304
|
-
elif self.platform == "droid":
|
|
305
|
-
return {}
|
|
306
|
-
elif self.platform == "pi":
|
|
307
|
-
return {}
|
|
308
|
-
else:
|
|
309
|
-
return {"CLAUDE_NON_INTERACTIVE": "1"}
|
|
310
|
-
|
|
311
|
-
# =========================================================================
|
|
312
|
-
# CLI Command Building
|
|
313
|
-
# =========================================================================
|
|
60
|
+
return {}
|
|
314
61
|
|
|
315
62
|
def build_run_command(
|
|
316
63
|
self,
|
|
@@ -321,337 +68,57 @@ class CLIAdapter:
|
|
|
321
68
|
verbose: bool = True,
|
|
322
69
|
json_output: bool = True,
|
|
323
70
|
) -> list[str]:
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
prompt: Prompt to send to the agent
|
|
329
|
-
session_id: Optional session ID (Claude Code only for creation)
|
|
330
|
-
skip_permissions: Whether to skip permission prompts
|
|
331
|
-
verbose: Whether to enable verbose output
|
|
332
|
-
json_output: Whether to use JSON output format
|
|
333
|
-
|
|
334
|
-
Returns:
|
|
335
|
-
List of command arguments
|
|
336
|
-
"""
|
|
337
|
-
mapped_agent = self.get_agent_name(agent)
|
|
338
|
-
|
|
339
|
-
if self.platform == "opencode":
|
|
340
|
-
cmd = ["opencode", "run"]
|
|
341
|
-
cmd.extend(["--agent", mapped_agent])
|
|
342
|
-
|
|
343
|
-
# Note: OpenCode 'run' mode is non-interactive by default
|
|
344
|
-
# No equivalent to Claude Code's --dangerously-skip-permissions
|
|
345
|
-
# See: https://github.com/anomalyco/opencode/issues/9070
|
|
346
|
-
|
|
347
|
-
if json_output:
|
|
348
|
-
cmd.extend(["--format", "json"])
|
|
349
|
-
|
|
350
|
-
if verbose:
|
|
351
|
-
cmd.extend(["--log-level", "DEBUG", "--print-logs"])
|
|
352
|
-
|
|
353
|
-
# Note: OpenCode doesn't support --session-id on creation
|
|
354
|
-
# Session ID must be extracted from logs after startup
|
|
355
|
-
|
|
356
|
-
cmd.append(prompt)
|
|
357
|
-
|
|
358
|
-
elif self.platform == "iflow":
|
|
359
|
-
cmd = ["iflow", "-y", "-p"]
|
|
360
|
-
cmd.append(f"${mapped_agent} {prompt}")
|
|
361
|
-
elif self.platform == "codex":
|
|
362
|
-
cmd = ["codex", "exec"]
|
|
363
|
-
cmd.append(prompt)
|
|
364
|
-
elif self.platform == "kiro":
|
|
365
|
-
cmd = ["kiro", "run", prompt]
|
|
366
|
-
elif self.platform == "gemini":
|
|
367
|
-
cmd = ["gemini"]
|
|
368
|
-
cmd.append(prompt)
|
|
369
|
-
elif self.platform == "antigravity":
|
|
370
|
-
raise ValueError(
|
|
371
|
-
"Antigravity workflows are UI slash commands; CLI agent run is not supported."
|
|
372
|
-
)
|
|
373
|
-
elif self.platform == "windsurf":
|
|
374
|
-
raise ValueError(
|
|
375
|
-
"Windsurf workflows are UI slash commands; CLI agent run is not supported."
|
|
376
|
-
)
|
|
377
|
-
elif self.platform == "qoder":
|
|
378
|
-
cmd = ["qodercli", "-p", prompt]
|
|
379
|
-
elif self.platform == "codebuddy":
|
|
380
|
-
raise ValueError(
|
|
381
|
-
"CodeBuddy does not support non-interactive mode (no CLI agent)"
|
|
382
|
-
)
|
|
383
|
-
elif self.platform == "copilot":
|
|
384
|
-
raise ValueError(
|
|
385
|
-
"GitHub Copilot is IDE-only; CLI agent run is not supported."
|
|
386
|
-
)
|
|
387
|
-
elif self.platform == "droid":
|
|
388
|
-
raise ValueError(
|
|
389
|
-
"Factory Droid CLI agent run is not yet supported."
|
|
390
|
-
)
|
|
391
|
-
elif self.platform == "pi":
|
|
392
|
-
cmd = ["pi", "-p", prompt]
|
|
393
|
-
|
|
394
|
-
else: # claude
|
|
395
|
-
cmd = ["claude", "-p"]
|
|
396
|
-
cmd.extend(["--agent", mapped_agent])
|
|
397
|
-
|
|
398
|
-
if session_id:
|
|
399
|
-
cmd.extend(["--session-id", session_id])
|
|
400
|
-
|
|
401
|
-
if skip_permissions:
|
|
402
|
-
cmd.append("--dangerously-skip-permissions")
|
|
403
|
-
|
|
404
|
-
if json_output:
|
|
405
|
-
cmd.extend(["--output-format", "stream-json"])
|
|
406
|
-
|
|
407
|
-
if verbose:
|
|
408
|
-
cmd.append("--verbose")
|
|
409
|
-
|
|
410
|
-
cmd.append(prompt)
|
|
411
|
-
|
|
412
|
-
return cmd
|
|
71
|
+
_ = (agent, prompt, session_id, skip_permissions, verbose, json_output)
|
|
72
|
+
raise ValueError(
|
|
73
|
+
"Cursor is IDE-only; CLI agent run is not supported. Use Cursor Agent in the IDE."
|
|
74
|
+
)
|
|
413
75
|
|
|
414
76
|
def build_resume_command(self, session_id: str) -> list[str]:
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
Args:
|
|
418
|
-
session_id: Session ID to resume (ignored for iFlow)
|
|
419
|
-
|
|
420
|
-
Returns:
|
|
421
|
-
List of command arguments
|
|
422
|
-
"""
|
|
423
|
-
if self.platform == "opencode":
|
|
424
|
-
return ["opencode", "run", "--session", session_id]
|
|
425
|
-
elif self.platform == "iflow":
|
|
426
|
-
# iFlow uses -c to continue most recent conversation
|
|
427
|
-
# session_id is ignored as iFlow doesn't support session IDs
|
|
428
|
-
return ["iflow", "-c"]
|
|
429
|
-
elif self.platform == "codex":
|
|
430
|
-
return ["codex", "resume", session_id]
|
|
431
|
-
elif self.platform == "kiro":
|
|
432
|
-
return ["kiro", "resume", session_id]
|
|
433
|
-
elif self.platform == "gemini":
|
|
434
|
-
return ["gemini", "--resume", session_id]
|
|
435
|
-
elif self.platform == "antigravity":
|
|
436
|
-
raise ValueError(
|
|
437
|
-
"Antigravity workflows are UI slash commands; CLI resume is not supported."
|
|
438
|
-
)
|
|
439
|
-
elif self.platform == "windsurf":
|
|
440
|
-
raise ValueError(
|
|
441
|
-
"Windsurf workflows are UI slash commands; CLI resume is not supported."
|
|
442
|
-
)
|
|
443
|
-
elif self.platform == "qoder":
|
|
444
|
-
return ["qodercli", "--resume", session_id]
|
|
445
|
-
elif self.platform == "codebuddy":
|
|
446
|
-
raise ValueError(
|
|
447
|
-
"CodeBuddy does not support non-interactive mode (no CLI agent)"
|
|
448
|
-
)
|
|
449
|
-
elif self.platform == "copilot":
|
|
450
|
-
raise ValueError(
|
|
451
|
-
"GitHub Copilot is IDE-only; CLI resume is not supported."
|
|
452
|
-
)
|
|
453
|
-
elif self.platform == "droid":
|
|
454
|
-
raise ValueError(
|
|
455
|
-
"Factory Droid CLI resume is not yet supported."
|
|
456
|
-
)
|
|
457
|
-
elif self.platform == "pi":
|
|
458
|
-
return ["pi", "-c", session_id]
|
|
459
|
-
else:
|
|
460
|
-
return ["claude", "--resume", session_id]
|
|
77
|
+
_ = session_id
|
|
78
|
+
raise ValueError("Cursor is IDE-only; CLI resume is not supported.")
|
|
461
79
|
|
|
462
80
|
def get_resume_command_str(self, session_id: str, cwd: str | None = None) -> str:
|
|
463
|
-
"""Get human-readable resume command string.
|
|
464
|
-
|
|
465
|
-
Args:
|
|
466
|
-
session_id: Session ID to resume
|
|
467
|
-
cwd: Optional working directory to cd into
|
|
468
|
-
|
|
469
|
-
Returns:
|
|
470
|
-
Command string for display
|
|
471
|
-
"""
|
|
472
81
|
cmd = self.build_resume_command(session_id)
|
|
473
82
|
cmd_str = " ".join(cmd)
|
|
474
|
-
|
|
475
83
|
if cwd:
|
|
476
84
|
return f"cd {cwd} && {cmd_str}"
|
|
477
85
|
return cmd_str
|
|
478
86
|
|
|
479
|
-
# =========================================================================
|
|
480
|
-
# Platform Detection Helpers
|
|
481
|
-
# =========================================================================
|
|
482
|
-
|
|
483
|
-
@property
|
|
484
|
-
def is_opencode(self) -> bool:
|
|
485
|
-
"""Check if platform is OpenCode."""
|
|
486
|
-
return self.platform == "opencode"
|
|
487
|
-
|
|
488
|
-
@property
|
|
489
|
-
def is_claude(self) -> bool:
|
|
490
|
-
"""Check if platform is Claude Code."""
|
|
491
|
-
return self.platform == "claude"
|
|
492
|
-
|
|
493
87
|
@property
|
|
494
88
|
def is_cursor(self) -> bool:
|
|
495
|
-
|
|
496
|
-
return self.platform == "cursor"
|
|
497
|
-
|
|
498
|
-
@property
|
|
499
|
-
def is_iflow(self) -> bool:
|
|
500
|
-
"""Check if platform is iFlow CLI."""
|
|
501
|
-
return self.platform == "iflow"
|
|
89
|
+
return True
|
|
502
90
|
|
|
503
91
|
@property
|
|
504
92
|
def cli_name(self) -> str:
|
|
505
|
-
""
|
|
506
|
-
|
|
507
|
-
Note: Cursor doesn't have a CLI tool, returns None-like value.
|
|
508
|
-
"""
|
|
509
|
-
if self.is_opencode:
|
|
510
|
-
return "opencode"
|
|
511
|
-
elif self.is_cursor:
|
|
512
|
-
return "cursor" # Note: Cursor is IDE-only, no CLI
|
|
513
|
-
elif self.platform == "iflow":
|
|
514
|
-
return "iflow"
|
|
515
|
-
elif self.platform == "kiro":
|
|
516
|
-
return "kiro"
|
|
517
|
-
elif self.platform == "gemini":
|
|
518
|
-
return "gemini"
|
|
519
|
-
elif self.platform == "antigravity":
|
|
520
|
-
return "agy"
|
|
521
|
-
elif self.platform == "windsurf":
|
|
522
|
-
return "windsurf"
|
|
523
|
-
elif self.platform == "qoder":
|
|
524
|
-
return "qodercli"
|
|
525
|
-
elif self.platform == "codebuddy":
|
|
526
|
-
return "codebuddy"
|
|
527
|
-
elif self.platform == "copilot":
|
|
528
|
-
return "copilot"
|
|
529
|
-
elif self.platform == "droid":
|
|
530
|
-
return "droid"
|
|
531
|
-
elif self.platform == "pi":
|
|
532
|
-
return "pi"
|
|
533
|
-
else:
|
|
534
|
-
return "claude"
|
|
93
|
+
return "cursor"
|
|
535
94
|
|
|
536
95
|
@property
|
|
537
96
|
def supports_cli_agents(self) -> bool:
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
Claude Code, OpenCode, iFlow, and Codex support CLI agent execution.
|
|
541
|
-
Cursor is IDE-only and doesn't support CLI agents.
|
|
542
|
-
"""
|
|
543
|
-
return self.platform in ("claude", "opencode", "iflow", "codex", "pi")
|
|
97
|
+
return False
|
|
544
98
|
|
|
545
99
|
@property
|
|
546
100
|
def requires_agent_definition_file(self) -> bool:
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
Claude Code, OpenCode, iFlow: require agent .md files (--agent flag).
|
|
550
|
-
Codex: auto-discovers agents from .codex/agents/*.toml, no --agent flag.
|
|
551
|
-
"""
|
|
552
|
-
return self.platform in ("claude", "opencode", "iflow")
|
|
553
|
-
|
|
554
|
-
# =========================================================================
|
|
555
|
-
# Session ID Handling
|
|
556
|
-
# =========================================================================
|
|
101
|
+
return True
|
|
557
102
|
|
|
558
103
|
@property
|
|
559
104
|
def supports_session_id_on_create(self) -> bool:
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
Claude Code: Yes (--session-id)
|
|
563
|
-
OpenCode: No (auto-generated, extract from logs)
|
|
564
|
-
iFlow: No (no session ID support)
|
|
565
|
-
"""
|
|
566
|
-
return self.platform == "claude"
|
|
105
|
+
return False
|
|
567
106
|
|
|
568
107
|
def extract_session_id_from_log(self, log_content: str) -> str | None:
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
OpenCode generates session IDs in format: ses_xxx
|
|
572
|
-
|
|
573
|
-
Args:
|
|
574
|
-
log_content: Log file content
|
|
575
|
-
|
|
576
|
-
Returns:
|
|
577
|
-
Session ID if found, None otherwise
|
|
578
|
-
"""
|
|
579
|
-
import re
|
|
580
|
-
|
|
581
|
-
# OpenCode session ID pattern
|
|
582
|
-
match = re.search(r"ses_[a-zA-Z0-9]+", log_content)
|
|
583
|
-
if match:
|
|
584
|
-
return match.group(0)
|
|
108
|
+
_ = log_content
|
|
585
109
|
return None
|
|
586
110
|
|
|
587
111
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
def get_cli_adapter(platform: str = "claude") -> CLIAdapter:
|
|
594
|
-
"""Get CLI adapter for the specified platform.
|
|
595
|
-
|
|
596
|
-
Args:
|
|
597
|
-
platform: Platform name ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'windsurf', 'qoder', 'codebuddy', 'copilot', 'droid', or 'pi')
|
|
598
|
-
|
|
599
|
-
Returns:
|
|
600
|
-
CLIAdapter instance
|
|
601
|
-
|
|
602
|
-
Raises:
|
|
603
|
-
ValueError: If platform is not supported
|
|
604
|
-
"""
|
|
605
|
-
if platform not in (
|
|
606
|
-
"claude",
|
|
607
|
-
"opencode",
|
|
608
|
-
"cursor",
|
|
609
|
-
"iflow",
|
|
610
|
-
"codex",
|
|
611
|
-
"kilo",
|
|
612
|
-
"kiro",
|
|
613
|
-
"gemini",
|
|
614
|
-
"antigravity",
|
|
615
|
-
"windsurf",
|
|
616
|
-
"qoder",
|
|
617
|
-
"codebuddy",
|
|
618
|
-
"copilot",
|
|
619
|
-
"droid",
|
|
620
|
-
"pi",
|
|
621
|
-
):
|
|
622
|
-
raise ValueError(
|
|
623
|
-
f"Unsupported platform: {platform} (must be 'claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'windsurf', 'qoder', 'codebuddy', 'copilot', 'droid', or 'pi')"
|
|
624
|
-
)
|
|
112
|
+
def get_cli_adapter(platform: str = "cursor") -> CLIAdapter:
|
|
113
|
+
if platform != "cursor":
|
|
114
|
+
raise ValueError(f"Unsupported platform: {platform} (must be 'cursor')")
|
|
115
|
+
return CLIAdapter(platform="cursor")
|
|
625
116
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
_ALL_PLATFORM_CONFIG_DIRS = (
|
|
630
|
-
".claude",
|
|
631
|
-
".cursor",
|
|
632
|
-
".iflow",
|
|
633
|
-
".opencode",
|
|
634
|
-
".codex",
|
|
635
|
-
".kilocode",
|
|
636
|
-
".kiro",
|
|
637
|
-
".gemini",
|
|
638
|
-
".agent",
|
|
639
|
-
".windsurf",
|
|
640
|
-
".qoder",
|
|
641
|
-
".codebuddy",
|
|
642
|
-
".github/copilot",
|
|
643
|
-
".factory",
|
|
644
|
-
".pi",
|
|
645
|
-
)
|
|
646
|
-
"""Platform-specific config directory names used by detect_platform exclusion
|
|
647
|
-
checks. `.agents/skills/` is NOT listed here: it is a shared cross-platform
|
|
648
|
-
layer (written by Codex, also consumed by Amp/Cline/Warp/etc. via the
|
|
649
|
-
agentskills.io standard), not a single-platform signal. Its presence must not
|
|
650
|
-
block detection of Kiro, Antigravity, Windsurf, or other platforms."""
|
|
117
|
+
|
|
118
|
+
_ALL_PLATFORM_CONFIG_DIRS = (".cursor",)
|
|
651
119
|
|
|
652
120
|
|
|
653
121
|
def _has_other_platform_dir(project_root: Path, exclude: set[str]) -> bool:
|
|
654
|
-
"""Check if any platform config dir exists besides those in *exclude*."""
|
|
655
122
|
return any(
|
|
656
123
|
(project_root / d).is_dir()
|
|
657
124
|
for d in _ALL_PLATFORM_CONFIG_DIRS
|
|
@@ -660,152 +127,9 @@ def _has_other_platform_dir(project_root: Path, exclude: set[str]) -> bool:
|
|
|
660
127
|
|
|
661
128
|
|
|
662
129
|
def detect_platform(project_root: Path) -> Platform:
|
|
663
|
-
"""
|
|
664
|
-
|
|
665
|
-
Detection order:
|
|
666
|
-
1. TRELLIS_PLATFORM environment variable (if set)
|
|
667
|
-
2. .opencode directory exists → opencode
|
|
668
|
-
3. .iflow directory exists → iflow
|
|
669
|
-
4. .cursor directory exists (without .claude) → cursor
|
|
670
|
-
5. .codex exists and no other platform dirs → codex
|
|
671
|
-
6. .kilocode directory exists → kilo
|
|
672
|
-
7. .kiro/skills exists and no other platform dirs → kiro
|
|
673
|
-
8. .gemini directory exists → gemini
|
|
674
|
-
9. .agent/workflows exists and no other platform dirs → antigravity
|
|
675
|
-
10. .windsurf/workflows exists and no other platform dirs → windsurf
|
|
676
|
-
11. .codebuddy directory exists → codebuddy
|
|
677
|
-
12. .qoder directory exists → qoder
|
|
678
|
-
13. .pi directory exists → pi
|
|
679
|
-
14. Default → claude
|
|
680
|
-
|
|
681
|
-
Args:
|
|
682
|
-
project_root: Project root directory
|
|
683
|
-
|
|
684
|
-
Returns:
|
|
685
|
-
Detected platform ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'windsurf', 'qoder', 'codebuddy', 'copilot', 'droid', 'pi', or default 'claude')
|
|
686
|
-
"""
|
|
687
|
-
import os
|
|
688
|
-
|
|
689
|
-
# Check environment variable first
|
|
690
|
-
env_platform = os.environ.get("TRELLIS_PLATFORM", "").lower()
|
|
691
|
-
if env_platform in (
|
|
692
|
-
"claude",
|
|
693
|
-
"opencode",
|
|
694
|
-
"cursor",
|
|
695
|
-
"iflow",
|
|
696
|
-
"codex",
|
|
697
|
-
"kilo",
|
|
698
|
-
"kiro",
|
|
699
|
-
"gemini",
|
|
700
|
-
"antigravity",
|
|
701
|
-
"windsurf",
|
|
702
|
-
"qoder",
|
|
703
|
-
"codebuddy",
|
|
704
|
-
"copilot",
|
|
705
|
-
"droid",
|
|
706
|
-
"pi",
|
|
707
|
-
):
|
|
708
|
-
return env_platform # type: ignore
|
|
709
|
-
|
|
710
|
-
# Check for .opencode directory (OpenCode-specific)
|
|
711
|
-
if (project_root / ".opencode").is_dir():
|
|
712
|
-
return "opencode"
|
|
713
|
-
|
|
714
|
-
# Check for .iflow directory (iFlow-specific)
|
|
715
|
-
if (project_root / ".iflow").is_dir():
|
|
716
|
-
return "iflow"
|
|
717
|
-
|
|
718
|
-
# Check for .cursor directory (Cursor-specific)
|
|
719
|
-
# Only detect as cursor if .claude doesn't exist (to avoid confusion)
|
|
720
|
-
if (project_root / ".cursor").is_dir() and not (project_root / ".claude").is_dir():
|
|
130
|
+
override = __import__("os").environ.get("TRELLIS_PLATFORM", "").strip().lower()
|
|
131
|
+
if override == "cursor":
|
|
721
132
|
return "cursor"
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
return "gemini"
|
|
726
|
-
|
|
727
|
-
# Check for .codex directory (Codex-specific)
|
|
728
|
-
# .agents/skills/ alone does NOT trigger codex detection (it's a shared standard)
|
|
729
|
-
if (project_root / ".codex").is_dir() and not _has_other_platform_dir(
|
|
730
|
-
project_root, {".codex", ".agents"}
|
|
731
|
-
):
|
|
732
|
-
return "codex"
|
|
733
|
-
|
|
734
|
-
# Check for .kilocode directory (Kilo-specific)
|
|
735
|
-
if (project_root / ".kilocode").is_dir():
|
|
736
|
-
return "kilo"
|
|
737
|
-
|
|
738
|
-
# Check for Kiro skills directory only when no other platform config exists
|
|
739
|
-
if (project_root / ".kiro" / "skills").is_dir() and not _has_other_platform_dir(
|
|
740
|
-
project_root, {".kiro"}
|
|
741
|
-
):
|
|
742
|
-
return "kiro"
|
|
743
|
-
|
|
744
|
-
# Check for Antigravity workflow directory only when no other platform config exists
|
|
745
|
-
if (
|
|
746
|
-
project_root / ".agent" / "workflows"
|
|
747
|
-
).is_dir() and not _has_other_platform_dir(
|
|
748
|
-
project_root, {".agent", ".gemini"}
|
|
749
|
-
):
|
|
750
|
-
return "antigravity"
|
|
751
|
-
|
|
752
|
-
# Check for Windsurf workflow directory only when no other platform config exists
|
|
753
|
-
if (
|
|
754
|
-
project_root / ".windsurf" / "workflows"
|
|
755
|
-
).is_dir() and not _has_other_platform_dir(
|
|
756
|
-
project_root, {".windsurf"}
|
|
757
|
-
):
|
|
758
|
-
return "windsurf"
|
|
759
|
-
|
|
760
|
-
# Check for .codebuddy directory (CodeBuddy-specific)
|
|
761
|
-
if (project_root / ".codebuddy").is_dir():
|
|
762
|
-
return "codebuddy"
|
|
763
|
-
|
|
764
|
-
# Check for .qoder directory (Qoder-specific)
|
|
765
|
-
if (project_root / ".qoder").is_dir():
|
|
766
|
-
return "qoder"
|
|
767
|
-
|
|
768
|
-
# Check for .github/copilot directory (GitHub Copilot-specific)
|
|
769
|
-
if (project_root / ".github" / "copilot").is_dir():
|
|
770
|
-
return "copilot"
|
|
771
|
-
|
|
772
|
-
# Check for .factory directory (Factory Droid-specific)
|
|
773
|
-
if (project_root / ".factory").is_dir():
|
|
774
|
-
return "droid"
|
|
775
|
-
|
|
776
|
-
# Check for .pi directory (Pi Agent-specific)
|
|
777
|
-
if (project_root / ".pi").is_dir():
|
|
778
|
-
return "pi"
|
|
779
|
-
|
|
780
|
-
# Fallback: checkout only has the Codex shared-skills layer
|
|
781
|
-
# (.agents/skills/trellis-* dirs) and no explicit platform config dir.
|
|
782
|
-
# Happens on fresh clones where .codex/ is gitignored/absent but the
|
|
783
|
-
# shared skills were committed to git. Must guard against the case
|
|
784
|
-
# where .claude/ or any other platform dir also exists — .agents/skills/
|
|
785
|
-
# can legitimately coexist with any platform as a shared consumption
|
|
786
|
-
# layer for Amp/Cline/Warp/etc.
|
|
787
|
-
agents_skills = project_root / ".agents" / "skills"
|
|
788
|
-
if agents_skills.is_dir() and not _has_other_platform_dir(
|
|
789
|
-
project_root, set()
|
|
790
|
-
):
|
|
791
|
-
try:
|
|
792
|
-
for entry in agents_skills.iterdir():
|
|
793
|
-
if entry.is_dir() and entry.name.startswith("trellis-"):
|
|
794
|
-
return "codex"
|
|
795
|
-
except OSError:
|
|
796
|
-
pass
|
|
797
|
-
|
|
798
|
-
return "claude"
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
def get_cli_adapter_auto(project_root: Path) -> CLIAdapter:
|
|
802
|
-
"""Get CLI adapter with auto-detected platform.
|
|
803
|
-
|
|
804
|
-
Args:
|
|
805
|
-
project_root: Project root directory
|
|
806
|
-
|
|
807
|
-
Returns:
|
|
808
|
-
CLIAdapter instance for detected platform
|
|
809
|
-
"""
|
|
810
|
-
platform = detect_platform(project_root)
|
|
811
|
-
return CLIAdapter(platform=platform)
|
|
133
|
+
if (project_root / ".cursor").is_dir():
|
|
134
|
+
return "cursor"
|
|
135
|
+
return "cursor"
|