@mindfoldhq/trellis 0.5.0-beta.9 → 0.5.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -95
- package/dist/cli/index.js +7 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +117 -117
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +289 -33
- package/dist/commands/update.js.map +1 -1
- package/dist/configurators/antigravity.d.ts.map +1 -1
- package/dist/configurators/antigravity.js +2 -8
- package/dist/configurators/antigravity.js.map +1 -1
- package/dist/configurators/claude.d.ts.map +1 -1
- package/dist/configurators/claude.js +4 -10
- package/dist/configurators/claude.js.map +1 -1
- package/dist/configurators/codebuddy.d.ts.map +1 -1
- package/dist/configurators/codebuddy.js +3 -3
- package/dist/configurators/codebuddy.js.map +1 -1
- package/dist/configurators/codex.d.ts.map +1 -1
- package/dist/configurators/codex.js +5 -13
- package/dist/configurators/codex.js.map +1 -1
- package/dist/configurators/copilot.d.ts.map +1 -1
- package/dist/configurators/copilot.js +5 -19
- package/dist/configurators/copilot.js.map +1 -1
- package/dist/configurators/cursor.d.ts.map +1 -1
- package/dist/configurators/cursor.js +3 -3
- package/dist/configurators/cursor.js.map +1 -1
- package/dist/configurators/droid.d.ts.map +1 -1
- package/dist/configurators/droid.js +3 -3
- package/dist/configurators/droid.js.map +1 -1
- package/dist/configurators/gemini.d.ts.map +1 -1
- package/dist/configurators/gemini.js +3 -5
- package/dist/configurators/gemini.js.map +1 -1
- package/dist/configurators/index.d.ts.map +1 -1
- package/dist/configurators/index.js +37 -49
- package/dist/configurators/index.js.map +1 -1
- package/dist/configurators/kilo.d.ts.map +1 -1
- package/dist/configurators/kilo.js +2 -8
- package/dist/configurators/kilo.js.map +1 -1
- package/dist/configurators/kiro.d.ts.map +1 -1
- package/dist/configurators/kiro.js +3 -3
- package/dist/configurators/kiro.js.map +1 -1
- package/dist/configurators/opencode.d.ts.map +1 -1
- package/dist/configurators/opencode.js +7 -4
- package/dist/configurators/opencode.js.map +1 -1
- package/dist/configurators/pi.d.ts +3 -0
- package/dist/configurators/pi.d.ts.map +1 -0
- package/dist/configurators/pi.js +44 -0
- package/dist/configurators/pi.js.map +1 -0
- package/dist/configurators/qoder.d.ts.map +1 -1
- package/dist/configurators/qoder.js +3 -5
- package/dist/configurators/qoder.js.map +1 -1
- package/dist/configurators/shared.d.ts +28 -6
- package/dist/configurators/shared.d.ts.map +1 -1
- package/dist/configurators/shared.js +47 -15
- package/dist/configurators/shared.js.map +1 -1
- package/dist/configurators/windsurf.d.ts.map +1 -1
- package/dist/configurators/windsurf.js +2 -8
- package/dist/configurators/windsurf.js.map +1 -1
- package/dist/constants/paths.d.ts +2 -0
- package/dist/constants/paths.d.ts.map +1 -1
- package/dist/constants/paths.js +2 -0
- package/dist/constants/paths.js.map +1 -1
- package/dist/migrations/manifests/0.5.0-beta.0.json +2 -0
- package/dist/migrations/manifests/0.5.0-beta.10.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.11.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.12.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.13.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.14.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.15.json +116 -0
- package/dist/migrations/manifests/0.5.0-beta.16.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.17.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.18.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.19.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.5.json +2 -0
- package/dist/migrations/manifests/0.5.0-rc.0.json +9 -0
- package/dist/templates/claude/agents/trellis-research.md +1 -1
- package/dist/templates/claude/settings.json +0 -4
- package/dist/templates/codebuddy/agents/trellis-research.md +1 -1
- package/dist/templates/codex/agents/trellis-research.toml +3 -2
- package/dist/templates/codex/hooks/session-start.py +126 -26
- package/dist/templates/codex/skills/finish-work/SKILL.md +41 -109
- package/dist/templates/codex/skills/start/SKILL.md +12 -9
- package/dist/templates/common/bundled-skills/trellis-meta/SKILL.md +73 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/add-project-local-conventions.md +83 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-agents.md +54 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-context-loading.md +81 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-hooks.md +57 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-skills-or-commands.md +78 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-spec-structure.md +83 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-task-lifecycle.md +90 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-workflow.md +64 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/overview.md +55 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/context-injection.md +68 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/generated-files.md +80 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/overview.md +51 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/spec-system.md +102 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/task-system.md +101 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/workflow.md +75 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/workspace-memory.md +71 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/agents.md +79 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/hooks-and-settings.md +69 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/overview.md +59 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/platform-map.md +74 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/skills-and-commands.md +83 -0
- package/dist/templates/common/commands/continue.md +9 -5
- package/dist/templates/common/commands/finish-work.md +34 -10
- package/dist/templates/common/index.d.ts +22 -2
- package/dist/templates/common/index.d.ts.map +1 -1
- package/dist/templates/common/index.js +53 -4
- package/dist/templates/common/index.js.map +1 -1
- package/dist/templates/common/skills/brainstorm.md +3 -0
- package/dist/templates/copilot/hooks/session-start.py +127 -30
- package/dist/templates/copilot/prompts/finish-work.prompt.md +44 -112
- package/dist/templates/copilot/prompts/start.prompt.md +12 -9
- package/dist/templates/cursor/agents/trellis-check.md +1 -1
- package/dist/templates/cursor/agents/trellis-implement.md +1 -1
- package/dist/templates/cursor/agents/trellis-research.md +2 -2
- package/dist/templates/cursor/hooks.json +7 -1
- package/dist/templates/droid/droids/trellis-research.md +1 -1
- package/dist/templates/extract.d.ts +6 -0
- package/dist/templates/extract.d.ts.map +1 -1
- package/dist/templates/extract.js +14 -0
- package/dist/templates/extract.js.map +1 -1
- package/dist/templates/gemini/agents/trellis-research.md +1 -1
- package/dist/templates/kiro/agents/trellis-research.json +1 -1
- package/dist/templates/markdown/agents.md +19 -12
- package/dist/templates/markdown/gitignore.txt +3 -0
- package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +24 -0
- package/dist/templates/opencode/agents/trellis-check.md +1 -1
- package/dist/templates/opencode/agents/trellis-implement.md +7 -4
- package/dist/templates/opencode/agents/trellis-research.md +2 -2
- package/dist/templates/opencode/lib/trellis-context.js +100 -13
- package/dist/templates/opencode/plugins/inject-subagent-context.js +70 -5
- package/dist/templates/opencode/plugins/inject-workflow-state.js +38 -58
- package/dist/templates/opencode/plugins/session-start.js +76 -31
- package/dist/templates/pi/agents/trellis-check.md +28 -0
- package/dist/templates/pi/agents/trellis-implement.md +33 -0
- package/dist/templates/pi/agents/trellis-research.md +25 -0
- package/dist/templates/pi/extensions/trellis/index.ts.txt +997 -0
- package/dist/templates/pi/index.d.ts +5 -0
- package/dist/templates/pi/index.d.ts.map +1 -0
- package/dist/templates/pi/index.js +12 -0
- package/dist/templates/pi/index.js.map +1 -0
- package/dist/templates/pi/settings.json +12 -0
- package/dist/templates/qoder/agents/trellis-research.md +1 -1
- package/dist/templates/shared-hooks/index.d.ts +31 -0
- package/dist/templates/shared-hooks/index.d.ts.map +1 -1
- package/dist/templates/shared-hooks/index.js +59 -0
- package/dist/templates/shared-hooks/index.js.map +1 -1
- package/dist/templates/shared-hooks/inject-shell-session-context.py +180 -0
- package/dist/templates/shared-hooks/inject-subagent-context.py +156 -27
- package/dist/templates/shared-hooks/inject-workflow-state.py +85 -105
- package/dist/templates/shared-hooks/session-start.py +222 -36
- package/dist/templates/trellis/gitignore.txt +3 -0
- package/dist/templates/trellis/index.d.ts +1 -0
- package/dist/templates/trellis/index.d.ts.map +1 -1
- package/dist/templates/trellis/index.js +2 -0
- package/dist/templates/trellis/index.js.map +1 -1
- package/dist/templates/trellis/scripts/common/__init__.py +8 -0
- package/dist/templates/trellis/scripts/common/active_task.py +593 -0
- package/dist/templates/trellis/scripts/common/cli_adapter.py +72 -14
- package/dist/templates/trellis/scripts/common/paths.py +61 -58
- package/dist/templates/trellis/scripts/common/session_context.py +12 -0
- package/dist/templates/trellis/scripts/common/task_context.py +27 -194
- package/dist/templates/trellis/scripts/common/task_store.py +102 -26
- package/dist/templates/trellis/scripts/common/tasks.py +4 -1
- package/dist/templates/trellis/scripts/common/workflow_phase.py +15 -3
- package/dist/templates/trellis/scripts/task.py +99 -34
- package/dist/templates/trellis/workflow.md +332 -69
- package/dist/types/ai-tools.d.ts +12 -3
- package/dist/types/ai-tools.d.ts.map +1 -1
- package/dist/types/ai-tools.js +29 -0
- package/dist/types/ai-tools.js.map +1 -1
- package/dist/utils/file-writer.d.ts.map +1 -1
- package/dist/utils/file-writer.js +7 -2
- package/dist/utils/file-writer.js.map +1 -1
- package/dist/utils/posix.d.ts +13 -0
- package/dist/utils/posix.d.ts.map +1 -0
- package/dist/utils/posix.js +15 -0
- package/dist/utils/posix.js.map +1 -0
- package/dist/utils/template-fetcher.d.ts +22 -6
- package/dist/utils/template-fetcher.d.ts.map +1 -1
- package/dist/utils/template-fetcher.js +405 -27
- package/dist/utils/template-fetcher.js.map +1 -1
- package/dist/utils/template-hash.d.ts +22 -3
- package/dist/utils/template-hash.d.ts.map +1 -1
- package/dist/utils/template-hash.js +99 -19
- package/dist/utils/template-hash.js.map +1 -1
- package/package.json +7 -7
- package/dist/templates/shared-hooks/statusline.py +0 -218
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
CLI Adapter for Multi-Platform Support.
|
|
3
3
|
|
|
4
|
-
Abstracts differences between Claude Code, OpenCode, Cursor, iFlow, Codex, Kilo, Kiro Code, Gemini CLI, Antigravity, Windsurf, Qoder, CodeBuddy, GitHub Copilot,
|
|
4
|
+
Abstracts differences between Claude Code, OpenCode, Cursor, iFlow, Codex, Kilo, Kiro Code, Gemini CLI, Antigravity, Windsurf, Qoder, CodeBuddy, GitHub Copilot, Factory Droid, and Pi Agent interfaces.
|
|
5
5
|
|
|
6
6
|
Supported platforms:
|
|
7
7
|
- claude: Claude Code (default)
|
|
@@ -18,6 +18,7 @@ Supported platforms:
|
|
|
18
18
|
- codebuddy: CodeBuddy
|
|
19
19
|
- copilot: GitHub Copilot (VS Code)
|
|
20
20
|
- droid: Factory Droid (commands-based)
|
|
21
|
+
- pi: Pi Agent (extension-backed)
|
|
21
22
|
|
|
22
23
|
Usage:
|
|
23
24
|
from common.cli_adapter import CLIAdapter
|
|
@@ -51,6 +52,7 @@ Platform = Literal[
|
|
|
51
52
|
"codebuddy",
|
|
52
53
|
"copilot",
|
|
53
54
|
"droid",
|
|
55
|
+
"pi",
|
|
54
56
|
]
|
|
55
57
|
|
|
56
58
|
|
|
@@ -95,7 +97,7 @@ class CLIAdapter:
|
|
|
95
97
|
"""Get platform-specific config directory name.
|
|
96
98
|
|
|
97
99
|
Returns:
|
|
98
|
-
Directory name ('.claude', '.opencode', '.cursor', '.iflow', '.codex', '.kilocode', '.kiro', '.gemini', '.agent', '.windsurf', '.qoder', or '.
|
|
100
|
+
Directory name ('.claude', '.opencode', '.cursor', '.iflow', '.codex', '.kilocode', '.kiro', '.gemini', '.agent', '.windsurf', '.qoder', '.codebuddy', '.github/copilot', '.factory', or '.pi')
|
|
99
101
|
"""
|
|
100
102
|
if self.platform == "opencode":
|
|
101
103
|
return ".opencode"
|
|
@@ -123,6 +125,8 @@ class CLIAdapter:
|
|
|
123
125
|
return ".github/copilot"
|
|
124
126
|
elif self.platform == "droid":
|
|
125
127
|
return ".factory"
|
|
128
|
+
elif self.platform == "pi":
|
|
129
|
+
return ".pi"
|
|
126
130
|
else:
|
|
127
131
|
return ".claude"
|
|
128
132
|
|
|
@@ -133,7 +137,7 @@ class CLIAdapter:
|
|
|
133
137
|
project_root: Project root directory
|
|
134
138
|
|
|
135
139
|
Returns:
|
|
136
|
-
Path to config directory (.claude, .opencode, .cursor, .iflow, .codex, .kilocode, .kiro, .gemini, .agent, .windsurf, .qoder, or .
|
|
140
|
+
Path to config directory (.claude, .opencode, .cursor, .iflow, .codex, .kilocode, .kiro, .gemini, .agent, .windsurf, .qoder, .codebuddy, .github/copilot, .factory, or .pi)
|
|
137
141
|
"""
|
|
138
142
|
return project_root / self.config_dir_name
|
|
139
143
|
|
|
@@ -167,8 +171,20 @@ class CLIAdapter:
|
|
|
167
171
|
Antigravity uses workflow directory: .agent/workflows/<name>.md
|
|
168
172
|
Windsurf uses workflow directory: .windsurf/workflows/trellis-<name>.md
|
|
169
173
|
Copilot uses prompt files: .github/prompts/<name>.prompt.md
|
|
174
|
+
Pi uses prompt templates: .pi/prompts/trellis-<name>.md
|
|
170
175
|
Claude/OpenCode use subdirectory: .claude/commands/trellis/<name>.md
|
|
171
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
|
+
|
|
172
188
|
if self.platform == "windsurf":
|
|
173
189
|
workflow_dir = self.get_config_dir(project_root) / "workflows"
|
|
174
190
|
if not parts:
|
|
@@ -222,19 +238,22 @@ class CLIAdapter:
|
|
|
222
238
|
|
|
223
239
|
Note:
|
|
224
240
|
Cursor: .cursor/commands/trellis-<name>.md
|
|
225
|
-
Codex: .agents/skills
|
|
226
|
-
Kiro: .kiro/skills
|
|
241
|
+
Codex: .agents/skills/trellis-<name>/SKILL.md
|
|
242
|
+
Kiro: .kiro/skills/trellis-<name>/SKILL.md
|
|
227
243
|
Gemini: .gemini/commands/trellis/<name>.toml
|
|
228
244
|
Antigravity: .agent/workflows/<name>.md
|
|
229
245
|
Windsurf: .windsurf/workflows/trellis-<name>.md
|
|
246
|
+
Pi: .pi/prompts/trellis-<name>.md
|
|
230
247
|
Others: .{platform}/commands/trellis/<name>.md
|
|
231
248
|
"""
|
|
232
249
|
if self.platform == "cursor":
|
|
233
250
|
return f".cursor/commands/trellis-{name}.md"
|
|
234
251
|
elif self.platform == "codex":
|
|
235
|
-
|
|
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"
|
|
236
255
|
elif self.platform == "kiro":
|
|
237
|
-
return f".kiro/skills/{name}/SKILL.md"
|
|
256
|
+
return f".kiro/skills/trellis-{name}/SKILL.md"
|
|
238
257
|
elif self.platform == "gemini":
|
|
239
258
|
return f".gemini/commands/trellis/{name}.toml"
|
|
240
259
|
elif self.platform == "antigravity":
|
|
@@ -247,6 +266,8 @@ class CLIAdapter:
|
|
|
247
266
|
return f".github/prompts/{name}.prompt.md"
|
|
248
267
|
elif self.platform == "droid":
|
|
249
268
|
return f".factory/commands/trellis/{name}.md"
|
|
269
|
+
elif self.platform == "pi":
|
|
270
|
+
return f".pi/prompts/trellis-{name}.md"
|
|
250
271
|
else:
|
|
251
272
|
return f"{self.config_dir_name}/commands/trellis/{name}.md"
|
|
252
273
|
|
|
@@ -282,6 +303,8 @@ class CLIAdapter:
|
|
|
282
303
|
return {}
|
|
283
304
|
elif self.platform == "droid":
|
|
284
305
|
return {}
|
|
306
|
+
elif self.platform == "pi":
|
|
307
|
+
return {}
|
|
285
308
|
else:
|
|
286
309
|
return {"CLAUDE_NON_INTERACTIVE": "1"}
|
|
287
310
|
|
|
@@ -365,6 +388,8 @@ class CLIAdapter:
|
|
|
365
388
|
raise ValueError(
|
|
366
389
|
"Factory Droid CLI agent run is not yet supported."
|
|
367
390
|
)
|
|
391
|
+
elif self.platform == "pi":
|
|
392
|
+
cmd = ["pi", "-p", prompt]
|
|
368
393
|
|
|
369
394
|
else: # claude
|
|
370
395
|
cmd = ["claude", "-p"]
|
|
@@ -429,6 +454,8 @@ class CLIAdapter:
|
|
|
429
454
|
raise ValueError(
|
|
430
455
|
"Factory Droid CLI resume is not yet supported."
|
|
431
456
|
)
|
|
457
|
+
elif self.platform == "pi":
|
|
458
|
+
return ["pi", "-c", session_id]
|
|
432
459
|
else:
|
|
433
460
|
return ["claude", "--resume", session_id]
|
|
434
461
|
|
|
@@ -501,6 +528,8 @@ class CLIAdapter:
|
|
|
501
528
|
return "copilot"
|
|
502
529
|
elif self.platform == "droid":
|
|
503
530
|
return "droid"
|
|
531
|
+
elif self.platform == "pi":
|
|
532
|
+
return "pi"
|
|
504
533
|
else:
|
|
505
534
|
return "claude"
|
|
506
535
|
|
|
@@ -511,7 +540,7 @@ class CLIAdapter:
|
|
|
511
540
|
Claude Code, OpenCode, iFlow, and Codex support CLI agent execution.
|
|
512
541
|
Cursor is IDE-only and doesn't support CLI agents.
|
|
513
542
|
"""
|
|
514
|
-
return self.platform in ("claude", "opencode", "iflow", "codex")
|
|
543
|
+
return self.platform in ("claude", "opencode", "iflow", "codex", "pi")
|
|
515
544
|
|
|
516
545
|
@property
|
|
517
546
|
def requires_agent_definition_file(self) -> bool:
|
|
@@ -565,7 +594,7 @@ def get_cli_adapter(platform: str = "claude") -> CLIAdapter:
|
|
|
565
594
|
"""Get CLI adapter for the specified platform.
|
|
566
595
|
|
|
567
596
|
Args:
|
|
568
|
-
platform: Platform name ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'windsurf', 'qoder', or '
|
|
597
|
+
platform: Platform name ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'windsurf', 'qoder', 'codebuddy', 'copilot', 'droid', or 'pi')
|
|
569
598
|
|
|
570
599
|
Returns:
|
|
571
600
|
CLIAdapter instance
|
|
@@ -588,9 +617,10 @@ def get_cli_adapter(platform: str = "claude") -> CLIAdapter:
|
|
|
588
617
|
"codebuddy",
|
|
589
618
|
"copilot",
|
|
590
619
|
"droid",
|
|
620
|
+
"pi",
|
|
591
621
|
):
|
|
592
622
|
raise ValueError(
|
|
593
|
-
f"Unsupported platform: {platform} (must be 'claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'windsurf', 'qoder', 'codebuddy', 'copilot', or '
|
|
623
|
+
f"Unsupported platform: {platform} (must be 'claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'windsurf', 'qoder', 'codebuddy', 'copilot', 'droid', or 'pi')"
|
|
594
624
|
)
|
|
595
625
|
|
|
596
626
|
return CLIAdapter(platform=platform) # type: ignore
|
|
@@ -601,7 +631,6 @@ _ALL_PLATFORM_CONFIG_DIRS = (
|
|
|
601
631
|
".cursor",
|
|
602
632
|
".iflow",
|
|
603
633
|
".opencode",
|
|
604
|
-
".agents",
|
|
605
634
|
".codex",
|
|
606
635
|
".kilocode",
|
|
607
636
|
".kiro",
|
|
@@ -612,8 +641,13 @@ _ALL_PLATFORM_CONFIG_DIRS = (
|
|
|
612
641
|
".codebuddy",
|
|
613
642
|
".github/copilot",
|
|
614
643
|
".factory",
|
|
644
|
+
".pi",
|
|
615
645
|
)
|
|
616
|
-
"""
|
|
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."""
|
|
617
651
|
|
|
618
652
|
|
|
619
653
|
def _has_other_platform_dir(project_root: Path, exclude: set[str]) -> bool:
|
|
@@ -641,13 +675,14 @@ def detect_platform(project_root: Path) -> Platform:
|
|
|
641
675
|
10. .windsurf/workflows exists and no other platform dirs → windsurf
|
|
642
676
|
11. .codebuddy directory exists → codebuddy
|
|
643
677
|
12. .qoder directory exists → qoder
|
|
644
|
-
13.
|
|
678
|
+
13. .pi directory exists → pi
|
|
679
|
+
14. Default → claude
|
|
645
680
|
|
|
646
681
|
Args:
|
|
647
682
|
project_root: Project root directory
|
|
648
683
|
|
|
649
684
|
Returns:
|
|
650
|
-
Detected platform ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'windsurf', 'qoder', 'codebuddy', or default 'claude')
|
|
685
|
+
Detected platform ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'windsurf', 'qoder', 'codebuddy', 'copilot', 'droid', 'pi', or default 'claude')
|
|
651
686
|
"""
|
|
652
687
|
import os
|
|
653
688
|
|
|
@@ -668,6 +703,7 @@ def detect_platform(project_root: Path) -> Platform:
|
|
|
668
703
|
"codebuddy",
|
|
669
704
|
"copilot",
|
|
670
705
|
"droid",
|
|
706
|
+
"pi",
|
|
671
707
|
):
|
|
672
708
|
return env_platform # type: ignore
|
|
673
709
|
|
|
@@ -737,6 +773,28 @@ def detect_platform(project_root: Path) -> Platform:
|
|
|
737
773
|
if (project_root / ".factory").is_dir():
|
|
738
774
|
return "droid"
|
|
739
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
|
+
|
|
740
798
|
return "claude"
|
|
741
799
|
|
|
742
800
|
|
|
@@ -207,22 +207,8 @@ def count_lines(file_path: Path) -> int:
|
|
|
207
207
|
# Current Task Management
|
|
208
208
|
# =============================================================================
|
|
209
209
|
|
|
210
|
-
def _get_current_task_file(repo_root: Path | None = None) -> Path:
|
|
211
|
-
"""Get .current-task file path.
|
|
212
|
-
|
|
213
|
-
Args:
|
|
214
|
-
repo_root: Repository root path. Defaults to auto-detected.
|
|
215
|
-
|
|
216
|
-
Returns:
|
|
217
|
-
Path to .current-task file.
|
|
218
|
-
"""
|
|
219
|
-
if repo_root is None:
|
|
220
|
-
repo_root = get_repo_root()
|
|
221
|
-
return repo_root / DIR_WORKFLOW / FILE_CURRENT_TASK
|
|
222
|
-
|
|
223
|
-
|
|
224
210
|
def normalize_task_ref(task_ref: str) -> str:
|
|
225
|
-
"""Normalize a task ref for stable storage
|
|
211
|
+
"""Normalize a task ref for stable runtime storage.
|
|
226
212
|
|
|
227
213
|
Stored refs should prefer repo-relative POSIX paths like
|
|
228
214
|
`.trellis/tasks/03-27-my-task`, even on Windows. Absolute paths are preserved
|
|
@@ -247,7 +233,7 @@ def normalize_task_ref(task_ref: str) -> str:
|
|
|
247
233
|
|
|
248
234
|
|
|
249
235
|
def resolve_task_ref(task_ref: str, repo_root: Path | None = None) -> Path | None:
|
|
250
|
-
"""Resolve a task ref
|
|
236
|
+
"""Resolve a task ref to an absolute task directory path."""
|
|
251
237
|
if repo_root is None:
|
|
252
238
|
repo_root = get_repo_root()
|
|
253
239
|
|
|
@@ -265,7 +251,11 @@ def resolve_task_ref(task_ref: str, repo_root: Path | None = None) -> Path | Non
|
|
|
265
251
|
return repo_root / DIR_WORKFLOW / DIR_TASKS / path_obj
|
|
266
252
|
|
|
267
253
|
|
|
268
|
-
def get_current_task(
|
|
254
|
+
def get_current_task(
|
|
255
|
+
repo_root: Path | None = None,
|
|
256
|
+
platform_input: dict | None = None,
|
|
257
|
+
platform: str | None = None,
|
|
258
|
+
) -> str | None:
|
|
269
259
|
"""Get current task directory path (relative to repo_root).
|
|
270
260
|
|
|
271
261
|
Args:
|
|
@@ -274,19 +264,19 @@ def get_current_task(repo_root: Path | None = None) -> str | None:
|
|
|
274
264
|
Returns:
|
|
275
265
|
Relative path to current task directory or None.
|
|
276
266
|
"""
|
|
277
|
-
|
|
267
|
+
if repo_root is None:
|
|
268
|
+
repo_root = get_repo_root()
|
|
278
269
|
|
|
279
|
-
|
|
280
|
-
return None
|
|
270
|
+
from .active_task import resolve_active_task
|
|
281
271
|
|
|
282
|
-
|
|
283
|
-
content = current_file.read_text(encoding="utf-8").strip()
|
|
284
|
-
return normalize_task_ref(content) if content else None
|
|
285
|
-
except (OSError, IOError):
|
|
286
|
-
return None
|
|
272
|
+
return resolve_active_task(repo_root, platform_input, platform).task_path
|
|
287
273
|
|
|
288
274
|
|
|
289
|
-
def get_current_task_abs(
|
|
275
|
+
def get_current_task_abs(
|
|
276
|
+
repo_root: Path | None = None,
|
|
277
|
+
platform_input: dict | None = None,
|
|
278
|
+
platform: str | None = None,
|
|
279
|
+
) -> Path | None:
|
|
290
280
|
"""Get current task directory absolute path.
|
|
291
281
|
|
|
292
282
|
Args:
|
|
@@ -298,14 +288,33 @@ def get_current_task_abs(repo_root: Path | None = None) -> Path | None:
|
|
|
298
288
|
if repo_root is None:
|
|
299
289
|
repo_root = get_repo_root()
|
|
300
290
|
|
|
301
|
-
relative = get_current_task(repo_root)
|
|
291
|
+
relative = get_current_task(repo_root, platform_input, platform)
|
|
302
292
|
if relative:
|
|
303
293
|
return resolve_task_ref(relative, repo_root)
|
|
304
294
|
return None
|
|
305
295
|
|
|
306
296
|
|
|
307
|
-
def
|
|
308
|
-
|
|
297
|
+
def get_current_task_source(
|
|
298
|
+
repo_root: Path | None = None,
|
|
299
|
+
platform_input: dict | None = None,
|
|
300
|
+
platform: str | None = None,
|
|
301
|
+
) -> tuple[str, str | None, str | None]:
|
|
302
|
+
"""Get active task source as (`source`, `context_key`, `task_path`)."""
|
|
303
|
+
if repo_root is None:
|
|
304
|
+
repo_root = get_repo_root()
|
|
305
|
+
|
|
306
|
+
from .active_task import get_current_task_source as _get_source
|
|
307
|
+
|
|
308
|
+
return _get_source(repo_root, platform_input, platform)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def set_current_task(
|
|
312
|
+
task_path: str,
|
|
313
|
+
repo_root: Path | None = None,
|
|
314
|
+
platform_input: dict | None = None,
|
|
315
|
+
platform: str | None = None,
|
|
316
|
+
) -> bool:
|
|
317
|
+
"""Set current task in session scope.
|
|
309
318
|
|
|
310
319
|
Args:
|
|
311
320
|
task_path: Task directory path (relative to repo_root).
|
|
@@ -317,31 +326,22 @@ def set_current_task(task_path: str, repo_root: Path | None = None) -> bool:
|
|
|
317
326
|
if repo_root is None:
|
|
318
327
|
repo_root = get_repo_root()
|
|
319
328
|
|
|
320
|
-
|
|
321
|
-
if not normalized:
|
|
322
|
-
return False
|
|
329
|
+
from .active_task import set_active_task
|
|
323
330
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
331
|
+
return set_active_task(
|
|
332
|
+
task_path,
|
|
333
|
+
repo_root,
|
|
334
|
+
platform_input=platform_input,
|
|
335
|
+
platform=platform,
|
|
336
|
+
) is not None
|
|
328
337
|
|
|
329
|
-
try:
|
|
330
|
-
normalized = full_path.relative_to(repo_root).as_posix()
|
|
331
|
-
except ValueError:
|
|
332
|
-
normalized = str(full_path)
|
|
333
338
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
return False
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
def clear_current_task(repo_root: Path | None = None) -> bool:
|
|
344
|
-
"""Clear current task.
|
|
339
|
+
def clear_current_task(
|
|
340
|
+
repo_root: Path | None = None,
|
|
341
|
+
platform_input: dict | None = None,
|
|
342
|
+
platform: str | None = None,
|
|
343
|
+
) -> bool:
|
|
344
|
+
"""Clear current task in session scope.
|
|
345
345
|
|
|
346
346
|
Args:
|
|
347
347
|
repo_root: Repository root path. Defaults to auto-detected.
|
|
@@ -349,14 +349,17 @@ def clear_current_task(repo_root: Path | None = None) -> bool:
|
|
|
349
349
|
Returns:
|
|
350
350
|
True on success.
|
|
351
351
|
"""
|
|
352
|
-
|
|
352
|
+
if repo_root is None:
|
|
353
|
+
repo_root = get_repo_root()
|
|
353
354
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
355
|
+
from .active_task import clear_active_task
|
|
356
|
+
|
|
357
|
+
clear_active_task(
|
|
358
|
+
repo_root,
|
|
359
|
+
platform_input=platform_input,
|
|
360
|
+
platform=platform,
|
|
361
|
+
)
|
|
362
|
+
return True
|
|
360
363
|
|
|
361
364
|
|
|
362
365
|
def has_current_task(repo_root: Path | None = None) -> bool:
|
|
@@ -29,6 +29,7 @@ from .paths import (
|
|
|
29
29
|
count_lines,
|
|
30
30
|
get_active_journal_file,
|
|
31
31
|
get_current_task,
|
|
32
|
+
get_current_task_source,
|
|
32
33
|
get_developer,
|
|
33
34
|
get_repo_root,
|
|
34
35
|
get_tasks_dir,
|
|
@@ -279,7 +280,11 @@ def get_context_text(repo_root: Path | None = None) -> str:
|
|
|
279
280
|
current_task = get_current_task(repo_root)
|
|
280
281
|
if current_task:
|
|
281
282
|
current_task_dir = repo_root / current_task
|
|
283
|
+
source_type, context_key, _ = get_current_task_source(repo_root)
|
|
282
284
|
lines.append(f"Path: {current_task}")
|
|
285
|
+
lines.append(
|
|
286
|
+
f"Source: {source_type}" + (f":{context_key}" if context_key else "")
|
|
287
|
+
)
|
|
283
288
|
|
|
284
289
|
ct = load_task(current_task_dir)
|
|
285
290
|
if ct:
|
|
@@ -429,12 +434,15 @@ def get_context_record_json(repo_root: Path | None = None) -> dict:
|
|
|
429
434
|
current_task_info = None
|
|
430
435
|
current_task = get_current_task(repo_root)
|
|
431
436
|
if current_task:
|
|
437
|
+
source_type, context_key, _ = get_current_task_source(repo_root)
|
|
432
438
|
ct = load_task(repo_root / current_task)
|
|
433
439
|
if ct:
|
|
434
440
|
current_task_info = {
|
|
435
441
|
"path": current_task,
|
|
436
442
|
"name": ct.name,
|
|
437
443
|
"status": ct.status,
|
|
444
|
+
"source": source_type,
|
|
445
|
+
"contextKey": context_key,
|
|
438
446
|
}
|
|
439
447
|
|
|
440
448
|
# Package git repos
|
|
@@ -539,7 +547,11 @@ def get_context_text_record(repo_root: Path | None = None) -> str:
|
|
|
539
547
|
lines.append("## CURRENT TASK")
|
|
540
548
|
current_task = get_current_task(repo_root)
|
|
541
549
|
if current_task:
|
|
550
|
+
source_type, context_key, _ = get_current_task_source(repo_root)
|
|
542
551
|
lines.append(f"Path: {current_task}")
|
|
552
|
+
lines.append(
|
|
553
|
+
f"Source: {source_type}" + (f":{context_key}" if context_key else "")
|
|
554
|
+
)
|
|
543
555
|
ct = load_task(repo_root / current_task)
|
|
544
556
|
if ct:
|
|
545
557
|
lines.append(f"Name: {ct.name}")
|