@caddis/cli 0.0.0 → 0.1.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/LICENSE +21 -0
- package/README.md +150 -1
- package/bundles/antigravity-plugin/agents/code-reviewer.md +47 -0
- package/bundles/antigravity-plugin/agents/preflight.md +53 -0
- package/bundles/antigravity-plugin/guard_agy.py +338 -0
- package/bundles/antigravity-plugin/hooks.json +36 -0
- package/bundles/antigravity-plugin/mcp_config.json +8 -0
- package/bundles/antigravity-plugin/mcp_ping_server.py +55 -0
- package/bundles/antigravity-plugin/plugin.json +5 -0
- package/bundles/antigravity-plugin/session_end_agy.py +57 -0
- package/bundles/antigravity-plugin/skills/_registry.md +115 -0
- package/bundles/antigravity-plugin/skills/add-rules/SKILL.md +45 -0
- package/bundles/antigravity-plugin/skills/api-design/SKILL.md +249 -0
- package/bundles/antigravity-plugin/skills/backend-development/SKILL.md +305 -0
- package/bundles/antigravity-plugin/skills/best-practices/SKILL.md +500 -0
- package/bundles/antigravity-plugin/skills/best-practices/agents/best-practices-referencer.md +263 -0
- package/bundles/antigravity-plugin/skills/best-practices/agents/codebase-context-builder.md +326 -0
- package/bundles/antigravity-plugin/skills/best-practices/agents/task-intent-analyzer.md +245 -0
- package/bundles/antigravity-plugin/skills/best-practices/references/anti-patterns.md +571 -0
- package/bundles/antigravity-plugin/skills/best-practices/references/before-after-examples.md +1114 -0
- package/bundles/antigravity-plugin/skills/best-practices/references/best-practices-guide.md +513 -0
- package/bundles/antigravity-plugin/skills/best-practices/references/common-workflows.md +692 -0
- package/bundles/antigravity-plugin/skills/best-practices/references/prompt-patterns.md +547 -0
- package/bundles/antigravity-plugin/skills/brainstorming/SKILL.md +57 -0
- package/bundles/antigravity-plugin/skills/ci-cd-pipeline/SKILL.md +315 -0
- package/bundles/antigravity-plugin/skills/code-documentation/SKILL.md +271 -0
- package/bundles/antigravity-plugin/skills/code-review/SKILL.md +122 -0
- package/bundles/antigravity-plugin/skills/codebase-audit/SKILL.md +204 -0
- package/bundles/antigravity-plugin/skills/context-curator/SKILL.md +157 -0
- package/bundles/antigravity-plugin/skills/cross-review/SKILL.md +40 -0
- package/bundles/antigravity-plugin/skills/css-architecture/SKILL.md +305 -0
- package/bundles/antigravity-plugin/skills/css-architecture/references/RESPONSIVE-DESIGN.md +604 -0
- package/bundles/antigravity-plugin/skills/database-design/SKILL.md +177 -0
- package/bundles/antigravity-plugin/skills/db-diagram/SKILL.md +148 -0
- package/bundles/antigravity-plugin/skills/db-diagram/scripts/sql_to_graph.py +1212 -0
- package/bundles/antigravity-plugin/skills/digress/SKILL.md +61 -0
- package/bundles/antigravity-plugin/skills/draw-io/SKILL.md +162 -0
- package/bundles/antigravity-plugin/skills/draw-io/references/aws-icons.md +677 -0
- package/bundles/antigravity-plugin/skills/draw-io/references/layout-guidelines.md +142 -0
- package/bundles/antigravity-plugin/skills/draw-io/references/troubleshooting.md +118 -0
- package/bundles/antigravity-plugin/skills/draw-io/references/workflows.md +103 -0
- package/bundles/antigravity-plugin/skills/draw-io/scripts/convert-drawio-to-png.sh +25 -0
- package/bundles/antigravity-plugin/skills/draw-io/scripts/find_aws_icon.py +79 -0
- package/bundles/antigravity-plugin/skills/error-handling/SKILL.md +260 -0
- package/bundles/antigravity-plugin/skills/excalidraw-db/SKILL.md +38 -0
- package/bundles/antigravity-plugin/skills/fastapi-dev/SKILL.md +300 -0
- package/bundles/antigravity-plugin/skills/feature-plan/SKILL.md +198 -0
- package/bundles/antigravity-plugin/skills/frontend-design/SKILL.md +193 -0
- package/bundles/antigravity-plugin/skills/frontend-design/references/my-tech-stack.md +127 -0
- package/bundles/antigravity-plugin/skills/gh-cli/SKILL.md +195 -0
- package/bundles/antigravity-plugin/skills/git-commit/SKILL.md +285 -0
- package/bundles/antigravity-plugin/skills/golden-plan/SKILL.md +577 -0
- package/bundles/antigravity-plugin/skills/handoff/SKILL.md +100 -0
- package/bundles/antigravity-plugin/skills/implement/SKILL.md +114 -0
- package/bundles/antigravity-plugin/skills/javascript-typescript/SKILL.md +142 -0
- package/bundles/antigravity-plugin/skills/kb/SKILL.md +60 -0
- package/bundles/antigravity-plugin/skills/mermaid-db/SKILL.md +33 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/SKILL.md +236 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/ENHANCEMENTS.md +264 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/MERMAID-SUMMARY.md +137 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/advanced-features.md +556 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/architecture-diagrams.md +192 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/c4-diagrams.md +410 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/class-diagrams.md +361 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/erd-diagrams.md +510 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/flowcharts.md +450 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/sequence-diagrams.md +394 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/troubleshooting.md +335 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/workflows.md +418 -0
- package/bundles/antigravity-plugin/skills/migrate-dir/SKILL.md +68 -0
- package/bundles/antigravity-plugin/skills/mockup/SKILL.md +242 -0
- package/bundles/antigravity-plugin/skills/particle-art/SKILL.md +243 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/canvas-utils.ts +171 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/dot-field.template.tsx +203 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/flow-field.template.tsx +263 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/node-shape.template.tsx +261 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/shape-sampler.ts +281 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/stipple-morph.template.tsx +167 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/stipple.template.tsx +175 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/trail-ghost.template.tsx +266 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/usage-examples.md +320 -0
- package/bundles/antigravity-plugin/skills/playwright/API_REFERENCE.md +653 -0
- package/bundles/antigravity-plugin/skills/playwright/SKILL.md +454 -0
- package/bundles/antigravity-plugin/skills/playwright/lib/helpers.js +441 -0
- package/bundles/antigravity-plugin/skills/playwright/package.json +26 -0
- package/bundles/antigravity-plugin/skills/playwright/run.js +228 -0
- package/bundles/antigravity-plugin/skills/prd/SKILL.md +107 -0
- package/bundles/antigravity-plugin/skills/preflight/SKILL.md +435 -0
- package/bundles/antigravity-plugin/skills/python/SKILL.md +388 -0
- package/bundles/antigravity-plugin/skills/react-best-practices/SKILL.md +269 -0
- package/bundles/antigravity-plugin/skills/react-dev/README.md +404 -0
- package/bundles/antigravity-plugin/skills/react-dev/SKILL.md +459 -0
- package/bundles/antigravity-plugin/skills/react-dev/examples/generic-components.md +579 -0
- package/bundles/antigravity-plugin/skills/react-dev/examples/server-components.md +579 -0
- package/bundles/antigravity-plugin/skills/react-dev/references/event-handlers.md +574 -0
- package/bundles/antigravity-plugin/skills/react-dev/references/hooks.md +456 -0
- package/bundles/antigravity-plugin/skills/react-dev/references/react-19-patterns.md +638 -0
- package/bundles/antigravity-plugin/skills/react-dev/references/react-router.md +1002 -0
- package/bundles/antigravity-plugin/skills/react-dev/references/tanstack-router.md +587 -0
- package/bundles/antigravity-plugin/skills/refactoring/SKILL.md +486 -0
- package/bundles/antigravity-plugin/skills/resume/SKILL.md +36 -0
- package/bundles/antigravity-plugin/skills/security-review/SKILL.md +196 -0
- package/bundles/antigravity-plugin/skills/setup-project-ai/SKILL.md +61 -0
- package/bundles/antigravity-plugin/skills/ship/SKILL.md +107 -0
- package/bundles/antigravity-plugin/skills/ship-merge/SKILL.md +103 -0
- package/bundles/antigravity-plugin/skills/ship-pr/SKILL.md +102 -0
- package/bundles/antigravity-plugin/skills/skill-creator/LICENSE.txt +202 -0
- package/bundles/antigravity-plugin/skills/skill-creator/SKILL.md +491 -0
- package/bundles/antigravity-plugin/skills/skill-creator/agents/analyzer.md +274 -0
- package/bundles/antigravity-plugin/skills/skill-creator/agents/comparator.md +202 -0
- package/bundles/antigravity-plugin/skills/skill-creator/agents/grader.md +223 -0
- package/bundles/antigravity-plugin/skills/skill-creator/assets/eval_review.html +146 -0
- package/bundles/antigravity-plugin/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/bundles/antigravity-plugin/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/bundles/antigravity-plugin/skills/skill-creator/references/schemas.md +430 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/__init__.py +0 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/generate_report.py +326 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/improve_description.py +247 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/package_skill.py +136 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/run_eval.py +310 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/run_loop.py +328 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/utils.py +47 -0
- package/bundles/antigravity-plugin/skills/sql/SKILL.md +321 -0
- package/bundles/antigravity-plugin/skills/tdd/SKILL.md +37 -0
- package/bundles/antigravity-plugin/skills/tdd-workflow/SKILL.md +188 -0
- package/bundles/antigravity-plugin/skills/technical-writing/SKILL.md +286 -0
- package/bundles/antigravity-plugin/skills/test-strategy/SKILL.md +155 -0
- package/bundles/antigravity-plugin/skills/ui-brief/SKILL.md +84 -0
- package/bundles/antigravity-plugin/skills/ui-review/SKILL.md +176 -0
- package/bundles/antigravity-plugin/skills/ui-review/references/framework-fixes.md +471 -0
- package/bundles/antigravity-plugin/skills/ui-review/references/visual-checklist.md +236 -0
- package/bundles/antigravity-plugin/skills/usage-review/SKILL.md +77 -0
- package/bundles/antigravity-plugin/skills/use-model/SKILL.md +64 -0
- package/bundles/antigravity-plugin/skills/using-git-worktrees/SKILL.md +217 -0
- package/bundles/antigravity-plugin/skills/version/SKILL.md +18 -0
- package/bundles/antigravity-plugin/skills/warm-editorial-ui/DESIGN_TOKENS.md +487 -0
- package/bundles/antigravity-plugin/skills/warm-editorial-ui/IMPLEMENTATION_GUIDE.md +177 -0
- package/bundles/antigravity-plugin/skills/warm-editorial-ui/SKILL.md +732 -0
- package/bundles/antigravity-plugin/skills/webapp-testing/LICENSE.txt +202 -0
- package/bundles/antigravity-plugin/skills/webapp-testing/SKILL.md +97 -0
- package/bundles/antigravity-plugin/skills/webapp-testing/examples/console_logging.py +35 -0
- package/bundles/antigravity-plugin/skills/webapp-testing/examples/element_discovery.py +40 -0
- package/bundles/antigravity-plugin/skills/webapp-testing/examples/static_html_automation.py +33 -0
- package/bundles/antigravity-plugin/skills/webapp-testing/scripts/with_server.py +106 -0
- package/bundles/antigravity-plugin/skills/windows-deployment/SKILL.md +880 -0
- package/bundles/antigravity-plugin/skills/writing-plans/SKILL.md +384 -0
- package/bundles/antigravity-plugin/statusline-command-agy.sh +91 -0
- package/bundles/antigravity-plugin/warm_start_agy.py +149 -0
- package/bundles/manifest.json +6 -0
- package/dist/cli.js +5363 -0
- package/package.json +61 -4
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: writing-plans
|
|
3
|
+
context: fork
|
|
4
|
+
description: Use when you have a spec or requirements for a multi-step task, before touching code
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Writing Plans
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
Write comprehensive implementation plans assuming the engineer has zero context for our codebase and questionable taste. Document everything they need to know: which files to touch for each task, code, testing, docs they might need to check, how to test it. Give them the whole plan as bite-sized tasks. DRY. YAGNI. TDD. Frequent commits.
|
|
12
|
+
|
|
13
|
+
Assume they are a skilled developer, but know almost nothing about our toolset or problem domain. Assume they don't know good test design very well.
|
|
14
|
+
|
|
15
|
+
**Announce at start:** "I'm using the writing-plans skill to create the implementation plan."
|
|
16
|
+
|
|
17
|
+
**Context:** This should be run in a dedicated worktree (created by brainstorming skill).
|
|
18
|
+
|
|
19
|
+
**Save plans to:** `docs/plans/YYYY-MM-DD-<feature-name>.md`
|
|
20
|
+
|
|
21
|
+
**Document metadata:** Before creating or updating a plan, apply `.github/instructions/document-frontmatter.instructions.md`. The YAML frontmatter block must be the first content in the file. New plans require `Original Author`, `Creation Date`, and `Creating Model`; revised plans must preserve those fields and add or update `Last Author`, `Last Updated`, and `Last Model Used`.
|
|
22
|
+
|
|
23
|
+
## Bite-Sized Task Granularity
|
|
24
|
+
|
|
25
|
+
**Each step is one action (2-5 minutes):**
|
|
26
|
+
- "Write the failing test" - step
|
|
27
|
+
- "Run it to make sure it fails" - step
|
|
28
|
+
- "Implement the minimal code to make the test pass" - step
|
|
29
|
+
- "Run the tests and make sure they pass" - step
|
|
30
|
+
- "Commit" - step
|
|
31
|
+
|
|
32
|
+
## Plan Document Header
|
|
33
|
+
|
|
34
|
+
**Every plan MUST start with this header (YAML frontmatter first, then title):**
|
|
35
|
+
|
|
36
|
+
```markdown
|
|
37
|
+
---
|
|
38
|
+
chain_id: <chain_id>
|
|
39
|
+
type: plan
|
|
40
|
+
status: current
|
|
41
|
+
approval: pending
|
|
42
|
+
Original Author: <active author or agent name>
|
|
43
|
+
Creation Date: <YYYY-MM-DDTHH:MM:SSZ>
|
|
44
|
+
Creating Model: <exact runtime model identifier or display name>
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
# [Feature Name] Implementation Plan
|
|
48
|
+
|
|
49
|
+
> **For the implementing agent:** Follow this plan task-by-task, executing each step sequentially.
|
|
50
|
+
|
|
51
|
+
**Goal:** [One sentence describing what this builds]
|
|
52
|
+
|
|
53
|
+
**Architecture:** [2-3 sentences about approach]
|
|
54
|
+
|
|
55
|
+
**Tech Stack:** [Key technologies/libraries]
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
> ⚠️ The YAML frontmatter block (`---` delimiters) is required for Orchestrator artefact contract validation. Do NOT use blockquote-style metadata (`> **approval:** pending`) — it will not be parsed.
|
|
61
|
+
> Preserve the original metadata fields on later edits, and add or update `Last Author`, `Last Updated`, and `Last Model Used` when the plan is revised. Use full ISO 8601 UTC timestamps for `Creation Date` and `Last Updated`.
|
|
62
|
+
|
|
63
|
+
## Task Structure
|
|
64
|
+
|
|
65
|
+
```markdown
|
|
66
|
+
### Task N: [Component Name]
|
|
67
|
+
|
|
68
|
+
**Files:**
|
|
69
|
+
- Create: `exact/path/to/file.py`
|
|
70
|
+
- Modify: `exact/path/to/existing.py:123-145`
|
|
71
|
+
- Test: `tests/exact/path/to/test.py`
|
|
72
|
+
|
|
73
|
+
**Step 1: Write the failing test**
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
def test_specific_behavior():
|
|
77
|
+
result = function(input)
|
|
78
|
+
assert result == expected
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Step 2: Run test to verify it fails**
|
|
82
|
+
|
|
83
|
+
Run: `pytest tests/path/test.py::test_name -v`
|
|
84
|
+
Expected: FAIL with "function not defined"
|
|
85
|
+
|
|
86
|
+
**Step 3: Write minimal implementation**
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
def function(input):
|
|
90
|
+
return expected
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Step 4: Run test to verify it passes**
|
|
94
|
+
|
|
95
|
+
Run: `pytest tests/path/test.py::test_name -v`
|
|
96
|
+
Expected: PASS
|
|
97
|
+
|
|
98
|
+
**Step 5: Commit**
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
git add tests/path/test.py src/path/file.py
|
|
102
|
+
git commit -m "feat: add specific feature"
|
|
103
|
+
```
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Manual Execution Protocol
|
|
107
|
+
|
|
108
|
+
**Every plan MUST include a Manual Execution Protocol section** at the top (after header, before phases). This tells the user exactly how to run each phase session:
|
|
109
|
+
|
|
110
|
+
```markdown
|
|
111
|
+
## Manual Execution Protocol
|
|
112
|
+
|
|
113
|
+
For each phase below, follow this workflow:
|
|
114
|
+
|
|
115
|
+
1. **Open** a new chat session with the agent specified in the phase header
|
|
116
|
+
2. **Load skills** listed in the phase's "Skills to load" section
|
|
117
|
+
3. **Attach files** listed in the phase's "Files to attach" section
|
|
118
|
+
4. **Paste** the self-contained Phase Prompt into the chat
|
|
119
|
+
5. **Validate** using the phase's Validation Checklist — every item must pass
|
|
120
|
+
6. **Get green light** before moving to the next phase
|
|
121
|
+
|
|
122
|
+
**Drift rule:** If you find bugs introduced by Phase N, fix them in the SAME session
|
|
123
|
+
before starting Phase N+1. Never carry implementation debt forward between phases.
|
|
124
|
+
|
|
125
|
+
**Dependency sequencing rule:** Write phases in execution order \u2014 every phase's dependencies must appear before that phase in the plan. If Phase 3 requires output from Phase 4, reorder before writing. No forward dependencies.
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Phase 0 — Context & Decisions
|
|
129
|
+
|
|
130
|
+
**Every multi-phase plan MUST include a Phase 0** before the implementation phases. Phase 0 is not an implementation phase — it is a ground-truth inventory that prevents agents from making assumptions.
|
|
131
|
+
|
|
132
|
+
Phase 0 contains four mandatory tables:
|
|
133
|
+
|
|
134
|
+
### Technology Decision Table
|
|
135
|
+
|
|
136
|
+
```markdown
|
|
137
|
+
### Technology Decisions
|
|
138
|
+
|
|
139
|
+
| Decision | Choice | Rationale |
|
|
140
|
+
|----------|--------|-----------|
|
|
141
|
+
| Charting library | Recharts | Tree-shakeable, React-native, typed API |
|
|
142
|
+
| Animation | Framer Motion | AnimatePresence for tab transitions, spring physics |
|
|
143
|
+
| State management | Zustand | Lightweight, no boilerplate, devtools support |
|
|
144
|
+
| ... | ... | ... |
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Every technology choice that is NOT already in `project-config.md` must appear here with a rationale.
|
|
148
|
+
|
|
149
|
+
### Data Parity / Availability Matrix
|
|
150
|
+
|
|
151
|
+
```markdown
|
|
152
|
+
### Data Availability
|
|
153
|
+
|
|
154
|
+
| Feature / Tab | Data Field | Available? | Strategy |
|
|
155
|
+
|---------------|-----------|------------|----------|
|
|
156
|
+
| Executive Overview | `ceoInsight` | ✅ Full | Live API |
|
|
157
|
+
| Product Deep-Dive | `satisfactionScores` | ❌ Empty `{}` | Show empty state: "Coming in future release" |
|
|
158
|
+
| Geography | `byGeography` | ⚠️ Partial (was present May-Oct) | Show empty state with explanation |
|
|
159
|
+
| ... | ... | ... | ... |
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
For any data field that may be empty, partial, or absent: document the exact empty state message text.
|
|
163
|
+
|
|
164
|
+
### Existing Scaffold Audit
|
|
165
|
+
|
|
166
|
+
```markdown
|
|
167
|
+
### Existing Scaffold — DO NOT Recreate
|
|
168
|
+
|
|
169
|
+
| File | Purpose | Current State |
|
|
170
|
+
|------|---------|---------------|
|
|
171
|
+
| `frontend/src/api/client.ts` | API client with JWT auth | ✅ Working — build on top |
|
|
172
|
+
| `frontend/src/types/nps.ts` | 30+ TypeScript interfaces | ✅ Working — import, don't recreate |
|
|
173
|
+
| `frontend/src/components/layout/AppShell.tsx` | App shell | ⚠️ Cold zinc theme — needs warm overhaul |
|
|
174
|
+
| ... | ... | ... |
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
The "Current State" column tells agents what exists and whether to modify or leave it alone.
|
|
178
|
+
|
|
179
|
+
### Dependency Split
|
|
180
|
+
|
|
181
|
+
```markdown
|
|
182
|
+
### Dependencies
|
|
183
|
+
|
|
184
|
+
**Already installed** (DO NOT reinstall):
|
|
185
|
+
- react, react-dom, typescript, vite
|
|
186
|
+
- @tanstack/react-query, @tanstack/react-router
|
|
187
|
+
- tailwindcss, zustand
|
|
188
|
+
|
|
189
|
+
**Not yet installed** (install in Phase 1):
|
|
190
|
+
- recharts, framer-motion, leaflet, react-leaflet
|
|
191
|
+
- d3-force, d3-scale
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Enhanced Per-Phase Template
|
|
195
|
+
|
|
196
|
+
**Every implementation phase MUST use this structure.** The sections OUTSIDE the prompt block are for the user (what to prepare before opening a session). The prompt block is for the agent (what to paste into the session).
|
|
197
|
+
|
|
198
|
+
```markdown
|
|
199
|
+
## Phase N — {Name}
|
|
200
|
+
|
|
201
|
+
**Agent:** `@{agent-name}`
|
|
202
|
+
**Objective:** {One sentence describing what this phase builds}
|
|
203
|
+
|
|
204
|
+
### Skills to load
|
|
205
|
+
|
|
206
|
+
- `.github/skills/{path}/SKILL.md` — {why}
|
|
207
|
+
- `.github/skills/{path}/SKILL.md` — {why}
|
|
208
|
+
|
|
209
|
+
### Instructions to follow
|
|
210
|
+
|
|
211
|
+
- `.github/instructions/{name}.instructions.md`
|
|
212
|
+
- `.github/instructions/{name}.instructions.md`
|
|
213
|
+
|
|
214
|
+
### Files to attach
|
|
215
|
+
|
|
216
|
+
- `path/to/file.ext` — {why this file is needed}
|
|
217
|
+
- `path/to/file.ext` (from Phase N-1)
|
|
218
|
+
- `.github/plans/{this-plan}.md` (this file)
|
|
219
|
+
|
|
220
|
+
### Phase Prompt
|
|
221
|
+
|
|
222
|
+
\`\`\`
|
|
223
|
+
{Self-contained prompt — copy-paste ready. 30-60 lines.
|
|
224
|
+
References plan sections for detail. Does NOT duplicate code blocks.
|
|
225
|
+
Includes PRINCIPLES, SKILLS TO READ, IMPORTANT warnings, and numbered deliverable list.}
|
|
226
|
+
\`\`\`
|
|
227
|
+
|
|
228
|
+
### What to build
|
|
229
|
+
|
|
230
|
+
#### N.1 {Deliverable Name}
|
|
231
|
+
|
|
232
|
+
**File:** `exact/path/to/file.ext`
|
|
233
|
+
|
|
234
|
+
{Component interface / function signature}
|
|
235
|
+
|
|
236
|
+
**Data binding:**
|
|
237
|
+
- Uses `data.field.path` for {purpose}
|
|
238
|
+
- Uses `data.other.field` for {purpose}
|
|
239
|
+
|
|
240
|
+
**Behavior:**
|
|
241
|
+
- {Specific interactive behavior}
|
|
242
|
+
- {Animation spec with exact values}
|
|
243
|
+
|
|
244
|
+
**Empty state:** When `data.field` is `{}` or `[]`:
|
|
245
|
+
> "{Exact message text to display}"
|
|
246
|
+
|
|
247
|
+
**IMPORTANT:** {Trap-specific warning — e.g., "DO NOT recreate api/client.ts",
|
|
248
|
+
"field uses snake_case in BOTH API and TS types — no transformation needed"}
|
|
249
|
+
|
|
250
|
+
#### N.2 {Next Deliverable}
|
|
251
|
+
...
|
|
252
|
+
|
|
253
|
+
### Validation Checklist — Phase N complete when
|
|
254
|
+
|
|
255
|
+
- [ ] `npm run build` succeeds (or equivalent build command)
|
|
256
|
+
- [ ] {Specific behavioral criterion — e.g., "KpiFlipCard flip animation works independently on each card"}
|
|
257
|
+
- [ ] {Data binding criterion — e.g., "NpsSummaryTable renders 5 rows with correct data from surveys + trend"}
|
|
258
|
+
- [ ] {Visual criterion — e.g., "Dark mode: all components render correctly with soft dark tokens"}
|
|
259
|
+
- [ ] {Integration criterion — e.g., "Row click switches to Tab 2 and scrolls to chart"}
|
|
260
|
+
- [ ] Zero hardcoded data — all from props/hooks
|
|
261
|
+
- [ ] Zero hardcoded colors — all from CSS vars or constants
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Key rules for the "What to build" subsections
|
|
265
|
+
|
|
266
|
+
1. **Data binding is mandatory for UI components.** Every component spec must list the exact JSON field paths it consumes (e.g., `surveys.{product}.nps`, `trend.historicalNPS.byProduct.{product}`). This eliminates the #1 implementer failure mode: guessing which field to bind.
|
|
267
|
+
|
|
268
|
+
2. **Empty state specs are mandatory.** For every data field that might be empty, specify the exact message text. Do NOT say "show appropriate empty state" — write the message.
|
|
269
|
+
|
|
270
|
+
3. **IMPORTANT warnings for traps.** If a file already exists and must NOT be recreated, say so. If a field uses unexpected casing (snake_case where camelCase is expected), warn explicitly. These prevent the most common implementation errors.
|
|
271
|
+
|
|
272
|
+
4. **Complete code blocks when the component is foundational.** For theme files, config files, utility functions, and CSS — include the full source code in the plan. For application components — specify interface, behavior, and data binding; let the agent write the implementation.
|
|
273
|
+
|
|
274
|
+
## Remember
|
|
275
|
+
- Exact file paths always
|
|
276
|
+
- Complete code in plan (not "add validation")
|
|
277
|
+
- Exact commands with expected output
|
|
278
|
+
- Reference relevant skills with @ syntax
|
|
279
|
+
- DRY, YAGNI, TDD, frequent commits
|
|
280
|
+
- **Every phase MUST end with a numbered exit gate task** (e.g., "Task N.X: Exit Gate") that includes pass/fail checks, commit message format, and an explicit "STOP — do not proceed to next phase" instruction
|
|
281
|
+
- **Every phase/step must specify the executing agent and include a ready-to-use prompt with `═══ PROMPT START` / `═══ PROMPT END` markers**
|
|
282
|
+
- **Use 4-backtick fences (`` ```` ``) for the outer prompt block** so nested code blocks render correctly
|
|
283
|
+
- **After writing all phases, run the Cross-Reference Audit against ALL source documents**
|
|
284
|
+
- **Every plan MUST include a Manual Execution Protocol and Phase 0 — Context & Decisions**
|
|
285
|
+
- **Every UI phase MUST include data binding specs (exact JSON paths) per component**
|
|
286
|
+
- **Every data field that might be empty MUST have an explicit empty state message**
|
|
287
|
+
- **Drift rule: fix bugs from Phase N before starting Phase N+1**
|
|
288
|
+
|
|
289
|
+
## Cross-Reference Audit
|
|
290
|
+
|
|
291
|
+
**Run this AFTER all phases are written, BEFORE finalizing the plan.**
|
|
292
|
+
|
|
293
|
+
Walk through every FR, NFR, risk, and design decision from ALL input documents. For each, verify it maps to a specific, actionable plan step. Output a traceability matrix:
|
|
294
|
+
|
|
295
|
+
```markdown
|
|
296
|
+
## Source Document Traceability
|
|
297
|
+
|
|
298
|
+
| Requirement | Source | Plan Phase/Step | Status |
|
|
299
|
+
|-------------|--------|-----------------|--------|
|
|
300
|
+
| FR-101 | PRD §3.1 | Phase 1, Step 2 | ✅ Covered |
|
|
301
|
+
| NFR-208 | PRD §4.2 | Phase 5, Step 1 | ✅ Covered |
|
|
302
|
+
| Risk-003 | Arch §9 | Phase 3, Step 3 | ✅ Covered |
|
|
303
|
+
| ALT-002 | Arch §7.4 | N/A | ⚠️ Out of Scope — rationale: deferred to v2 |
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Rules:**
|
|
307
|
+
- A requirement without a plan step → add a step or mark "Out of Scope" with rationale
|
|
308
|
+
- A cited section reference (§N) → verify the section number matches the actual document
|
|
309
|
+
- Zero-tolerance: no unmapped requirements in a finalized plan
|
|
310
|
+
|
|
311
|
+
## Agent & Prompt Assignment
|
|
312
|
+
|
|
313
|
+
**Every phase/step MUST include a ready-to-use prompt block.** This is non-negotiable because plans are executed across multiple sessions by different agents.
|
|
314
|
+
|
|
315
|
+
### Prompt Block Template
|
|
316
|
+
|
|
317
|
+
> **CRITICAL**: Use 4-backtick fences (` ```` `) for the outer prompt block so nested code blocks (yaml, python, etc.) inside the prompt render correctly. Add `═══ PROMPT START` and `═══ PROMPT END` markers so users can clearly see where to copy from/to.
|
|
318
|
+
|
|
319
|
+
```markdown
|
|
320
|
+
### Ready-to-Use Prompt (Phase N — Step M)
|
|
321
|
+
|
|
322
|
+
> **How to use:** Copy the prompt block below (between ═══ START and ═══ END markers) into a new chat session. **Include all code blocks** — they're context for the agent, not for you to apply manually.
|
|
323
|
+
> **Agent:** `@{agent-name}` (see `.github/agents/{agent-name}.agent.md`)
|
|
324
|
+
> **Skills to load:** `.github/skills/{skill-path}/SKILL.md`
|
|
325
|
+
> **Instructions (auto-applied):** `{instruction1}.instructions.md`, `{instruction2}.instructions.md`
|
|
326
|
+
> **Project config:** `.github/project-config.md` (profile: `{profile}`)
|
|
327
|
+
|
|
328
|
+
> ═══ PROMPT START — Copy everything between START and END into a new chat ═══
|
|
329
|
+
|
|
330
|
+
\`\`\`\`
|
|
331
|
+
{One-sentence task description}
|
|
332
|
+
|
|
333
|
+
**Agent context:** You are the `@{agent-name}` agent. Load `.github/project-config.md` before starting.
|
|
334
|
+
|
|
335
|
+
**Read these files FIRST (in order):**
|
|
336
|
+
1. `.github/plans/{plan-file}.md` — **THIS PLAN** — read "Phase N — Step M"
|
|
337
|
+
2. {Architecture/PRD doc} — {specific sections}
|
|
338
|
+
3. {Target file(s)} — current state
|
|
339
|
+
|
|
340
|
+
**What to do:**
|
|
341
|
+
- {Actionable instruction 1}
|
|
342
|
+
- {Actionable instruction 2}
|
|
343
|
+
|
|
344
|
+
**Acceptance criteria:**
|
|
345
|
+
- {Testable criterion 1}
|
|
346
|
+
- {Testable criterion 2}
|
|
347
|
+
|
|
348
|
+
**Scope boundary:**
|
|
349
|
+
- Exit gate: Task N.X (the last task in this phase)
|
|
350
|
+
- Do NOT proceed to Phase N+1 after the exit gate passes
|
|
351
|
+
- Do NOT offer additional work beyond the exit gate tasks
|
|
352
|
+
- Commit with: `feat({feature}): Phase N — {description}` and STOP
|
|
353
|
+
\`\`\`\`
|
|
354
|
+
|
|
355
|
+
> ═══ PROMPT END ═══════════════════════════════════════════════════════════
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### Agent Selection Guide
|
|
359
|
+
|
|
360
|
+
| Task Type | Agent | Agent File |
|
|
361
|
+
|-----------|-------|------------|
|
|
362
|
+
| Models, services, logic | `@implement` | `implement.agent.md` |
|
|
363
|
+
| Streamlit UI, components | `@streamlit-developer` | `streamlit-developer.agent.md` |
|
|
364
|
+
| Tests, fixtures | `@tester` | `tester.agent.md` |
|
|
365
|
+
| SQL queries, schema | `@sql-expert` | `sql-expert.agent.md` |
|
|
366
|
+
| Docs, README | `@docs` | `docs.agent.md` |
|
|
367
|
+
| Code review | `@code-review` | `code-review.agent.md` |
|
|
368
|
+
|
|
369
|
+
## Execution Handoff
|
|
370
|
+
|
|
371
|
+
After saving the plan, offer execution choice:
|
|
372
|
+
|
|
373
|
+
**"Plan complete and saved to `.github/plans/<filename>.md`. Two execution options:**
|
|
374
|
+
|
|
375
|
+
**1. This session** — I implement each task sequentially, reviewing between tasks
|
|
376
|
+
|
|
377
|
+
**2. Separate session** — Open a new session with the `@implement` agent and provide the plan path
|
|
378
|
+
|
|
379
|
+
**Which approach?"**
|
|
380
|
+
|
|
381
|
+
**If separate session chosen:**
|
|
382
|
+
- Guide them to open new session
|
|
383
|
+
- Reference the `@implement` agent (`.github/agents/implement.agent.md`)
|
|
384
|
+
- Provide the plan file path for the implementing agent to read
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# caddis status line for Antigravity (agy). Shipped IN the agy plugin bundle (lands at
|
|
3
|
+
# ~/.gemini/config/plugins/caddis/statusline-command-agy.sh on install). Wire it once per machine in
|
|
4
|
+
# ~/.gemini/antigravity-cli/settings.json — use the SHORT bash path (agy runs the command via cmd.exe,
|
|
5
|
+
# where a bare `bash` is not on PATH and quoted spaced paths break):
|
|
6
|
+
# "statusLine": {"type":"command",
|
|
7
|
+
# "command":"C:\\PROGRA~1\\Git\\bin\\bash.exe ~/.gemini/config/plugins/caddis/statusline-command-agy.sh",
|
|
8
|
+
# "enabled":true}
|
|
9
|
+
# Reads agy's status JSON on stdin and prints one compact, colorized line, styled like the Claude Code
|
|
10
|
+
# status line (statusline-command.sh): dir · branch ±dirty · model · ctx% · mode · q%
|
|
11
|
+
# agy's payload field names differ from Claude Code's — this is a sibling, not a copy.
|
|
12
|
+
input=$(cat)
|
|
13
|
+
|
|
14
|
+
# Parse the agy status JSON via Python; emit shell var assignments to eval into scope.
|
|
15
|
+
eval "$(python -c '
|
|
16
|
+
import sys, json, shlex
|
|
17
|
+
try:
|
|
18
|
+
d = json.load(sys.stdin)
|
|
19
|
+
except Exception:
|
|
20
|
+
d = {}
|
|
21
|
+
def g(*keys):
|
|
22
|
+
v = d
|
|
23
|
+
for k in keys:
|
|
24
|
+
if not isinstance(v, dict): return ""
|
|
25
|
+
v = v.get(k)
|
|
26
|
+
if v is None or v is False or v == "": return ""
|
|
27
|
+
return str(v)
|
|
28
|
+
cwd = g("workspace","current_dir") or g("cwd")
|
|
29
|
+
branch = g("vcs","branch")
|
|
30
|
+
model = g("model","display_name") or g("model","id")
|
|
31
|
+
used_pct = g("context_window","used_percentage")
|
|
32
|
+
mode = g("execution_mode")
|
|
33
|
+
# quota: agy sends {name: {remaining_fraction, reset_time, ...}}. Show the BINDING (min-remaining) as a %.
|
|
34
|
+
quota_pct = ""
|
|
35
|
+
q = d.get("quota")
|
|
36
|
+
if isinstance(q, dict) and q:
|
|
37
|
+
fr = [v.get("remaining_fraction") for v in q.values()
|
|
38
|
+
if isinstance(v, dict) and isinstance(v.get("remaining_fraction"), (int, float))]
|
|
39
|
+
if fr:
|
|
40
|
+
quota_pct = str(int(round(min(fr) * 100)))
|
|
41
|
+
for name, val in [
|
|
42
|
+
("cwd",cwd),("branch",branch),("model",model),("used_pct",used_pct),("mode",mode),("quota_pct",quota_pct),
|
|
43
|
+
]:
|
|
44
|
+
print(f"{name}={shlex.quote(val)}")
|
|
45
|
+
' <<< "$input")"
|
|
46
|
+
|
|
47
|
+
# Fall back to git for branch when the payload omits it.
|
|
48
|
+
if [ -z "$branch" ] && [ -n "$cwd" ]; then
|
|
49
|
+
branch=$(git -C "$cwd" --no-optional-locks rev-parse --abbrev-ref HEAD 2>/dev/null || true)
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# Uncommitted-change count (time-to-commit signal), from git.
|
|
53
|
+
dirty=""
|
|
54
|
+
if [ -n "$cwd" ]; then
|
|
55
|
+
n=$(git -C "$cwd" --no-optional-locks status --porcelain 2>/dev/null | grep -c . || true)
|
|
56
|
+
[ -n "$n" ] && [ "$n" -gt 0 ] 2>/dev/null && dirty="$n"
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# Colors (ANSI).
|
|
60
|
+
C_DIM=$'\033[2m'; C_CYAN=$'\033[36m'; C_YEL=$'\033[33m'; C_RED=$'\033[31m'; C_GRN=$'\033[32m'; C_RST=$'\033[0m'
|
|
61
|
+
|
|
62
|
+
# Context %: green < 50, yellow < 80, red >= 80. (used_pct may be a float string.)
|
|
63
|
+
ctx_int="${used_pct%%.*}"; ctxcol="$C_GRN"
|
|
64
|
+
if [ -n "$ctx_int" ] 2>/dev/null; then
|
|
65
|
+
if [ "$ctx_int" -ge 80 ] 2>/dev/null; then ctxcol="$C_RED"
|
|
66
|
+
elif [ "$ctx_int" -ge 50 ] 2>/dev/null; then ctxcol="$C_YEL"; fi
|
|
67
|
+
fi
|
|
68
|
+
# Quota % REMAINING: red <= 15, yellow <= 40, else green.
|
|
69
|
+
qcol="$C_GRN"
|
|
70
|
+
if [ -n "$quota_pct" ] 2>/dev/null; then
|
|
71
|
+
if [ "$quota_pct" -le 15 ] 2>/dev/null; then qcol="$C_RED"
|
|
72
|
+
elif [ "$quota_pct" -le 40 ] 2>/dev/null; then qcol="$C_YEL"; fi
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
sep="${C_DIM} · ${C_RST}"
|
|
76
|
+
segs=()
|
|
77
|
+
[ -n "$cwd" ] && segs+=("${C_DIM}$(basename "$cwd")${C_RST}")
|
|
78
|
+
if [ -n "$branch" ]; then
|
|
79
|
+
b="${C_CYAN}${branch}${C_RST}"; [ -n "$dirty" ] && b="${b} ${C_YEL}±${dirty}${C_RST}"; segs+=("$b")
|
|
80
|
+
fi
|
|
81
|
+
[ -n "$model" ] && segs+=("$model")
|
|
82
|
+
[ -n "$ctx_int" ] && segs+=("${ctxcol}ctx ${ctx_int}%${C_RST}")
|
|
83
|
+
[ -n "$mode" ] && segs+=("${C_DIM}${mode}${C_RST}")
|
|
84
|
+
[ -n "$quota_pct" ] && segs+=("${qcol}q ${quota_pct}%${C_RST}")
|
|
85
|
+
|
|
86
|
+
out=""
|
|
87
|
+
for i in "${!segs[@]}"; do
|
|
88
|
+
[ "$i" -gt 0 ] && out="${out}${sep}"
|
|
89
|
+
out="${out}${segs[$i]}"
|
|
90
|
+
done
|
|
91
|
+
printf '%b' "$out"
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""caddis warm-start hook for agy (Antigravity) — PreInvocation event.
|
|
3
|
+
|
|
4
|
+
Ports the relay half of claude-harness/hooks/inject_relay.py. agy has NO SessionStart event, so the
|
|
5
|
+
nearest equivalent is PreInvocation with `invocationNum == 1` — the first model turn of a session.
|
|
6
|
+
On that turn only, the workspace's relay doc is injected as an ephemeral step so a fresh agy session
|
|
7
|
+
resumes with zero re-discovery. Every later invocation emits nothing (re-injecting the relay on every
|
|
8
|
+
turn would burn context and drown the conversation).
|
|
9
|
+
|
|
10
|
+
Self-contained (the agy bundle ships neither claude-harness/hooks/ nor scripts/), stdlib-only.
|
|
11
|
+
|
|
12
|
+
agy PreInvocation stdin (camelCase protojson):
|
|
13
|
+
{"invocationNum": 1, "initialNumSteps": N, "conversationId": "…", "workspacePaths": ["…"], …}
|
|
14
|
+
NOTE: cwd is the PLUGIN dir, not the workspace — the repo root comes from workspacePaths[0].
|
|
15
|
+
|
|
16
|
+
agy PreInvocation stdout:
|
|
17
|
+
{"injectSteps": [{"ephemeralMessage": "…"}]} — or nothing at all.
|
|
18
|
+
|
|
19
|
+
Fail open: any error, missing relay, or non-first invocation prints NOTHING and exits 0.
|
|
20
|
+
"""
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import json
|
|
24
|
+
import os
|
|
25
|
+
import subprocess
|
|
26
|
+
import sys
|
|
27
|
+
|
|
28
|
+
_ARTIFACT_DIRS = (".caddis", ".claudster")
|
|
29
|
+
|
|
30
|
+
INJECT_MAX_LINES = 120 # same budget as the Claude Code hook
|
|
31
|
+
INJECT_MAX_CHARS = 24000 # hard backstop: an ephemeralMessage should never be a context bomb
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _first_existing(paths: list[str]) -> str:
|
|
35
|
+
for p in paths:
|
|
36
|
+
try:
|
|
37
|
+
if os.path.isfile(p):
|
|
38
|
+
return p
|
|
39
|
+
except Exception:
|
|
40
|
+
continue
|
|
41
|
+
return ""
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _branch_slug(root: str) -> str:
|
|
45
|
+
"""Filesystem-safe current branch name, or "" when it can't be determined (best-effort)."""
|
|
46
|
+
try:
|
|
47
|
+
branch = subprocess.run(
|
|
48
|
+
["git", "-C", root, "rev-parse", "--abbrev-ref", "HEAD"],
|
|
49
|
+
capture_output=True, text=True, timeout=3,
|
|
50
|
+
).stdout.strip()
|
|
51
|
+
except Exception:
|
|
52
|
+
return ""
|
|
53
|
+
if not branch or branch == "HEAD":
|
|
54
|
+
return ""
|
|
55
|
+
return "".join(c if (c.isalnum() or c in "-_.") else "-" for c in branch)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def resolve_relay(root: str) -> str:
|
|
59
|
+
"""First existing relay doc for `root`, else "".
|
|
60
|
+
|
|
61
|
+
Preference order mirrors inject_relay.py:
|
|
62
|
+
1. <artifact-dir>/relay/<branch>.md (per-branch team mode — .caddis, then .claudster)
|
|
63
|
+
2. <artifact-dir>/relay.md (solo/default — .caddis, then .claudster)
|
|
64
|
+
3. .claude/relay/<branch>.md (legacy per-branch)
|
|
65
|
+
4. relay.md (legacy repo root)
|
|
66
|
+
"""
|
|
67
|
+
slug = _branch_slug(root)
|
|
68
|
+
candidates: list[str] = []
|
|
69
|
+
if slug:
|
|
70
|
+
candidates += [os.path.join(root, d, "relay", f"{slug}.md") for d in _ARTIFACT_DIRS]
|
|
71
|
+
candidates += [os.path.join(root, d, "relay.md") for d in _ARTIFACT_DIRS]
|
|
72
|
+
if slug:
|
|
73
|
+
candidates.append(os.path.join(root, ".claude", "relay", f"{slug}.md"))
|
|
74
|
+
candidates.append(os.path.join(root, "relay.md"))
|
|
75
|
+
return _first_existing(candidates)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def truncate_relay(text: str) -> str:
|
|
79
|
+
"""Cap the injected doc.
|
|
80
|
+
|
|
81
|
+
Line pass (from inject_relay.py): over INJECT_MAX_LINES, replace the unbounded `## Done` bullets
|
|
82
|
+
with a one-liner so `## Next step` / the resume prompt is never pushed off-screen; if the section
|
|
83
|
+
headers can't be found, keep the text as-is rather than lose data. Char pass: a hard tail-cut so a
|
|
84
|
+
pathological relay can't blow up the ephemeral message.
|
|
85
|
+
"""
|
|
86
|
+
lines = text.splitlines()
|
|
87
|
+
if len(lines) > INJECT_MAX_LINES:
|
|
88
|
+
done_idx = next_step_idx = read_first_idx = None
|
|
89
|
+
for i, line in enumerate(lines):
|
|
90
|
+
s = line.strip()
|
|
91
|
+
if done_idx is None and s.startswith("## Done"):
|
|
92
|
+
done_idx = i
|
|
93
|
+
elif next_step_idx is None and s.startswith("## Next step"):
|
|
94
|
+
next_step_idx = i
|
|
95
|
+
elif read_first_idx is None and s.startswith("## Read first on resume"):
|
|
96
|
+
read_first_idx = i
|
|
97
|
+
break
|
|
98
|
+
if done_idx is not None and next_step_idx is not None and read_first_idx is not None:
|
|
99
|
+
omitted = len([l for l in lines[done_idx + 1:next_step_idx] if l.strip().startswith("-")])
|
|
100
|
+
summary = f"- [Done section truncated — {omitted} bullets omitted to save context; see git log]"
|
|
101
|
+
text = "\n".join(lines[:done_idx + 1] + [summary, ""] + lines[next_step_idx:])
|
|
102
|
+
if len(text) > INJECT_MAX_CHARS:
|
|
103
|
+
text = text[:INJECT_MAX_CHARS] + "\n\n[…relay truncated — read the file for the rest]"
|
|
104
|
+
return text
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def main() -> None:
|
|
108
|
+
try:
|
|
109
|
+
_reconfig = getattr(sys.stdout, "reconfigure", None)
|
|
110
|
+
if _reconfig:
|
|
111
|
+
try:
|
|
112
|
+
_reconfig(encoding="utf-8")
|
|
113
|
+
except Exception:
|
|
114
|
+
pass
|
|
115
|
+
try:
|
|
116
|
+
data = json.load(sys.stdin)
|
|
117
|
+
except Exception:
|
|
118
|
+
return
|
|
119
|
+
if not isinstance(data, dict):
|
|
120
|
+
return
|
|
121
|
+
# SessionStart equivalent: the FIRST invocation only. Anything else (or an unparseable
|
|
122
|
+
# invocationNum) injects nothing.
|
|
123
|
+
try:
|
|
124
|
+
if int(data.get("invocationNum")) != 1:
|
|
125
|
+
return
|
|
126
|
+
except Exception:
|
|
127
|
+
return
|
|
128
|
+
workspaces = data.get("workspacePaths") or []
|
|
129
|
+
if not (isinstance(workspaces, list) and workspaces):
|
|
130
|
+
return
|
|
131
|
+
root = str(workspaces[0])
|
|
132
|
+
relay = resolve_relay(root)
|
|
133
|
+
if not relay:
|
|
134
|
+
return
|
|
135
|
+
text = open(relay, encoding="utf-8").read().strip()
|
|
136
|
+
if not text:
|
|
137
|
+
return
|
|
138
|
+
message = ("=== relay.md (session resume — read before acting) ===\n\n"
|
|
139
|
+
+ truncate_relay(text))
|
|
140
|
+
payload = json.dumps({"injectSteps": [{"ephemeralMessage": message}]})
|
|
141
|
+
sys.stdout.write(payload)
|
|
142
|
+
except Exception:
|
|
143
|
+
return # fail open: no injection is always better than a broken invocation
|
|
144
|
+
finally:
|
|
145
|
+
sys.exit(0)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
if __name__ == "__main__":
|
|
149
|
+
main()
|