@reservine/dx 1.0.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.
@@ -0,0 +1,244 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Reservine-DX — Angular Frontend Worktree Setup
4
+ #
5
+ # Sets up a git worktree for the Reservine Angular frontend:
6
+ # - Symlinks (or copies) node_modules from the main repo
7
+ # - Copies SSL certs for the dev server
8
+ # - Copies proxy.conf.json for backend API proxying
9
+ # - Copies .env / .env.local
10
+ # - Suggests a dev server port (main uses 1111)
11
+ #
12
+ # Usage:
13
+ # ./setup-worktree-fe.sh [OPTIONS]
14
+ #
15
+ # Options:
16
+ # --plan=<name> Search .claude/plans/ for matching file, extract branch name
17
+ # --branch=<name> Create and checkout this branch
18
+ # --base=<branch> Base branch for PR (default: main)
19
+ # --no-dep-link Run bun install instead of symlinking node_modules
20
+ # -h, --help Show this help message
21
+ #
22
+
23
+ set -euo pipefail
24
+
25
+ # Source shared core
26
+ SCRIPTS_DIR="$(cd "$(dirname "$0")" && pwd)"
27
+ source "$SCRIPTS_DIR/_core.sh"
28
+
29
+ # ─── Defaults ───────────────────────────────────────────────────────────────────
30
+
31
+ DEP_LINK=true
32
+ BRANCH_NAME=""
33
+ BASE_BRANCH="main"
34
+ PLAN_PATTERN=""
35
+
36
+ # ─── Help ───────────────────────────────────────────────────────────────────────
37
+
38
+ show_help() {
39
+ cat << 'EOF'
40
+ Reservine-DX — Angular Frontend Worktree Setup
41
+
42
+ Usage: ./setup-worktree-fe.sh [OPTIONS]
43
+
44
+ Options:
45
+ --plan=<name> Search .claude/plans/ for matching file, extract branch name
46
+ --branch=<name> Create and checkout this branch
47
+ --base=<branch> Base branch for PR validation (default: main)
48
+ --no-dep-link Run bun install instead of symlinking node_modules
49
+ -h, --help Show this help message
50
+
51
+ Environment Variables:
52
+ ROOT_WORKTREE_PATH Path to main repo (auto-detected from git worktree list)
53
+
54
+ Examples:
55
+ # Simple setup — auto-detects everything
56
+ ./setup-worktree-fe.sh
57
+
58
+ # Setup with explicit branch
59
+ ./setup-worktree-fe.sh --branch=feat/my-feature
60
+
61
+ # Install node_modules instead of symlinking
62
+ ./setup-worktree-fe.sh --no-dep-link
63
+
64
+ # Setup from a plan file
65
+ ./setup-worktree-fe.sh --plan=seo-configurator
66
+ EOF
67
+ }
68
+
69
+ # ─── Parse arguments ────────────────────────────────────────────────────────────
70
+
71
+ while [[ $# -gt 0 ]]; do
72
+ case $1 in
73
+ --plan=*) PLAN_PATTERN="${1#*=}"; shift ;;
74
+ --branch=*) BRANCH_NAME="${1#*=}"; shift ;;
75
+ --base=*) BASE_BRANCH="${1#*=}"; shift ;;
76
+ --no-dep-link) DEP_LINK=false; shift ;;
77
+ --log) LOG_FILE="$(pwd)/setup.log"; shift ;;
78
+ --log=*) LOG_FILE="${1#*=}"; shift ;;
79
+ -h|--help) show_help; exit 0 ;;
80
+ *) error "Unknown option: $1"; show_help; exit 1 ;;
81
+ esac
82
+ done
83
+
84
+ init_log "$@"
85
+
86
+ # ─── Plan resolution ────────────────────────────────────────────────────────────
87
+
88
+ if [[ -n "$PLAN_PATTERN" ]]; then
89
+ resolve_plan_file "$PLAN_PATTERN"
90
+ fi
91
+
92
+ # ─── Pre-flight ─────────────────────────────────────────────────────────────────
93
+
94
+ resolve_root_worktree_path
95
+ preflight_check
96
+
97
+ info "Stack: Angular (bun)"
98
+
99
+ # ─── Branch setup ────────────────────────────────────────────────────────────────
100
+
101
+ if [[ -n "$BRANCH_NAME" ]]; then
102
+ setup_branch "$BRANCH_NAME" "$BASE_BRANCH"
103
+ fi
104
+
105
+ # ─── Environment setup ──────────────────────────────────────────────────────────
106
+
107
+ if [[ "$IS_CLOUD" == true ]]; then
108
+ info "Cloud environment — skipping local setup"
109
+ else
110
+ echo "⚙️ Angular Environment Setup"
111
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
112
+
113
+ # ── node_modules ──
114
+
115
+ if [[ "$DEP_LINK" == true ]]; then
116
+ if [[ -d "node_modules" ]] && [[ ! -L "node_modules" ]]; then
117
+ warn "node_modules/ is a directory — removing to create symlink"
118
+ rm -rf node_modules
119
+ fi
120
+
121
+ if [[ -L "node_modules" ]]; then
122
+ info "node_modules/ symlink already exists → $(readlink node_modules)"
123
+ elif [[ -d "${ROOT_WORKTREE_PATH}/node_modules" ]]; then
124
+ ln -s "${ROOT_WORKTREE_PATH}/node_modules" node_modules
125
+ success "Symlinked node_modules/ → main repo"
126
+ else
127
+ warn "Main repo has no node_modules/ — running bun install"
128
+ bun install
129
+ success "Installed node_modules/"
130
+ fi
131
+ else
132
+ if [[ -d "node_modules" ]] && [[ ! -L "node_modules" ]]; then
133
+ info "node_modules/ directory already exists (local copy)"
134
+ else
135
+ [[ -L "node_modules" ]] && rm node_modules
136
+ if [[ -d "${ROOT_WORKTREE_PATH}/node_modules" ]]; then
137
+ info "Copying node_modules/ from main repo (this may take a moment)..."
138
+ cp -R "${ROOT_WORKTREE_PATH}/node_modules" node_modules
139
+ success "Copied node_modules/ (local copy)"
140
+ else
141
+ bun install
142
+ success "Installed node_modules/"
143
+ fi
144
+ fi
145
+ fi
146
+
147
+ # ── SSL certs ──
148
+
149
+ for cert in localhost.pem localhost-key.pem; do
150
+ if [[ ! -f "$cert" ]] && [[ -f "${ROOT_WORKTREE_PATH}/$cert" ]]; then
151
+ cp "${ROOT_WORKTREE_PATH}/$cert" .
152
+ success "Copied $cert"
153
+ fi
154
+ done
155
+
156
+ # ── proxy.conf.json ──
157
+ # Priority: 1) already exists (generated by BE --isolated), 2) detect running BE stack, 3) copy from main
158
+
159
+ if [[ -f "proxy.conf.json" ]]; then
160
+ info "proxy.conf.json already exists (generated by BE --isolated)"
161
+ else
162
+ # Check if a BE isolated stack is running for this branch
163
+ BRANCH_SLUG=$(get_branch_slug)
164
+ BE_APP_PORT=$(docker ps --filter "name=wt-${BRANCH_SLUG}-app" --format "{{.Ports}}" 2>/dev/null \
165
+ | grep -oE '0\.0\.0\.0:[0-9]+->80' | head -1 | cut -d: -f2 | cut -d- -f1)
166
+ if [[ -n "$BE_APP_PORT" ]]; then
167
+ cat > proxy.conf.json <<PROXY_EOF
168
+ {
169
+ "/api": { "target": "http://localhost:${BE_APP_PORT}", "secure": false, "changeOrigin": true },
170
+ "/sanctum": { "target": "http://localhost:${BE_APP_PORT}", "secure": false, "changeOrigin": true }
171
+ }
172
+ PROXY_EOF
173
+ success "Generated proxy.conf.json → isolated BE on :${BE_APP_PORT}"
174
+ elif [[ -f "${ROOT_WORKTREE_PATH}/proxy.conf.json" ]]; then
175
+ cp "${ROOT_WORKTREE_PATH}/proxy.conf.json" .
176
+ success "Copied proxy.conf.json from main repo"
177
+ fi
178
+ fi
179
+
180
+ # ── .env files ──
181
+
182
+ for envfile in .env .env.local; do
183
+ if [[ ! -f "$envfile" ]] && [[ -f "${ROOT_WORKTREE_PATH}/$envfile" ]]; then
184
+ cp "${ROOT_WORKTREE_PATH}/$envfile" .
185
+ success "Copied $envfile"
186
+ fi
187
+ done
188
+
189
+ # ── .claude/config.local ──
190
+
191
+ if [[ ! -f ".claude/config.local" ]] && [[ -f "${ROOT_WORKTREE_PATH}/.claude/config.local" ]]; then
192
+ mkdir -p .claude
193
+ cp "${ROOT_WORKTREE_PATH}/.claude/config.local" .claude/config.local
194
+ success "Copied .claude/config.local"
195
+ fi
196
+
197
+ echo ""
198
+ fi
199
+
200
+ # ─── Final output ───────────────────────────────────────────────────────────────
201
+
202
+ echo "✨ Worktree setup complete!"
203
+ echo ""
204
+
205
+ if [[ "$IS_CLOUD" == false ]]; then
206
+ # Find first free port in the worktree range (main uses 1111)
207
+ SUGGESTED_PORT=""
208
+ for port in 4200 4201 4202 4203 4204 4205; do
209
+ if ! port_in_use "$port"; then
210
+ SUGGESTED_PORT=$port
211
+ break
212
+ fi
213
+ done
214
+ SUGGESTED_PORT=${SUGGESTED_PORT:-4200} # fallback if all in use
215
+
216
+ # Write worktree port to config.local so Playwright MCP can auto-connect
217
+ mkdir -p .claude
218
+ if grep -q "^MCP_WORKTREE_PORT=" .claude/config.local 2>/dev/null; then
219
+ sed -i.bak "s/^MCP_WORKTREE_PORT=.*/MCP_WORKTREE_PORT=$SUGGESTED_PORT/" .claude/config.local
220
+ rm -f .claude/config.local.bak
221
+ else
222
+ echo "" >> .claude/config.local 2>/dev/null || true
223
+ echo "# Worktree dev server port (auto-detected by setup script)" >> .claude/config.local
224
+ echo "MCP_WORKTREE_PORT=$SUGGESTED_PORT" >> .claude/config.local
225
+ fi
226
+ success "Set MCP_WORKTREE_PORT=$SUGGESTED_PORT in .claude/config.local"
227
+
228
+ echo "📦 Angular Worktree Ready"
229
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
230
+ echo ""
231
+ echo " Start dev server (main uses port 1111):"
232
+ echo " nx serve reservine --port $SUGGESTED_PORT"
233
+ echo ""
234
+ echo " With SSL:"
235
+ echo " nx serve reservine --port $SUGGESTED_PORT --ssl"
236
+ echo ""
237
+ if [[ -f "proxy.conf.json" ]]; then
238
+ echo " With local backend proxy:"
239
+ echo " nx serve reservine --port $SUGGESTED_PORT --proxy-config=proxy.conf.json"
240
+ echo ""
241
+ fi
242
+ fi
243
+
244
+ print_state "node_modules" "$BRANCH_NAME"
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Reservine-DX — Worktree Setup (entry point)
4
+ #
5
+ # Auto-detects the current stack (Angular or Laravel) and delegates to the
6
+ # appropriate stack-specific setup script.
7
+ #
8
+ # Usage:
9
+ # ./setup-worktree.sh [OPTIONS]
10
+ #
11
+ # The script will detect:
12
+ # - angular.json / nx.json → runs setup-worktree-fe.sh
13
+ # - artisan / composer.json → runs setup-worktree-be.sh
14
+ #
15
+ # All options are forwarded to the stack-specific script.
16
+ # See setup-worktree-fe.sh --help or setup-worktree-be.sh --help for details.
17
+ #
18
+
19
+ set -euo pipefail
20
+
21
+ SCRIPTS_DIR="$(cd "$(dirname "$0")" && pwd)"
22
+
23
+ # Quick help
24
+ if [[ "${1:-}" == "-h" ]] || [[ "${1:-}" == "--help" ]]; then
25
+ cat << 'EOF'
26
+ Reservine-DX — Worktree Setup
27
+
28
+ Auto-detects the stack and runs the appropriate setup script.
29
+
30
+ Usage: ./setup-worktree.sh [OPTIONS]
31
+
32
+ Stack detection:
33
+ angular.json / nx.json → Angular (setup-worktree-fe.sh)
34
+ artisan / composer.json → Laravel (setup-worktree-be.sh)
35
+
36
+ You can also call the stack-specific script directly:
37
+ ./setup-worktree-fe.sh [OPTIONS]
38
+ ./setup-worktree-be.sh [OPTIONS]
39
+
40
+ Run with --help on a specific script for its options:
41
+ ./setup-worktree-fe.sh --help
42
+ ./setup-worktree-be.sh --help
43
+ EOF
44
+ exit 0
45
+ fi
46
+
47
+ # Detect stack
48
+ if [[ -f "angular.json" ]] || [[ -f "nx.json" ]]; then
49
+ exec "$SCRIPTS_DIR/setup-worktree-fe.sh" "$@"
50
+ elif [[ -f "artisan" ]] || [[ -f "composer.json" ]]; then
51
+ exec "$SCRIPTS_DIR/setup-worktree-be.sh" "$@"
52
+ else
53
+ echo "❌ Could not detect stack (no angular.json, nx.json, artisan, or composer.json found)" >&2
54
+ echo "" >&2
55
+ echo " Run the stack-specific script directly:" >&2
56
+ echo " $SCRIPTS_DIR/setup-worktree-fe.sh [OPTIONS] # Angular" >&2
57
+ echo " $SCRIPTS_DIR/setup-worktree-be.sh [OPTIONS] # Laravel" >&2
58
+ exit 1
59
+ fi
@@ -0,0 +1,339 @@
1
+ ---
2
+ name: reservine-dx:cross-plan
3
+ description: >
4
+ Create an intent file and linked GitHub issue in the sibling repo when a feature requires
5
+ cross-repo changes. Auto-detects direction (FE→BE or BE→FE) and creates the appropriate
6
+ intent file template with skill references, GitHub issue tracking, sub-issue linking,
7
+ and milestone sync. Works from either repo.
8
+ Triggers: "cross-plan", "create intent file", "needs backend/frontend changes".
9
+ argument-hint: [feature description]
10
+ allowed-tools:
11
+ - Read
12
+ - Write
13
+ - Bash
14
+ - AskUserQuestion
15
+ ---
16
+
17
+ # Cross-Project Plan (Bidirectional)
18
+
19
+ Create an intent file and linked GitHub issue in the sibling repo when a feature requires
20
+ cross-repo changes. Auto-detects whether you're in the FE or BE repo and creates the
21
+ appropriate direction-specific artifacts.
22
+
23
+ ## Step 1: Gather Context & Detect Direction
24
+
25
+ Read the project config to resolve paths and repo identifiers:
26
+
27
+ ```bash
28
+ cat .claude/config 2>/dev/null
29
+ cat .claude/config.local 2>/dev/null
30
+ ```
31
+
32
+ **Auto-detect direction:**
33
+
34
+ ```bash
35
+ if [[ -f "angular.json" ]] || [[ -f "nx.json" ]]; then
36
+ DIRECTION="FE_TO_BE"
37
+ CURRENT_REPO="FE"
38
+ CURRENT_GITHUB_REPO=$GITHUB_REPO # from .claude/config
39
+ TARGET_DIR=$(grep 'BACKEND_DIR' .claude/config | cut -d= -f2)
40
+ TARGET_DIR_ABS=$(grep 'BACKEND_DIR_ABSOLUTE' .claude/config.local 2>/dev/null | cut -d= -f2)
41
+ [[ -n "$TARGET_DIR_ABS" ]] && TARGET_DIR="$TARGET_DIR_ABS"
42
+ else
43
+ DIRECTION="BE_TO_FE"
44
+ CURRENT_REPO="BE"
45
+ CURRENT_GITHUB_REPO=$GITHUB_REPO
46
+ TARGET_DIR=$(grep 'FRONTEND_DIR' .claude/config | cut -d= -f2)
47
+ TARGET_DIR_ABS=$(grep 'FRONTEND_DIR_ABSOLUTE' .claude/config.local 2>/dev/null | cut -d= -f2)
48
+ [[ -n "$TARGET_DIR_ABS" ]] && TARGET_DIR="$TARGET_DIR_ABS"
49
+ fi
50
+ ```
51
+
52
+ Then read the target repo config:
53
+ ```bash
54
+ cat $TARGET_DIR/.claude/config 2>/dev/null
55
+ ```
56
+ Extract `GITHUB_REPO` from the target config → `TARGET_GITHUB_REPO`.
57
+
58
+ **Fallback defaults:**
59
+ - FE repo: `LEFTEQ/reservine`
60
+ - BE repo: `genesiscz/ReservineBack`
61
+
62
+ ### Resolve current issue number
63
+
64
+ Look for the current issue number from these sources (in priority order):
65
+ 1. Conversation context — if working on an issue (e.g., `implement-plan` invoked with `#259`)
66
+ 2. Current branch name — extract issue number from patterns like `feat/social-login-259`
67
+ 3. If no issue is found, proceed without cross-linking (intent file + standalone issue)
68
+
69
+ ### Resolve feature name
70
+
71
+ If `$ARGUMENTS` is provided, use it as the feature description. Otherwise, infer from conversation context or ask the user:
72
+
73
+ 1. **Feature name** — short kebab-case identifier (e.g., `sms-confirmation-toggle`)
74
+ 2. **What the target repo needs to do** — endpoints/pages, data changes, components
75
+ 3. **Why** — business context
76
+
77
+ ## Step 2: Write the Intent File
78
+
79
+ Create the file at: `<TARGET_DIR>/.claude/plans/future/<feature>.intent.md`
80
+
81
+ ### FE→BE template (API-focused)
82
+
83
+ ```markdown
84
+ # <Feature Name> — Intent
85
+
86
+ > **Auto-invoke these skills when starting work on this plan:**
87
+ > 1. `/reservine-dx:implement-plan` — full end-to-end implementation orchestrator (worktree, tests, PR)
88
+ > 2. `/reservine:api` — API endpoint implementation patterns (migration, model, service, controller, routes, tests)
89
+
90
+ ## What we need
91
+ <Business-level description of what the backend must provide>
92
+
93
+ ## API changes needed
94
+ <Endpoints to add/modify, request/response shapes, HTTP methods>
95
+
96
+ ## Permissions & authorization
97
+ <Required roles, new permissions, middleware considerations>
98
+
99
+ ## Why
100
+ <Business context — why this change matters>
101
+
102
+ ## FE context
103
+ <What the frontend is doing, which components/services will consume the API>
104
+
105
+ ## Data shape expected by FE
106
+ <TypeScript interfaces or JSON examples the frontend expects>
107
+
108
+ ## Tracking
109
+ - FE issue: <FE_GITHUB_REPO>#<current-issue>
110
+ - BE issue: <BE_GITHUB_REPO>#<be-issue>
111
+ ```
112
+
113
+ ### BE→FE template (UI-focused)
114
+
115
+ ```markdown
116
+ # <Feature Name> — Intent
117
+
118
+ > **Auto-invoke these skills when starting work on this plan:**
119
+ > 1. `/reservine-dx:implement-plan` — full end-to-end implementation orchestrator (design critique, questionnaire, worktree, E2E tests, PR)
120
+ > 2. `/reservine:design` — UI design & component composition
121
+ > 3. `/reservine:play` — Playwright MCP browser tools for E2E testing
122
+ > 4. _(optional, when creating/modifying forms)_ `/reservine:form-builder`
123
+
124
+ ## What we need
125
+ <Business-level description of what the frontend must provide>
126
+
127
+ ## UI changes needed
128
+ <Pages/components to add/modify, expected UX flow>
129
+
130
+ ## Data shape from BE
131
+ <What the API returns — response format, TypeScript types, endpoint paths>
132
+
133
+ ## Why
134
+ <Business context — why this change matters>
135
+
136
+ ## BE context
137
+ <What the backend is doing, which endpoints are available, auth requirements>
138
+
139
+ ## Tracking
140
+ - FE issue: <FE_GITHUB_REPO>#<fe-issue>
141
+ - BE issue: <BE_GITHUB_REPO>#<current-issue>
142
+ ```
143
+
144
+ **Note:** The `## Tracking` section uses placeholders initially — update it after the target issue is created (Step 3).
145
+
146
+ ## Step 3: Create Target GitHub Issue
147
+
148
+ Create a GitHub issue in the target repo for tracking implementation:
149
+
150
+ ### FE→BE: Create BE issue
151
+
152
+ ```bash
153
+ TARGET_ISSUE_URL=$(gh issue create --repo $TARGET_GITHUB_REPO \
154
+ --title "<Feature Title> — Backend" \
155
+ --body "$(cat <<'EOF'
156
+ - [ ] @LEFTEQ read this
157
+ - [ ] @genesiscz read this
158
+
159
+ ---
160
+
161
+ ## Summary
162
+ <1-3 sentence business-level summary from intent file>
163
+
164
+ ## Intent File
165
+ Implementation plan: `<relative-path-to-intent-file>`
166
+
167
+ > Open a session in the BE repo and run:
168
+ > `Implement the feature described in <absolute-path-to-intent-file>`
169
+
170
+ ## FE Reference
171
+ Frontend implementation: <FE_GITHUB_REPO>#<current-issue>
172
+ EOF
173
+ )")
174
+ ```
175
+
176
+ ### BE→FE: Create FE issue
177
+
178
+ ```bash
179
+ TARGET_ISSUE_URL=$(gh issue create --repo $TARGET_GITHUB_REPO \
180
+ --title "<Feature Title>" \
181
+ --body "$(cat <<'EOF'
182
+ - [ ] @LEFTEQ read this
183
+ - [ ] @genesiscz read this
184
+
185
+ ---
186
+
187
+ ## Summary
188
+ <1-3 sentence business-level summary from intent file>
189
+
190
+ ## Intent File
191
+ Implementation plan: `<relative-path-to-intent-file>`
192
+
193
+ > Open a session in the FE repo and run:
194
+ > `Implement the feature described in <absolute-path-to-intent-file>`
195
+
196
+ ## BE Reference
197
+ Backend implementation: <BE_GITHUB_REPO>#<current-issue>
198
+ EOF
199
+ )")
200
+ ```
201
+
202
+ Extract the target issue number from the returned URL.
203
+
204
+ ### Milestone sync
205
+
206
+ If the current issue has a milestone, apply the same milestone to the target issue:
207
+
208
+ ```bash
209
+ MILESTONE=$(gh issue view <current-issue> --repo $CURRENT_GITHUB_REPO --json milestone --jq '.milestone.title // empty')
210
+ if [[ -n "$MILESTONE" ]]; then
211
+ gh issue edit <target-issue> --repo $TARGET_GITHUB_REPO --milestone "$MILESTONE"
212
+ fi
213
+ ```
214
+
215
+ ### Apply label
216
+
217
+ ```bash
218
+ gh issue edit <target-issue> --repo $TARGET_GITHUB_REPO --add-label "status:planning" 2>/dev/null || true
219
+ ```
220
+
221
+ ### Update intent file tracking section
222
+
223
+ Now that the target issue number is known, update the `## Tracking` section in the intent file
224
+ with the actual issue numbers.
225
+
226
+ ## Step 4: Link Issues
227
+
228
+ ### Sub-issue linking (FE = parent, BE = child)
229
+
230
+ Determine which is the FE issue and which is the BE issue:
231
+ - **FE→BE**: FE issue = `<current-issue>` in `FE_GITHUB_REPO`, BE issue = `<target-issue>` in `BE_GITHUB_REPO`
232
+ - **BE→FE**: FE issue = `<target-issue>` in `FE_GITHUB_REPO`, BE issue = `<current-issue>` in `BE_GITHUB_REPO`
233
+
234
+ FE is always the parent:
235
+
236
+ ```bash
237
+ # Get FE issue node ID
238
+ FE_OWNER=$(echo $FE_GITHUB_REPO | cut -d/ -f1)
239
+ FE_NAME=$(echo $FE_GITHUB_REPO | cut -d/ -f2)
240
+ FE_NODE_ID=$(gh api graphql -f query='
241
+ { repository(owner:"'"$FE_OWNER"'", name:"'"$FE_NAME"'") {
242
+ issue(number:<fe-issue>) { id }
243
+ } }' --jq '.data.repository.issue.id')
244
+
245
+ # Get BE issue node ID
246
+ BE_OWNER=$(echo $BE_GITHUB_REPO | cut -d/ -f1)
247
+ BE_NAME=$(echo $BE_GITHUB_REPO | cut -d/ -f2)
248
+ BE_NODE_ID=$(gh api graphql -f query='
249
+ { repository(owner:"'"$BE_OWNER"'", name:"'"$BE_NAME"'") {
250
+ issue(number:<be-issue>) { id }
251
+ } }' --jq '.data.repository.issue.id')
252
+
253
+ # Add BE as sub-issue of FE
254
+ gh api graphql -f query='
255
+ mutation {
256
+ addSubIssue(input: {
257
+ issueId: "'"$FE_NODE_ID"'"
258
+ subIssueId: "'"$BE_NODE_ID"'"
259
+ }) {
260
+ issue { id }
261
+ subIssue { id }
262
+ }
263
+ }'
264
+ ```
265
+
266
+ If the sub-issue API fails (feature not available), fall back to cross-reference comments only.
267
+
268
+ ### Cross-reference comments
269
+
270
+ ```bash
271
+ # On current repo issue
272
+ gh issue comment <current-issue> --repo $CURRENT_GITHUB_REPO \
273
+ --body "**Target Issue:** $TARGET_GITHUB_REPO#<target-issue>
274
+ Frontend implementation tracked here. Intent file: \`<path-to-intent-file>\`"
275
+
276
+ # On target repo issue
277
+ gh issue comment <target-issue> --repo $TARGET_GITHUB_REPO \
278
+ --body "**Source Issue:** $CURRENT_GITHUB_REPO#<current-issue>
279
+ Linked as sub-issue for implementation tracking."
280
+ ```
281
+
282
+ ### No current issue available
283
+
284
+ If no current issue was found in Step 1:
285
+ - Skip sub-issue linking entirely
286
+ - Skip cross-reference comments
287
+ - Create the target issue without the reference section
288
+ - Note in the output that no source issue was linked
289
+
290
+ ## Step 5: Plan Directory Structure
291
+
292
+ The target repo uses this directory layout:
293
+
294
+ ```
295
+ .claude/plans/
296
+ ├── future/ # ← you write here
297
+ │ └── <feature>.intent.md
298
+ ├── active/ # ← receiving AI moves here when starting work
299
+ │ └── <feature>/
300
+ │ ├── <feature>.intent.md
301
+ │ └── <feature>.technical.md
302
+ └── finished/ # ← after implementation
303
+ └── <feature>/
304
+ ```
305
+
306
+ ## Step 6: Output the Handoff
307
+
308
+ After writing the intent file and creating/linking issues, output this EXACT format (replace placeholders):
309
+
310
+ ---
311
+
312
+ **Cross-plan ready.**
313
+
314
+ Target issue created: `<TARGET_GITHUB_REPO>#<target-issue>` — <link-to-target-issue>
315
+ Linked to source issue: `<CURRENT_GITHUB_REPO>#<current-issue>`
316
+
317
+ Intent file written to:
318
+ `<full absolute path to the intent file>`
319
+
320
+ Open a new session in **<target repo name>** and paste:
321
+
322
+ ```
323
+ Implement the feature described in <full absolute path to intent file>. Read the intent file — it contains the requirements and lists which skills to auto-invoke before writing code. Create a technical plan first, then implement.
324
+ ```
325
+
326
+ ---
327
+
328
+ If no source issue was linked, replace the "Linked to" line with:
329
+ `No source issue linked (not detected in conversation context).`
330
+
331
+ ## Rules
332
+
333
+ - Intent files are **business-level** — describe WHAT is needed, not HOW to build it
334
+ - Never write implementation details in the intent file — that's the receiving repo's job
335
+ - Always create the target GitHub issue — it's the tracking ticket for the cross-repo work
336
+ - Always attempt to link issues when a source issue number is available
337
+ - FE is always the parent in sub-issue relationships
338
+ - Always use the exact handoff format above — the user copies it into the next session
339
+ - The receiving AI reads the intent file, invokes the listed skills, and handles the rest