@fifine/aim-studio 0.0.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/LICENSE +21 -0
- package/README.md +159 -0
- package/bin/aim.js +3 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +89 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/commands/init.d.ts +13 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +513 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/update.d.ts +27 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +1275 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/configurators/claude.d.ts +32 -0
- package/dist/configurators/claude.d.ts.map +1 -0
- package/dist/configurators/claude.js +98 -0
- package/dist/configurators/claude.js.map +1 -0
- package/dist/configurators/index.d.ts +51 -0
- package/dist/configurators/index.d.ts.map +1 -0
- package/dist/configurators/index.js +113 -0
- package/dist/configurators/index.js.map +1 -0
- package/dist/configurators/shared.d.ts +12 -0
- package/dist/configurators/shared.d.ts.map +1 -0
- package/dist/configurators/shared.js +21 -0
- package/dist/configurators/shared.js.map +1 -0
- package/dist/configurators/workflow.d.ts +28 -0
- package/dist/configurators/workflow.d.ts.map +1 -0
- package/dist/configurators/workflow.js +147 -0
- package/dist/configurators/workflow.js.map +1 -0
- package/dist/constants/paths.d.ts +68 -0
- package/dist/constants/paths.d.ts.map +1 -0
- package/dist/constants/paths.js +77 -0
- package/dist/constants/paths.js.map +1 -0
- package/dist/constants/version.d.ts +9 -0
- package/dist/constants/version.d.ts.map +1 -0
- package/dist/constants/version.js +15 -0
- package/dist/constants/version.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/migrations/index.d.ts +54 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +160 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrations/manifests/0.0.1.json +9 -0
- package/dist/migrations/manifests/0.1.9.json +30 -0
- package/dist/migrations/manifests/0.2.0.json +49 -0
- package/dist/migrations/manifests/0.2.12.json +9 -0
- package/dist/migrations/manifests/0.2.13.json +9 -0
- package/dist/migrations/manifests/0.2.14.json +175 -0
- package/dist/migrations/manifests/0.2.15.json +33 -0
- package/dist/migrations/manifests/0.3.0-beta.0.json +278 -0
- package/dist/migrations/manifests/0.3.0-beta.1.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.10.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.11.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.12.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.13.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.14.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.15.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.16.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.2.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.3.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.4.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.5.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.6.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.7.json +11 -0
- package/dist/migrations/manifests/0.3.0-beta.8.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.9.json +9 -0
- package/dist/migrations/manifests/0.3.0-rc.0.json +9 -0
- package/dist/migrations/manifests/0.3.0-rc.1.json +9 -0
- package/dist/migrations/manifests/0.3.0-rc.2.json +9 -0
- package/dist/templates/CLAUDE.md +71 -0
- package/dist/templates/aim/gitignore.txt +29 -0
- package/dist/templates/aim/index.d.ts +49 -0
- package/dist/templates/aim/index.d.ts.map +1 -0
- package/dist/templates/aim/index.js +92 -0
- package/dist/templates/aim/index.js.map +1 -0
- package/dist/templates/aim/scripts/__init__.py +5 -0
- package/dist/templates/aim/scripts/add_session.py +392 -0
- package/dist/templates/aim/scripts/common/__init__.py +80 -0
- package/dist/templates/aim/scripts/common/cli_adapter.py +435 -0
- package/dist/templates/aim/scripts/common/developer.py +190 -0
- package/dist/templates/aim/scripts/common/git_context.py +383 -0
- package/dist/templates/aim/scripts/common/paths.py +347 -0
- package/dist/templates/aim/scripts/common/phase.py +253 -0
- package/dist/templates/aim/scripts/common/registry.py +366 -0
- package/dist/templates/aim/scripts/common/task_queue.py +255 -0
- package/dist/templates/aim/scripts/common/task_utils.py +178 -0
- package/dist/templates/aim/scripts/common/worktree.py +219 -0
- package/dist/templates/aim/scripts/create_bootstrap.py +290 -0
- package/dist/templates/aim/scripts/get_context.py +16 -0
- package/dist/templates/aim/scripts/get_developer.py +26 -0
- package/dist/templates/aim/scripts/init_developer.py +51 -0
- package/dist/templates/aim/scripts/multi_agent/__init__.py +5 -0
- package/dist/templates/aim/scripts/multi_agent/cleanup.py +403 -0
- package/dist/templates/aim/scripts/multi_agent/create_pr.py +329 -0
- package/dist/templates/aim/scripts/multi_agent/plan.py +233 -0
- package/dist/templates/aim/scripts/multi_agent/start.py +461 -0
- package/dist/templates/aim/scripts/multi_agent/status.py +817 -0
- package/dist/templates/aim/scripts/task.py +1068 -0
- package/dist/templates/aim/scripts-shell-archive/add-session.sh +384 -0
- package/dist/templates/aim/scripts-shell-archive/common/developer.sh +129 -0
- package/dist/templates/aim/scripts-shell-archive/common/git-context.sh +263 -0
- package/dist/templates/aim/scripts-shell-archive/common/paths.sh +208 -0
- package/dist/templates/aim/scripts-shell-archive/common/phase.sh +150 -0
- package/dist/templates/aim/scripts-shell-archive/common/registry.sh +247 -0
- package/dist/templates/aim/scripts-shell-archive/common/task-queue.sh +142 -0
- package/dist/templates/aim/scripts-shell-archive/common/task-utils.sh +151 -0
- package/dist/templates/aim/scripts-shell-archive/common/worktree.sh +128 -0
- package/dist/templates/aim/scripts-shell-archive/create-bootstrap.sh +299 -0
- package/dist/templates/aim/scripts-shell-archive/get-context.sh +7 -0
- package/dist/templates/aim/scripts-shell-archive/get-developer.sh +15 -0
- package/dist/templates/aim/scripts-shell-archive/init-developer.sh +34 -0
- package/dist/templates/aim/scripts-shell-archive/multi-agent/cleanup.sh +396 -0
- package/dist/templates/aim/scripts-shell-archive/multi-agent/create-pr.sh +241 -0
- package/dist/templates/aim/scripts-shell-archive/multi-agent/plan.sh +207 -0
- package/dist/templates/aim/scripts-shell-archive/multi-agent/start.sh +317 -0
- package/dist/templates/aim/scripts-shell-archive/multi-agent/status.sh +828 -0
- package/dist/templates/aim/scripts-shell-archive/task.sh +1204 -0
- package/dist/templates/aim/tasks/.gitkeep +0 -0
- package/dist/templates/aim/workflow.md +258 -0
- package/dist/templates/aim/worktree.yaml +47 -0
- package/dist/templates/claude/agents/check.md +122 -0
- package/dist/templates/claude/agents/debug.md +106 -0
- package/dist/templates/claude/agents/dispatch.md +230 -0
- package/dist/templates/claude/agents/implement.md +96 -0
- package/dist/templates/claude/agents/plan.md +396 -0
- package/dist/templates/claude/agents/research.md +120 -0
- package/dist/templates/claude/agents/story.md +53 -0
- package/dist/templates/claude/commands/aim/before-backend-dev.md +13 -0
- package/dist/templates/claude/commands/aim/before-frontend-dev.md +13 -0
- package/dist/templates/claude/commands/aim/break-loop.md +153 -0
- package/dist/templates/claude/commands/aim/check-backend.md +13 -0
- package/dist/templates/claude/commands/aim/check-cross-layer.md +153 -0
- package/dist/templates/claude/commands/aim/check-frontend.md +13 -0
- package/dist/templates/claude/commands/aim/check-story.md +59 -0
- package/dist/templates/claude/commands/aim/create-command.md +154 -0
- package/dist/templates/claude/commands/aim/export.md +187 -0
- package/dist/templates/claude/commands/aim/finish-work.md +104 -0
- package/dist/templates/claude/commands/aim/integrate-skill.md +219 -0
- package/dist/templates/claude/commands/aim/onboard.md +358 -0
- package/dist/templates/claude/commands/aim/parallel.md +217 -0
- package/dist/templates/claude/commands/aim/portrait.md +170 -0
- package/dist/templates/claude/commands/aim/record-session.md +92 -0
- package/dist/templates/claude/commands/aim/start.md +112 -0
- package/dist/templates/claude/commands/aim/story.md +140 -0
- package/dist/templates/claude/commands/aim/update-spec.md +285 -0
- package/dist/templates/claude/commands/aim/visualize.md +182 -0
- package/dist/templates/claude/commands/trellis/before-backend-dev.md +13 -0
- package/dist/templates/claude/commands/trellis/before-frontend-dev.md +13 -0
- package/dist/templates/claude/commands/trellis/break-loop.md +125 -0
- package/dist/templates/claude/commands/trellis/check-backend.md +13 -0
- package/dist/templates/claude/commands/trellis/check-cross-layer.md +153 -0
- package/dist/templates/claude/commands/trellis/check-frontend.md +13 -0
- package/dist/templates/claude/commands/trellis/create-command.md +154 -0
- package/dist/templates/claude/commands/trellis/finish-work.md +129 -0
- package/dist/templates/claude/commands/trellis/integrate-skill.md +219 -0
- package/dist/templates/claude/commands/trellis/onboard.md +358 -0
- package/dist/templates/claude/commands/trellis/parallel.md +193 -0
- package/dist/templates/claude/commands/trellis/record-session.md +62 -0
- package/dist/templates/claude/commands/trellis/start.md +280 -0
- package/dist/templates/claude/commands/trellis/update-spec.md +285 -0
- package/dist/templates/claude/hooks/inject-subagent-context.py +772 -0
- package/dist/templates/claude/hooks/ralph-loop.py +388 -0
- package/dist/templates/claude/hooks/session-start.py +142 -0
- package/dist/templates/claude/index.d.ts +54 -0
- package/dist/templates/claude/index.d.ts.map +1 -0
- package/dist/templates/claude/index.js +85 -0
- package/dist/templates/claude/index.js.map +1 -0
- package/dist/templates/claude/settings.json +41 -0
- package/dist/templates/extract.d.ts +68 -0
- package/dist/templates/extract.d.ts.map +1 -0
- package/dist/templates/extract.js +128 -0
- package/dist/templates/extract.js.map +1 -0
- package/dist/templates/markdown/agents.md +25 -0
- package/dist/templates/markdown/gitignore.txt +12 -0
- package/dist/templates/markdown/index.d.ts +32 -0
- package/dist/templates/markdown/index.d.ts.map +1 -0
- package/dist/templates/markdown/index.js +58 -0
- package/dist/templates/markdown/index.js.map +1 -0
- package/dist/templates/markdown/spec/backend/database-guidelines.md.txt +51 -0
- package/dist/templates/markdown/spec/backend/directory-structure.md.txt +54 -0
- package/dist/templates/markdown/spec/backend/error-handling.md.txt +51 -0
- package/dist/templates/markdown/spec/backend/index.md +40 -0
- package/dist/templates/markdown/spec/backend/index.md.txt +38 -0
- package/dist/templates/markdown/spec/backend/logging-guidelines.md.txt +51 -0
- package/dist/templates/markdown/spec/backend/quality-guidelines.md.txt +51 -0
- package/dist/templates/markdown/spec/backend/script-conventions.md +467 -0
- package/dist/templates/markdown/spec/frontend/component-guidelines.md.txt +59 -0
- package/dist/templates/markdown/spec/frontend/directory-structure.md.txt +54 -0
- package/dist/templates/markdown/spec/frontend/hook-guidelines.md.txt +51 -0
- package/dist/templates/markdown/spec/frontend/index.md.txt +39 -0
- package/dist/templates/markdown/spec/frontend/quality-guidelines.md.txt +51 -0
- package/dist/templates/markdown/spec/frontend/state-management.md.txt +51 -0
- package/dist/templates/markdown/spec/frontend/type-safety.md.txt +51 -0
- package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md +118 -0
- package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md.txt +92 -0
- package/dist/templates/markdown/spec/guides/cross-layer-thinking-guide.md.txt +94 -0
- package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md +394 -0
- package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +319 -0
- package/dist/templates/markdown/spec/guides/index.md.txt +89 -0
- package/dist/templates/markdown/spec/story/character.md.txt +95 -0
- package/dist/templates/markdown/spec/story/index.md.txt +31 -0
- package/dist/templates/markdown/spec/story/script.md.txt +313 -0
- package/dist/templates/markdown/spec/story/world.md.txt +92 -0
- package/dist/templates/markdown/workspace-index.md +123 -0
- package/dist/templates/markdown/worktree.yaml.txt +58 -0
- package/dist/templates/trellis/gitignore.txt +29 -0
- package/dist/templates/trellis/index.d.ts +49 -0
- package/dist/templates/trellis/index.d.ts.map +1 -0
- package/dist/templates/trellis/index.js +92 -0
- package/dist/templates/trellis/index.js.map +1 -0
- package/dist/templates/trellis/scripts/__init__.py +5 -0
- package/dist/templates/trellis/scripts/add_session.py +392 -0
- package/dist/templates/trellis/scripts/common/__init__.py +80 -0
- package/dist/templates/trellis/scripts/common/cli_adapter.py +435 -0
- package/dist/templates/trellis/scripts/common/developer.py +190 -0
- package/dist/templates/trellis/scripts/common/git_context.py +383 -0
- package/dist/templates/trellis/scripts/common/paths.py +347 -0
- package/dist/templates/trellis/scripts/common/phase.py +253 -0
- package/dist/templates/trellis/scripts/common/registry.py +366 -0
- package/dist/templates/trellis/scripts/common/task_queue.py +255 -0
- package/dist/templates/trellis/scripts/common/task_utils.py +178 -0
- package/dist/templates/trellis/scripts/common/worktree.py +219 -0
- package/dist/templates/trellis/scripts/create_bootstrap.py +290 -0
- package/dist/templates/trellis/scripts/get_context.py +16 -0
- package/dist/templates/trellis/scripts/get_developer.py +26 -0
- package/dist/templates/trellis/scripts/init_developer.py +51 -0
- package/dist/templates/trellis/scripts/multi_agent/__init__.py +5 -0
- package/dist/templates/trellis/scripts/multi_agent/cleanup.py +403 -0
- package/dist/templates/trellis/scripts/multi_agent/create_pr.py +329 -0
- package/dist/templates/trellis/scripts/multi_agent/plan.py +233 -0
- package/dist/templates/trellis/scripts/multi_agent/start.py +461 -0
- package/dist/templates/trellis/scripts/multi_agent/status.py +817 -0
- package/dist/templates/trellis/scripts/task.py +1056 -0
- package/dist/templates/trellis/scripts-shell-archive/add-session.sh +384 -0
- package/dist/templates/trellis/scripts-shell-archive/common/developer.sh +129 -0
- package/dist/templates/trellis/scripts-shell-archive/common/git-context.sh +263 -0
- package/dist/templates/trellis/scripts-shell-archive/common/paths.sh +208 -0
- package/dist/templates/trellis/scripts-shell-archive/common/phase.sh +150 -0
- package/dist/templates/trellis/scripts-shell-archive/common/registry.sh +247 -0
- package/dist/templates/trellis/scripts-shell-archive/common/task-queue.sh +142 -0
- package/dist/templates/trellis/scripts-shell-archive/common/task-utils.sh +151 -0
- package/dist/templates/trellis/scripts-shell-archive/common/worktree.sh +128 -0
- package/dist/templates/trellis/scripts-shell-archive/create-bootstrap.sh +299 -0
- package/dist/templates/trellis/scripts-shell-archive/get-context.sh +7 -0
- package/dist/templates/trellis/scripts-shell-archive/get-developer.sh +15 -0
- package/dist/templates/trellis/scripts-shell-archive/init-developer.sh +34 -0
- package/dist/templates/trellis/scripts-shell-archive/multi-agent/cleanup.sh +396 -0
- package/dist/templates/trellis/scripts-shell-archive/multi-agent/create-pr.sh +241 -0
- package/dist/templates/trellis/scripts-shell-archive/multi-agent/plan.sh +207 -0
- package/dist/templates/trellis/scripts-shell-archive/multi-agent/start.sh +317 -0
- package/dist/templates/trellis/scripts-shell-archive/multi-agent/status.sh +828 -0
- package/dist/templates/trellis/scripts-shell-archive/task.sh +1204 -0
- package/dist/templates/trellis/tasks/.gitkeep +0 -0
- package/dist/templates/trellis/workflow.md +416 -0
- package/dist/templates/trellis/worktree.yaml +47 -0
- package/dist/types/ai-tools.d.ts +48 -0
- package/dist/types/ai-tools.d.ts.map +1 -0
- package/dist/types/ai-tools.js +32 -0
- package/dist/types/ai-tools.js.map +1 -0
- package/dist/types/migration.d.ts +86 -0
- package/dist/types/migration.d.ts.map +1 -0
- package/dist/types/migration.js +8 -0
- package/dist/types/migration.js.map +1 -0
- package/dist/utils/compare-versions.d.ts +12 -0
- package/dist/utils/compare-versions.d.ts.map +1 -0
- package/dist/utils/compare-versions.js +76 -0
- package/dist/utils/compare-versions.js.map +1 -0
- package/dist/utils/file-writer.d.ts +23 -0
- package/dist/utils/file-writer.d.ts.map +1 -0
- package/dist/utils/file-writer.js +140 -0
- package/dist/utils/file-writer.js.map +1 -0
- package/dist/utils/project-detector.d.ts +16 -0
- package/dist/utils/project-detector.d.ts.map +1 -0
- package/dist/utils/project-detector.js +188 -0
- package/dist/utils/project-detector.js.map +1 -0
- package/dist/utils/template-fetcher.d.ts +51 -0
- package/dist/utils/template-fetcher.d.ts.map +1 -0
- package/dist/utils/template-fetcher.js +174 -0
- package/dist/utils/template-fetcher.js.map +1 -0
- package/dist/utils/template-hash.d.ts +78 -0
- package/dist/utils/template-hash.d.ts.map +1 -0
- package/dist/utils/template-hash.js +239 -0
- package/dist/utils/template-hash.js.map +1 -0
- package/package.json +87 -0
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
# Cross-Platform Thinking Guide
|
|
2
|
+
|
|
3
|
+
> **Purpose**: Catch platform-specific assumptions before they become bugs.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Why This Matters
|
|
8
|
+
|
|
9
|
+
**Most cross-platform bugs come from implicit assumptions**:
|
|
10
|
+
|
|
11
|
+
- Assumed shebang works → breaks on Windows
|
|
12
|
+
- Assumed `/` path separator → breaks on Windows
|
|
13
|
+
- Assumed `\n` line endings → inconsistent behavior
|
|
14
|
+
- Assumed command availability → `grep` vs `findstr`
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Platform Differences Checklist
|
|
19
|
+
|
|
20
|
+
### 1. Script Execution
|
|
21
|
+
|
|
22
|
+
| Assumption | macOS/Linux | Windows |
|
|
23
|
+
|------------|-------------|---------|
|
|
24
|
+
| Shebang (`#!/usr/bin/env python3`) | ✅ Works | ❌ Ignored |
|
|
25
|
+
| Direct execution (`./script.py`) | ✅ Works | ❌ Fails |
|
|
26
|
+
| `python3` command | ✅ Always available | ⚠️ May need `python` |
|
|
27
|
+
| `python` command | ⚠️ May be Python 2 | ✅ Usually Python 3 |
|
|
28
|
+
|
|
29
|
+
**Rule 1**: Always use explicit `python3` in documentation, help text, and error messages.
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
# BAD - Assumes shebang works
|
|
33
|
+
print("Usage: ./script.py <args>")
|
|
34
|
+
print("Run: script.py <args>")
|
|
35
|
+
|
|
36
|
+
# GOOD - Explicit interpreter
|
|
37
|
+
print("Usage: python3 script.py <args>")
|
|
38
|
+
print("Run: python3 ./script.py <args>")
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Rule 2**: When calling Python from TypeScript/Node.js, detect the available command:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
function getPythonCommand(): string {
|
|
45
|
+
try {
|
|
46
|
+
execSync("python3 --version", { stdio: "pipe" });
|
|
47
|
+
return "python3";
|
|
48
|
+
} catch {
|
|
49
|
+
try {
|
|
50
|
+
execSync("python --version", { stdio: "pipe" });
|
|
51
|
+
return "python";
|
|
52
|
+
} catch {
|
|
53
|
+
return "python3"; // Default, will fail with clear error
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Rule 3**: When calling Python from Python, use `sys.executable`:
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
import sys
|
|
63
|
+
import subprocess
|
|
64
|
+
|
|
65
|
+
# BAD - Hardcoded command
|
|
66
|
+
subprocess.run(["python3", "other_script.py"])
|
|
67
|
+
|
|
68
|
+
# GOOD - Use current interpreter
|
|
69
|
+
subprocess.run([sys.executable, "other_script.py"])
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 2. Path Handling
|
|
73
|
+
|
|
74
|
+
| Assumption | macOS/Linux | Windows |
|
|
75
|
+
|------------|-------------|---------|
|
|
76
|
+
| `/` separator | ✅ Works | ⚠️ Sometimes works |
|
|
77
|
+
| `\` separator | ❌ Escape char | ✅ Native |
|
|
78
|
+
| `pathlib.Path` | ✅ Works | ✅ Works |
|
|
79
|
+
|
|
80
|
+
**Rule**: Use `pathlib.Path` for all path operations.
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
# BAD - String concatenation
|
|
84
|
+
path = base + "/" + filename
|
|
85
|
+
|
|
86
|
+
# GOOD - pathlib
|
|
87
|
+
from pathlib import Path
|
|
88
|
+
path = Path(base) / filename
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 3. Line Endings
|
|
92
|
+
|
|
93
|
+
| Format | macOS/Linux | Windows | Git |
|
|
94
|
+
|--------|-------------|---------|-----|
|
|
95
|
+
| `\n` (LF) | ✅ Native | ⚠️ Some tools | ✅ Normalized |
|
|
96
|
+
| `\r\n` (CRLF) | ⚠️ Extra char | ✅ Native | Converted |
|
|
97
|
+
|
|
98
|
+
**Rule**: Use `.gitattributes` to enforce consistent line endings.
|
|
99
|
+
|
|
100
|
+
```gitattributes
|
|
101
|
+
* text=auto eol=lf
|
|
102
|
+
*.sh text eol=lf
|
|
103
|
+
*.py text eol=lf
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 4. Environment Variables
|
|
107
|
+
|
|
108
|
+
| Variable | macOS/Linux | Windows |
|
|
109
|
+
|----------|-------------|---------|
|
|
110
|
+
| `HOME` | ✅ Set | ❌ Use `USERPROFILE` |
|
|
111
|
+
| `PATH` separator | `:` | `;` |
|
|
112
|
+
| Case sensitivity | ✅ Case-sensitive | ❌ Case-insensitive |
|
|
113
|
+
|
|
114
|
+
**Rule**: Use `pathlib.Path.home()` instead of environment variables.
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
# BAD
|
|
118
|
+
home = os.environ.get("HOME")
|
|
119
|
+
|
|
120
|
+
# GOOD
|
|
121
|
+
home = Path.home()
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 5. Command Availability
|
|
125
|
+
|
|
126
|
+
| Command | macOS/Linux | Windows |
|
|
127
|
+
|---------|-------------|---------|
|
|
128
|
+
| `grep` | ✅ Built-in | ❌ Not available |
|
|
129
|
+
| `find` | ✅ Built-in | ⚠️ Different syntax |
|
|
130
|
+
| `cat` | ✅ Built-in | ❌ Use `type` |
|
|
131
|
+
| `tail -f` | ✅ Built-in | ❌ Not available |
|
|
132
|
+
|
|
133
|
+
**Rule**: Use Python standard library instead of shell commands when possible.
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
# BAD - tail -f is not available on Windows
|
|
137
|
+
subprocess.run(["tail", "-f", log_file])
|
|
138
|
+
|
|
139
|
+
# GOOD - Cross-platform implementation
|
|
140
|
+
def tail_follow(file_path: Path) -> None:
|
|
141
|
+
"""Follow a file like 'tail -f', cross-platform compatible."""
|
|
142
|
+
with open(file_path, "r", encoding="utf-8", errors="replace") as f:
|
|
143
|
+
f.seek(0, 2) # Go to end
|
|
144
|
+
while True:
|
|
145
|
+
line = f.readline()
|
|
146
|
+
if line:
|
|
147
|
+
print(line, end="", flush=True)
|
|
148
|
+
else:
|
|
149
|
+
time.sleep(0.1)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### 6. File Encoding
|
|
153
|
+
|
|
154
|
+
| Default Encoding | macOS/Linux | Windows |
|
|
155
|
+
|------------------|-------------|---------|
|
|
156
|
+
| Terminal | UTF-8 | Often CP1252 or GBK |
|
|
157
|
+
| File I/O | UTF-8 | System locale |
|
|
158
|
+
| Git output | UTF-8 | May vary |
|
|
159
|
+
|
|
160
|
+
**Rule**: Always explicitly specify `encoding="utf-8"` and use `errors="replace"`.
|
|
161
|
+
|
|
162
|
+
> **Checklist**: When writing scripts that print non-ASCII, did you configure stdout encoding?
|
|
163
|
+
> See `backend/script-conventions.md` for the specific pattern.
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
# BAD - Relies on system default
|
|
167
|
+
with open(file, "r") as f:
|
|
168
|
+
content = f.read()
|
|
169
|
+
|
|
170
|
+
result = subprocess.run(cmd, capture_output=True, text=True)
|
|
171
|
+
|
|
172
|
+
# GOOD - Explicit encoding with error handling
|
|
173
|
+
with open(file, "r", encoding="utf-8", errors="replace") as f:
|
|
174
|
+
content = f.read()
|
|
175
|
+
|
|
176
|
+
result = subprocess.run(
|
|
177
|
+
cmd,
|
|
178
|
+
capture_output=True,
|
|
179
|
+
text=True,
|
|
180
|
+
encoding="utf-8",
|
|
181
|
+
errors="replace"
|
|
182
|
+
)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Git commands**: Force UTF-8 output encoding:
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
# Force git to output UTF-8
|
|
189
|
+
git_args = ["git", "-c", "i18n.logOutputEncoding=UTF-8"] + args
|
|
190
|
+
result = subprocess.run(
|
|
191
|
+
git_args,
|
|
192
|
+
capture_output=True,
|
|
193
|
+
text=True,
|
|
194
|
+
encoding="utf-8",
|
|
195
|
+
errors="replace"
|
|
196
|
+
)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Change Propagation Checklist
|
|
202
|
+
|
|
203
|
+
When making platform-related changes, check **all these locations**:
|
|
204
|
+
|
|
205
|
+
### Documentation & Help Text
|
|
206
|
+
- [ ] Docstrings at top of Python files
|
|
207
|
+
- [ ] `--help` output / argparse descriptions
|
|
208
|
+
- [ ] Usage examples in README
|
|
209
|
+
- [ ] Error messages that suggest commands
|
|
210
|
+
- [ ] Markdown documentation (`.md` files)
|
|
211
|
+
|
|
212
|
+
### Code Locations
|
|
213
|
+
- [ ] `src/templates/` - Template files for new projects
|
|
214
|
+
- [ ] `.aim-studio/scripts/` - Project's own scripts (if self-hosting)
|
|
215
|
+
- [ ] `dist/` - Built output (rebuild after changes)
|
|
216
|
+
|
|
217
|
+
### Search Pattern
|
|
218
|
+
```bash
|
|
219
|
+
# Find all places that might need updating
|
|
220
|
+
grep -r "python [a-z]" --include="*.py" --include="*.md"
|
|
221
|
+
grep -r "\./" --include="*.py" --include="*.md" | grep -v python3
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Pre-Commit Checklist
|
|
227
|
+
|
|
228
|
+
Before committing cross-platform code:
|
|
229
|
+
|
|
230
|
+
- [ ] All Python invocations use `python3` explicitly (docs) or `sys.executable` (code)
|
|
231
|
+
- [ ] All paths use `pathlib.Path`
|
|
232
|
+
- [ ] No hardcoded path separators (`/` or `\`)
|
|
233
|
+
- [ ] No platform-specific commands without fallbacks (e.g., `tail -f`)
|
|
234
|
+
- [ ] All file I/O specifies `encoding="utf-8"` and `errors="replace"`
|
|
235
|
+
- [ ] All subprocess calls specify `encoding="utf-8"` and `errors="replace"`
|
|
236
|
+
- [ ] Git commands use `-c i18n.logOutputEncoding=UTF-8`
|
|
237
|
+
- [ ] External tool API formats verified from documentation
|
|
238
|
+
- [ ] Documentation matches code behavior
|
|
239
|
+
- [ ] Ran search to find all affected locations
|
|
240
|
+
|
|
241
|
+
### 7. External Tool API Contracts
|
|
242
|
+
|
|
243
|
+
When integrating with external tools (Claude Code, Cursor, etc.), their API contracts are **implicit assumptions**.
|
|
244
|
+
|
|
245
|
+
**Rule**: Verify API formats from official documentation, don't guess.
|
|
246
|
+
|
|
247
|
+
```python
|
|
248
|
+
# BAD - Guessed format
|
|
249
|
+
output = {"continue": True, "message": "..."}
|
|
250
|
+
|
|
251
|
+
# GOOD - Verified format from documentation
|
|
252
|
+
output = {
|
|
253
|
+
"hookSpecificOutput": {
|
|
254
|
+
"hookEventName": "SessionStart",
|
|
255
|
+
"additionalContext": "..."
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
> **Warning**: Different hook types may have different output formats.
|
|
261
|
+
> Always check the specific documentation for each hook event.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## JSON/External Data Defensive Checks
|
|
266
|
+
|
|
267
|
+
When parsing JSON or external data, TypeScript types are **compile-time only**. Runtime data may not match.
|
|
268
|
+
|
|
269
|
+
**Rule**: Always add defensive checks for required fields before using them.
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
// BAD - Trusts TypeScript type definition
|
|
273
|
+
interface MigrationItem {
|
|
274
|
+
from: string; // TypeScript says required
|
|
275
|
+
to?: string;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function process(item: MigrationItem) {
|
|
279
|
+
const path = item.from; // Runtime: could be undefined!
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// GOOD - Defensive check before use
|
|
283
|
+
function process(item: MigrationItem) {
|
|
284
|
+
if (!item.from) return; // Skip invalid data
|
|
285
|
+
const path = item.from; // Now guaranteed
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
**When to apply**:
|
|
290
|
+
- Parsing JSON files (manifests, configs)
|
|
291
|
+
- API responses
|
|
292
|
+
- User input
|
|
293
|
+
- Any data from external sources
|
|
294
|
+
|
|
295
|
+
**Pattern**: Check existence → then use
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
// Filter pattern - skip invalid items
|
|
299
|
+
const validItems = items.filter(item => item.from && item.to);
|
|
300
|
+
|
|
301
|
+
// Early return pattern - bail on invalid
|
|
302
|
+
if (!data.requiredField) {
|
|
303
|
+
console.warn("Missing required field");
|
|
304
|
+
return defaultValue;
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Common Mistakes
|
|
311
|
+
|
|
312
|
+
### 1. "It works on my Mac"
|
|
313
|
+
|
|
314
|
+
```python
|
|
315
|
+
# Developer's Mac
|
|
316
|
+
subprocess.run(["./script.py"]) # Works!
|
|
317
|
+
|
|
318
|
+
# User's Windows
|
|
319
|
+
subprocess.run(["./script.py"]) # FileNotFoundError
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### 2. "The shebang should handle it"
|
|
323
|
+
|
|
324
|
+
```python
|
|
325
|
+
#!/usr/bin/env python3
|
|
326
|
+
# This line is IGNORED on Windows
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### 3. "I updated the template"
|
|
330
|
+
|
|
331
|
+
```
|
|
332
|
+
src/templates/script.py ← Updated
|
|
333
|
+
.aim-studio/scripts/script.py ← Forgot to sync!
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### 4. "Python 3 is always python3"
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
# Developer's Mac/Linux
|
|
340
|
+
python3 script.py # Works!
|
|
341
|
+
|
|
342
|
+
# User's Windows (Python from python.org)
|
|
343
|
+
python3 script.py # 'python3' is not recognized
|
|
344
|
+
python script.py # Works!
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### 5. "UTF-8 is the default everywhere"
|
|
348
|
+
|
|
349
|
+
```python
|
|
350
|
+
# Developer's Mac (UTF-8 default)
|
|
351
|
+
subprocess.run(cmd, capture_output=True, text=True) # Works!
|
|
352
|
+
|
|
353
|
+
# User's Windows (GBK/CP1252 default)
|
|
354
|
+
subprocess.run(cmd, capture_output=True, text=True) # Garbled Chinese/Unicode
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
> **Note**: stdout encoding is also affected. See `backend/script-conventions.md` for the fix.
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
## Recovery: When You Find a Platform Bug
|
|
362
|
+
|
|
363
|
+
1. **Fix the immediate issue**
|
|
364
|
+
2. **Search for similar patterns** (grep the codebase)
|
|
365
|
+
3. **Update this guide** with the new pattern
|
|
366
|
+
4. **Add to pre-commit checklist** if recurring
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
**Core Principle**: If it's not explicit, it's an assumption. And assumptions break.
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
## Release Checklist: Versioned Files
|
|
375
|
+
|
|
376
|
+
When releasing a new version, ensure **all versioned files** are created/updated:
|
|
377
|
+
|
|
378
|
+
- [ ] `src/migrations/manifests/{version}.json` - Migration manifest exists
|
|
379
|
+
- [ ] Manifest has correct version, description, changelog
|
|
380
|
+
- [ ] `pnpm build` copies manifests to `dist/`
|
|
381
|
+
- [ ] Test upgrade path from older versions (not just adjacent)
|
|
382
|
+
|
|
383
|
+
**Why this matters**: Missing manifests cause "path undefined" errors when users upgrade from older versions.
|
|
384
|
+
|
|
385
|
+
```bash
|
|
386
|
+
# Verify all expected manifests exist
|
|
387
|
+
ls src/migrations/manifests/
|
|
388
|
+
|
|
389
|
+
# Test upgrade path
|
|
390
|
+
node -e "
|
|
391
|
+
const { getMigrationsForVersion } = require('./dist/migrations/index.js');
|
|
392
|
+
console.log('From 0.2.12:', getMigrationsForVersion('0.2.12', 'CURRENT').length);
|
|
393
|
+
"
|
|
394
|
+
```
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
# Cross-Platform Thinking Guide
|
|
2
|
+
|
|
3
|
+
> **Purpose**: Catch platform-specific assumptions before they become bugs.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Why This Matters
|
|
8
|
+
|
|
9
|
+
**Most cross-platform bugs come from implicit assumptions**:
|
|
10
|
+
|
|
11
|
+
- Assumed shebang works → breaks on Windows
|
|
12
|
+
- Assumed `/` path separator → breaks on Windows
|
|
13
|
+
- Assumed `\n` line endings → inconsistent behavior
|
|
14
|
+
- Assumed command availability → `grep` vs `findstr`
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Platform Differences Checklist
|
|
19
|
+
|
|
20
|
+
### 1. Script Execution
|
|
21
|
+
|
|
22
|
+
| Assumption | macOS/Linux | Windows |
|
|
23
|
+
|------------|-------------|---------|
|
|
24
|
+
| Shebang (`#!/usr/bin/env python3`) | ✅ Works | ❌ Ignored |
|
|
25
|
+
| Direct execution (`./script.py`) | ✅ Works | ❌ Fails |
|
|
26
|
+
| `python3` command | ✅ Always available | ⚠️ May need `python` |
|
|
27
|
+
| `python` command | ⚠️ May be Python 2 | ✅ Usually Python 3 |
|
|
28
|
+
|
|
29
|
+
**Rule 1**: Always use explicit `python3` in documentation, help text, and error messages.
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
# BAD - Assumes shebang works
|
|
33
|
+
print("Usage: ./script.py <args>")
|
|
34
|
+
print("Run: script.py <args>")
|
|
35
|
+
|
|
36
|
+
# GOOD - Explicit interpreter
|
|
37
|
+
print("Usage: python3 script.py <args>")
|
|
38
|
+
print("Run: python3 ./script.py <args>")
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Rule 2**: When calling Python from TypeScript/Node.js, detect the available command:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
function getPythonCommand(): string {
|
|
45
|
+
try {
|
|
46
|
+
execSync("python3 --version", { stdio: "pipe" });
|
|
47
|
+
return "python3";
|
|
48
|
+
} catch {
|
|
49
|
+
try {
|
|
50
|
+
execSync("python --version", { stdio: "pipe" });
|
|
51
|
+
return "python";
|
|
52
|
+
} catch {
|
|
53
|
+
return "python3"; // Default, will fail with clear error
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Rule 3**: When calling Python from Python, use `sys.executable`:
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
import sys
|
|
63
|
+
import subprocess
|
|
64
|
+
|
|
65
|
+
# BAD - Hardcoded command
|
|
66
|
+
subprocess.run(["python3", "other_script.py"])
|
|
67
|
+
|
|
68
|
+
# GOOD - Use current interpreter
|
|
69
|
+
subprocess.run([sys.executable, "other_script.py"])
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 2. Path Handling
|
|
73
|
+
|
|
74
|
+
| Assumption | macOS/Linux | Windows |
|
|
75
|
+
|------------|-------------|---------|
|
|
76
|
+
| `/` separator | ✅ Works | ⚠️ Sometimes works |
|
|
77
|
+
| `\` separator | ❌ Escape char | ✅ Native |
|
|
78
|
+
| `pathlib.Path` | ✅ Works | ✅ Works |
|
|
79
|
+
|
|
80
|
+
**Rule**: Use `pathlib.Path` for all path operations.
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
# BAD - String concatenation
|
|
84
|
+
path = base + "/" + filename
|
|
85
|
+
|
|
86
|
+
# GOOD - pathlib
|
|
87
|
+
from pathlib import Path
|
|
88
|
+
path = Path(base) / filename
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 3. Line Endings
|
|
92
|
+
|
|
93
|
+
| Format | macOS/Linux | Windows | Git |
|
|
94
|
+
|--------|-------------|---------|-----|
|
|
95
|
+
| `\n` (LF) | ✅ Native | ⚠️ Some tools | ✅ Normalized |
|
|
96
|
+
| `\r\n` (CRLF) | ⚠️ Extra char | ✅ Native | Converted |
|
|
97
|
+
|
|
98
|
+
**Rule**: Use `.gitattributes` to enforce consistent line endings.
|
|
99
|
+
|
|
100
|
+
```gitattributes
|
|
101
|
+
* text=auto eol=lf
|
|
102
|
+
*.sh text eol=lf
|
|
103
|
+
*.py text eol=lf
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 4. Environment Variables
|
|
107
|
+
|
|
108
|
+
| Variable | macOS/Linux | Windows |
|
|
109
|
+
|----------|-------------|---------|
|
|
110
|
+
| `HOME` | ✅ Set | ❌ Use `USERPROFILE` |
|
|
111
|
+
| `PATH` separator | `:` | `;` |
|
|
112
|
+
| Case sensitivity | ✅ Case-sensitive | ❌ Case-insensitive |
|
|
113
|
+
|
|
114
|
+
**Rule**: Use `pathlib.Path.home()` instead of environment variables.
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
# BAD
|
|
118
|
+
home = os.environ.get("HOME")
|
|
119
|
+
|
|
120
|
+
# GOOD
|
|
121
|
+
home = Path.home()
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 5. Command Availability
|
|
125
|
+
|
|
126
|
+
| Command | macOS/Linux | Windows |
|
|
127
|
+
|---------|-------------|---------|
|
|
128
|
+
| `grep` | ✅ Built-in | ❌ Not available |
|
|
129
|
+
| `find` | ✅ Built-in | ⚠️ Different syntax |
|
|
130
|
+
| `cat` | ✅ Built-in | ❌ Use `type` |
|
|
131
|
+
| `tail -f` | ✅ Built-in | ❌ Not available |
|
|
132
|
+
|
|
133
|
+
**Rule**: Use Python standard library instead of shell commands when possible.
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
# BAD - tail -f is not available on Windows
|
|
137
|
+
subprocess.run(["tail", "-f", log_file])
|
|
138
|
+
|
|
139
|
+
# GOOD - Cross-platform implementation
|
|
140
|
+
def tail_follow(file_path: Path) -> None:
|
|
141
|
+
"""Follow a file like 'tail -f', cross-platform compatible."""
|
|
142
|
+
with open(file_path, "r", encoding="utf-8", errors="replace") as f:
|
|
143
|
+
f.seek(0, 2) # Go to end
|
|
144
|
+
while True:
|
|
145
|
+
line = f.readline()
|
|
146
|
+
if line:
|
|
147
|
+
print(line, end="", flush=True)
|
|
148
|
+
else:
|
|
149
|
+
time.sleep(0.1)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### 6. File Encoding
|
|
153
|
+
|
|
154
|
+
| Default Encoding | macOS/Linux | Windows |
|
|
155
|
+
|------------------|-------------|---------|
|
|
156
|
+
| Terminal | UTF-8 | Often CP1252 or GBK |
|
|
157
|
+
| File I/O | UTF-8 | System locale |
|
|
158
|
+
| Git output | UTF-8 | May vary |
|
|
159
|
+
|
|
160
|
+
**Rule**: Always explicitly specify `encoding="utf-8"` and use `errors="replace"`.
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
# BAD - Relies on system default
|
|
164
|
+
with open(file, "r") as f:
|
|
165
|
+
content = f.read()
|
|
166
|
+
|
|
167
|
+
result = subprocess.run(cmd, capture_output=True, text=True)
|
|
168
|
+
|
|
169
|
+
# GOOD - Explicit encoding with error handling
|
|
170
|
+
with open(file, "r", encoding="utf-8", errors="replace") as f:
|
|
171
|
+
content = f.read()
|
|
172
|
+
|
|
173
|
+
result = subprocess.run(
|
|
174
|
+
cmd,
|
|
175
|
+
capture_output=True,
|
|
176
|
+
text=True,
|
|
177
|
+
encoding="utf-8",
|
|
178
|
+
errors="replace"
|
|
179
|
+
)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Git commands**: Force UTF-8 output encoding:
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
# Force git to output UTF-8
|
|
186
|
+
git_args = ["git", "-c", "i18n.logOutputEncoding=UTF-8"] + args
|
|
187
|
+
result = subprocess.run(
|
|
188
|
+
git_args,
|
|
189
|
+
capture_output=True,
|
|
190
|
+
text=True,
|
|
191
|
+
encoding="utf-8",
|
|
192
|
+
errors="replace"
|
|
193
|
+
)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Change Propagation Checklist
|
|
199
|
+
|
|
200
|
+
When making platform-related changes, check **all these locations**:
|
|
201
|
+
|
|
202
|
+
### Documentation & Help Text
|
|
203
|
+
- [ ] Docstrings at top of Python files
|
|
204
|
+
- [ ] `--help` output / argparse descriptions
|
|
205
|
+
- [ ] Usage examples in README
|
|
206
|
+
- [ ] Error messages that suggest commands
|
|
207
|
+
- [ ] Markdown documentation (`.md` files)
|
|
208
|
+
|
|
209
|
+
### Code Locations
|
|
210
|
+
- [ ] `src/templates/` - Template files for new projects
|
|
211
|
+
- [ ] `.aim-studio/scripts/` - Project's own scripts (if self-hosting)
|
|
212
|
+
- [ ] `dist/` - Built output (rebuild after changes)
|
|
213
|
+
|
|
214
|
+
### Search Pattern
|
|
215
|
+
```bash
|
|
216
|
+
# Find all places that might need updating
|
|
217
|
+
grep -r "python [a-z]" --include="*.py" --include="*.md"
|
|
218
|
+
grep -r "\./" --include="*.py" --include="*.md" | grep -v python3
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Pre-Commit Checklist
|
|
224
|
+
|
|
225
|
+
Before committing cross-platform code:
|
|
226
|
+
|
|
227
|
+
- [ ] All Python invocations use `python3` explicitly (docs) or `sys.executable` (code)
|
|
228
|
+
- [ ] All paths use `pathlib.Path`
|
|
229
|
+
- [ ] No hardcoded path separators (`/` or `\`)
|
|
230
|
+
- [ ] No platform-specific commands without fallbacks (e.g., `tail -f`)
|
|
231
|
+
- [ ] All file I/O specifies `encoding="utf-8"` and `errors="replace"`
|
|
232
|
+
- [ ] All subprocess calls specify `encoding="utf-8"` and `errors="replace"`
|
|
233
|
+
- [ ] Git commands use `-c i18n.logOutputEncoding=UTF-8`
|
|
234
|
+
- [ ] External tool API formats verified from documentation
|
|
235
|
+
- [ ] Documentation matches code behavior
|
|
236
|
+
- [ ] Ran search to find all affected locations
|
|
237
|
+
|
|
238
|
+
### 7. External Tool API Contracts
|
|
239
|
+
|
|
240
|
+
When integrating with external tools (Claude Code, Cursor, etc.), their API contracts are **implicit assumptions**.
|
|
241
|
+
|
|
242
|
+
**Rule**: Verify API formats from official documentation, don't guess.
|
|
243
|
+
|
|
244
|
+
```python
|
|
245
|
+
# BAD - Guessed format
|
|
246
|
+
output = {"continue": True, "message": "..."}
|
|
247
|
+
|
|
248
|
+
# GOOD - Verified format from documentation
|
|
249
|
+
output = {
|
|
250
|
+
"hookSpecificOutput": {
|
|
251
|
+
"hookEventName": "SessionStart",
|
|
252
|
+
"additionalContext": "..."
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
> **Warning**: Different hook types may have different output formats.
|
|
258
|
+
> Always check the specific documentation for each hook event.
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Common Mistakes
|
|
263
|
+
|
|
264
|
+
### 1. "It works on my Mac"
|
|
265
|
+
|
|
266
|
+
```python
|
|
267
|
+
# Developer's Mac
|
|
268
|
+
subprocess.run(["./script.py"]) # Works!
|
|
269
|
+
|
|
270
|
+
# User's Windows
|
|
271
|
+
subprocess.run(["./script.py"]) # FileNotFoundError
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### 2. "The shebang should handle it"
|
|
275
|
+
|
|
276
|
+
```python
|
|
277
|
+
#!/usr/bin/env python3
|
|
278
|
+
# This line is IGNORED on Windows
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### 3. "I updated the template"
|
|
282
|
+
|
|
283
|
+
```
|
|
284
|
+
src/templates/script.py ← Updated
|
|
285
|
+
.aim-studio/scripts/script.py ← Forgot to sync!
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### 4. "Python 3 is always python3"
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
# Developer's Mac/Linux
|
|
292
|
+
python3 script.py # Works!
|
|
293
|
+
|
|
294
|
+
# User's Windows (Python from python.org)
|
|
295
|
+
python3 script.py # 'python3' is not recognized
|
|
296
|
+
python script.py # Works!
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### 5. "UTF-8 is the default everywhere"
|
|
300
|
+
|
|
301
|
+
```python
|
|
302
|
+
# Developer's Mac (UTF-8 default)
|
|
303
|
+
subprocess.run(cmd, capture_output=True, text=True) # Works!
|
|
304
|
+
|
|
305
|
+
# User's Windows (GBK/CP1252 default)
|
|
306
|
+
subprocess.run(cmd, capture_output=True, text=True) # Garbled Chinese/Unicode
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Recovery: When You Find a Platform Bug
|
|
311
|
+
|
|
312
|
+
1. **Fix the immediate issue**
|
|
313
|
+
2. **Search for similar patterns** (grep the codebase)
|
|
314
|
+
3. **Update this guide** with the new pattern
|
|
315
|
+
4. **Add to pre-commit checklist** if recurring
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
**Core Principle**: If it's not explicit, it's an assumption. And assumptions break.
|