@erclx/aitk 0.89.0 → 0.89.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/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/claude-orchestrate/SKILL.md +5 -3
- package/claude/skills/claude-worktree/REQUIREMENT.md +8 -0
- package/claude/skills/claude-worktree/SKILL.md +22 -0
- package/docs/operating-model.md +4 -2
- package/package.json +1 -1
- package/tooling/astro/configs/astro.config.mjs +11 -0
- package/tooling/astro/configs/playwright.config.ts +4 -3
- package/tooling/astro/manifest.toml +5 -3
- package/tooling/astro/reference.md +3 -3
- package/tooling/vite-react/configs/playwright.config.ts +4 -3
- package/tooling/vite-react/configs/vite.config.ts +10 -0
- package/tooling/vite-react/manifest.toml +4 -2
- package/tooling/vite-react/reference.md +4 -4
- package/tooling/web/configs/scripts/worktree-port.sh +36 -0
- package/tooling/web/manifest.toml +3 -3
- package/tooling/web/reference.md +12 -0
|
@@ -196,6 +196,8 @@ properly and stop when you cannot.
|
|
|
196
196
|
Serialize any track that touches a shared wiring seam with another in flight.
|
|
197
197
|
Merge the branch with the smallest shared-file footprint first, and merge a
|
|
198
198
|
branch touching `CLAUDE.md`, a Claude context entry, or a regenerated `index.md`
|
|
199
|
-
last. Have every sibling rebase on the new `main` before the next merge.
|
|
200
|
-
a
|
|
201
|
-
|
|
199
|
+
last. Have every sibling rebase on the new `main` before the next merge. Two
|
|
200
|
+
workers running a server take a port apiece without being told to, since a
|
|
201
|
+
stack derives it from the worktree it runs in through `scripts/worktree-port.sh`.
|
|
202
|
+
Read that value rather than assigning one, and set `WORKTREE_PORT_OFFSET` by
|
|
203
|
+
hand only when two worktrees derive the same offset.
|
|
@@ -11,6 +11,10 @@ Without this skill, the user names the worktree by hand, and a name matching no
|
|
|
11
11
|
|
|
12
12
|
Entry also writes the bare flag into the shared config, which strands the main worktree. Every command run there fails while the files sit untouched on disk, and the linked worktree keeps working, so nothing surfaces until the operator returns to the main checkout and finds the repository broken. A rename onto a branch that already exists is the third failure, and it is the one that destroys work rather than blocking it.
|
|
13
13
|
|
|
14
|
+
The tree the entry hands over is also not one the session can run. Dependencies live in a folder git ignores and never shares between working directories, so a fresh worktree arrives with none, and nothing on the entry path says so. The session finds out from whichever command needs them first, and the message it gets names a missing module rather than an empty working directory.
|
|
15
|
+
|
|
16
|
+
A stack that derives its ports from the working directory has the same shape. The number is correct and invisible, and `claude-orchestrate` sends a reader here to read it rather than assign one, so the entry that knows the working directory is the surface that owes it.
|
|
17
|
+
|
|
14
18
|
## Must
|
|
15
19
|
|
|
16
20
|
- Derive the name from the plan matched to the current branch, falling through the ordered sources rather than picking
|
|
@@ -21,9 +25,13 @@ Entry also writes the bare flag into the shared config, which strands the main w
|
|
|
21
25
|
- Test the target branch and the target directory before entering, so a stop costs no worktree
|
|
22
26
|
- Read the bare flag before writing it, and repair it on both sides of entry
|
|
23
27
|
- Announce the repair only when a write actually happened
|
|
28
|
+
- Report on one line whether the entered worktree carries its dependencies, naming the command that installs them when it does not
|
|
29
|
+
- Report the same way when the project declares no package manifest, since silence there reads as a passing check
|
|
30
|
+
- Report the port offset this worktree derives, and say so when the project installs no derivation
|
|
24
31
|
|
|
25
32
|
## Must not
|
|
26
33
|
|
|
34
|
+
- Install dependencies on the session's behalf. Entering a worktree to read is as common as entering one to run, and an install is slow and needs a network.
|
|
27
35
|
- Pick between plans when more than one could match. Ask.
|
|
28
36
|
- Enter on a name inferred from session context without confirmation
|
|
29
37
|
- Delete or overwrite a branch or a worktree directory that already carries the target name
|
|
@@ -96,4 +96,26 @@ git config core.bare false
|
|
|
96
96
|
|
|
97
97
|
The flag is not set on every entry, so read before writing and announce only when the write happened. Tracked upstream as `anthropics/claude-code#58345`, closed as not planned, so the repair stays until the tool changes.
|
|
98
98
|
|
|
99
|
+
## Step 6: report whether the tree can run
|
|
100
|
+
|
|
101
|
+
A linked worktree is a second working directory over one repository, and every ecosystem installs its dependencies into a folder git ignores. Nothing copies that folder across, so a fresh worktree arrives without it and the session learns as much from whichever command needs it first, which reports a missing module rather than an empty working directory.
|
|
102
|
+
|
|
103
|
+
Report the state on one line. Do not install. Entering a worktree to read is as common as entering one to run, and an install is slow, needs a network, and picks an ecosystem on the session's behalf.
|
|
104
|
+
|
|
105
|
+
Read the worktree root and emit the first line that matches:
|
|
106
|
+
|
|
107
|
+
- `package.json` present, `node_modules/` missing: `Dependencies are not installed. Run <install> before any build, test, or server command.` Take `<install>` from the lockfile beside the manifest, and use `bun install` when no lockfile names one.
|
|
108
|
+
- A `pyproject.toml` or `requirements.txt` present, `.venv/` missing: `No virtual environment. Create and populate one before running anything.`
|
|
109
|
+
- A manifest present with its folder alongside it: `Dependencies are installed.`
|
|
110
|
+
- No package manifest of either kind: `No package manifest, so there is nothing to install.`
|
|
111
|
+
|
|
112
|
+
The last line is what keeps the step honest on a stack this skill cannot read. Entry is not stack-aware, and silence is indistinguishable from a check that passed.
|
|
113
|
+
|
|
114
|
+
Then report the port this worktree derives, on a second line:
|
|
115
|
+
|
|
116
|
+
- `scripts/worktree-port.sh` present: run `bash scripts/worktree-port.sh` and emit `Port offset <n>. Every served port adds it to the stack default.`
|
|
117
|
+
- Absent: `No port derivation installed, so every served port is the stack default.`
|
|
118
|
+
|
|
119
|
+
The offset is what `claude-orchestrate` sends a reader here to read rather than assign, and what an operator overrides through `WORKTREE_PORT_OFFSET` when two worktrees derive the same value. Deriving it correctly and printing it nowhere leaves both instructions naming a number no surface emits.
|
|
120
|
+
|
|
99
121
|
Do not invoke `ExitWorktree` from this skill. Exit is the user's call.
|
package/docs/operating-model.md
CHANGED
|
@@ -125,8 +125,10 @@ at two or three worker tracks and split them across the stack so they do not
|
|
|
125
125
|
collide on the same files.
|
|
126
126
|
|
|
127
127
|
Unit checks run freely in many worktrees at once.
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
A dev server, an end-to-end run, and a screenshot run alongside each other on a
|
|
129
|
+
web stack, since every worktree derives its own port. Singleton resources (one
|
|
130
|
+
local model server, one GPU) still serialize, as does any port a stack fixes by
|
|
131
|
+
hand. See
|
|
130
132
|
[Claude Code and git worktrees](../wiki/claude/claude-worktrees.md) for merge order and the
|
|
131
133
|
port-collision detail.
|
|
132
134
|
|
package/package.json
CHANGED
|
@@ -3,9 +3,14 @@ import tailwindcss from '@tailwindcss/vite'
|
|
|
3
3
|
import { defineConfig } from 'astro/config'
|
|
4
4
|
import path from 'path'
|
|
5
5
|
|
|
6
|
+
const portOffset = Number(process.env.WORKTREE_PORT_OFFSET) || 0
|
|
7
|
+
|
|
6
8
|
export default defineConfig({
|
|
7
9
|
integrations: [react()],
|
|
8
10
|
site: process.env.ASTRO_SITE,
|
|
11
|
+
server: {
|
|
12
|
+
port: 4321 + portOffset,
|
|
13
|
+
},
|
|
9
14
|
vite: {
|
|
10
15
|
plugins: [tailwindcss()],
|
|
11
16
|
resolve: {
|
|
@@ -13,5 +18,11 @@ export default defineConfig({
|
|
|
13
18
|
'@': path.resolve('./src'),
|
|
14
19
|
},
|
|
15
20
|
},
|
|
21
|
+
server: {
|
|
22
|
+
strictPort: true,
|
|
23
|
+
},
|
|
24
|
+
preview: {
|
|
25
|
+
strictPort: true,
|
|
26
|
+
},
|
|
16
27
|
},
|
|
17
28
|
})
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { defineConfig, devices } from '@playwright/test'
|
|
2
2
|
|
|
3
3
|
const isCI = !!process.env.CI
|
|
4
|
+
const baseURL = `http://localhost:${4321 + (Number(process.env.WORKTREE_PORT_OFFSET) || 0)}`
|
|
4
5
|
|
|
5
6
|
export default defineConfig({
|
|
6
7
|
testDir: 'e2e',
|
|
@@ -10,7 +11,7 @@ export default defineConfig({
|
|
|
10
11
|
reporter: isCI ? 'list' : 'html',
|
|
11
12
|
use: {
|
|
12
13
|
trace: 'on-first-retry',
|
|
13
|
-
baseURL
|
|
14
|
+
baseURL,
|
|
14
15
|
},
|
|
15
16
|
projects: [
|
|
16
17
|
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
|
|
@@ -19,7 +20,7 @@ export default defineConfig({
|
|
|
19
20
|
],
|
|
20
21
|
webServer: {
|
|
21
22
|
command: 'bun run build && bun run preview',
|
|
22
|
-
url:
|
|
23
|
-
reuseExistingServer:
|
|
23
|
+
url: baseURL,
|
|
24
|
+
reuseExistingServer: false,
|
|
24
25
|
},
|
|
25
26
|
})
|
|
@@ -15,15 +15,17 @@ packages = [
|
|
|
15
15
|
]
|
|
16
16
|
|
|
17
17
|
[scripts]
|
|
18
|
-
"dev" = "astro dev"
|
|
18
|
+
"dev" = "WORKTREE_PORT_OFFSET=$(bash scripts/worktree-port.sh) astro dev"
|
|
19
19
|
"build" = "astro check && astro build"
|
|
20
|
-
"preview" = "astro preview"
|
|
20
|
+
"preview" = "WORKTREE_PORT_OFFSET=$(bash scripts/worktree-port.sh) astro preview"
|
|
21
21
|
"astro" = "astro"
|
|
22
22
|
"typecheck" = "astro check"
|
|
23
23
|
"setup" = "./scripts/setup.sh"
|
|
24
24
|
|
|
25
25
|
[scripts.override]
|
|
26
|
-
"screenshot" = "PREVIEW_PORT
|
|
26
|
+
"screenshot" = "PREVIEW_PORT=$(bash scripts/worktree-port.sh 4321) bash scripts/screenshot.sh"
|
|
27
|
+
"dev" = "WORKTREE_PORT_OFFSET=$(bash scripts/worktree-port.sh) astro dev"
|
|
28
|
+
"preview" = "WORKTREE_PORT_OFFSET=$(bash scripts/worktree-port.sh) astro preview"
|
|
27
29
|
|
|
28
30
|
[gitignore]
|
|
29
31
|
"# Astro" = [".astro/"]
|
|
@@ -17,9 +17,9 @@ The astro stack covers Astro + TypeScript projects: content sites, marketing sit
|
|
|
17
17
|
|
|
18
18
|
## What ships as golden configs
|
|
19
19
|
|
|
20
|
-
- `astro.config.mjs`: `@astrojs/react` integration, `@tailwindcss/vite` in `vite.plugins`, `@/` path alias via `vite.resolve.alias`, `ASTRO_SITE` env for the `site` field.
|
|
20
|
+
- `astro.config.mjs`: `@astrojs/react` integration, `@tailwindcss/vite` in `vite.plugins`, `@/` path alias via `vite.resolve.alias`, `ASTRO_SITE` env for the `site` field. Port `4321` plus `WORKTREE_PORT_OFFSET` at `server.port`, with `strictPort` under `vite.server` and `vite.preview`. Astro merges the user's `vite` block into the config backing both its dev and its static preview server, and feeds `server.port` through as the preview port, so the port sits at the top level while the bind guarantee sits under `vite`.
|
|
21
21
|
- `vitest.config.ts`: uses `getViteConfig` from `astro/config` (not `mergeConfig`). jsdom, globals, setup file, `passWithNoTests: true`, v8 coverage, `**/*.astro` in coverage excludes.
|
|
22
|
-
- `playwright.config.ts`: all browsers, `webServer` runs `bun run build && bun run preview` on port 4321
|
|
22
|
+
- `playwright.config.ts`: all browsers, `webServer` runs `bun run build && bun run preview` on port `4321` plus `WORKTREE_PORT_OFFSET`, `reuseExistingServer: false`. Astro's dev/prod gap is wide (MDX, island hydration, asset optimization), so E2E always tests the built `dist/`.
|
|
23
23
|
- `tsconfig.json`: extends `astro/tsconfigs/strict`, adds `skipLibCheck`, `vitest/globals` and `@testing-library/jest-dom` in types, `@/` paths.
|
|
24
24
|
- `eslint.config.js`: overrides the web layer. Adds `eslint-plugin-astro` (`.astro` parser via `astro-eslint-parser`). React-hooks scoped to `.jsx`/`.tsx` only (`.astro` is not React). `src/pages/**` exempt from filename and folder naming conventions because Astro's file-based routing ties names to URL segments.
|
|
25
25
|
|
|
@@ -49,7 +49,7 @@ Add `prettier-plugin-astro` first in plugins, then `prettier-plugin-tailwindcss`
|
|
|
49
49
|
|
|
50
50
|
Append to the `## Scripts` table:
|
|
51
51
|
|
|
52
|
-
| `bun run dev` | Start the Astro dev server on port 4321. |
|
|
52
|
+
| `bun run dev` | Start the Astro dev server on port 4321, plus this worktree's port offset. |
|
|
53
53
|
| `bun run build` | Run `astro check` then build the static output. |
|
|
54
54
|
| `bun run preview` | Serve the built site locally. |
|
|
55
55
|
| `bun run astro` | Expose the Astro CLI. |
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { defineConfig, devices } from '@playwright/test'
|
|
2
2
|
|
|
3
3
|
const isCI = !!process.env.CI
|
|
4
|
+
const baseURL = `http://localhost:${5173 + (Number(process.env.WORKTREE_PORT_OFFSET) || 0)}`
|
|
4
5
|
|
|
5
6
|
export default defineConfig({
|
|
6
7
|
testDir: 'e2e',
|
|
@@ -10,7 +11,7 @@ export default defineConfig({
|
|
|
10
11
|
reporter: isCI ? 'list' : 'html',
|
|
11
12
|
use: {
|
|
12
13
|
trace: 'on-first-retry',
|
|
13
|
-
baseURL
|
|
14
|
+
baseURL,
|
|
14
15
|
},
|
|
15
16
|
projects: [
|
|
16
17
|
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
|
|
@@ -19,7 +20,7 @@ export default defineConfig({
|
|
|
19
20
|
],
|
|
20
21
|
webServer: {
|
|
21
22
|
command: 'bun run dev',
|
|
22
|
-
url:
|
|
23
|
-
reuseExistingServer:
|
|
23
|
+
url: baseURL,
|
|
24
|
+
reuseExistingServer: false,
|
|
24
25
|
},
|
|
25
26
|
})
|
|
@@ -3,6 +3,8 @@ import react from '@vitejs/plugin-react'
|
|
|
3
3
|
import path from 'path'
|
|
4
4
|
import { defineConfig } from 'vite'
|
|
5
5
|
|
|
6
|
+
const portOffset = Number(process.env.WORKTREE_PORT_OFFSET) || 0
|
|
7
|
+
|
|
6
8
|
export default defineConfig({
|
|
7
9
|
plugins: [react(), tailwindcss()],
|
|
8
10
|
resolve: {
|
|
@@ -11,4 +13,12 @@ export default defineConfig({
|
|
|
11
13
|
},
|
|
12
14
|
},
|
|
13
15
|
base: process.env.VITE_BASE_URL ?? '/',
|
|
16
|
+
server: {
|
|
17
|
+
port: 5173 + portOffset,
|
|
18
|
+
strictPort: true,
|
|
19
|
+
},
|
|
20
|
+
preview: {
|
|
21
|
+
port: 4173 + portOffset,
|
|
22
|
+
strictPort: true,
|
|
23
|
+
},
|
|
14
24
|
})
|
|
@@ -11,11 +11,13 @@ packages = [
|
|
|
11
11
|
]
|
|
12
12
|
|
|
13
13
|
[scripts]
|
|
14
|
-
"dev" = "vite"
|
|
14
|
+
"dev" = "WORKTREE_PORT_OFFSET=$(bash scripts/worktree-port.sh) vite"
|
|
15
15
|
"build" = "tsc --noEmit && vite build"
|
|
16
|
-
"preview" = "vite preview"
|
|
16
|
+
"preview" = "WORKTREE_PORT_OFFSET=$(bash scripts/worktree-port.sh) vite preview"
|
|
17
17
|
"typecheck" = "tsc --noEmit"
|
|
18
18
|
"setup" = "./scripts/setup.sh"
|
|
19
19
|
|
|
20
20
|
[scripts.override]
|
|
21
21
|
"build" = "tsc --noEmit && vite build"
|
|
22
|
+
"dev" = "WORKTREE_PORT_OFFSET=$(bash scripts/worktree-port.sh) vite"
|
|
23
|
+
"preview" = "WORKTREE_PORT_OFFSET=$(bash scripts/worktree-port.sh) vite preview"
|
|
@@ -16,16 +16,16 @@ The vite-react stack covers Vite + React + TypeScript projects: web apps and Chr
|
|
|
16
16
|
|
|
17
17
|
## What ships as golden configs
|
|
18
18
|
|
|
19
|
-
- `vite.config.ts`: `@vitejs/plugin-react`, `@tailwindcss/vite`, `@` path alias to `./src`, `VITE_BASE_URL` env for base path.
|
|
19
|
+
- `vite.config.ts`: `@vitejs/plugin-react`, `@tailwindcss/vite`, `@` path alias to `./src`, `VITE_BASE_URL` env for base path. Dev port `5173` and preview port `4173`, each plus `WORKTREE_PORT_OFFSET`, both with `strictPort`.
|
|
20
20
|
- `vitest.config.ts`: merges from `vite.config.ts`, jsdom, globals, setup file, `passWithNoTests: true`, v8 coverage.
|
|
21
|
-
- `playwright.config.ts`: all browsers, `webServer` on `bun run dev` at port 5173
|
|
21
|
+
- `playwright.config.ts`: all browsers, `webServer` on `bun run dev` at port `5173` plus `WORKTREE_PORT_OFFSET`, `reuseExistingServer: false`, trace under `use`.
|
|
22
22
|
- `tsconfig.json`: unified, `noEmit: true`, `skipLibCheck: true`, `@/` paths, `vitest/globals` and `@testing-library/jest-dom` in types.
|
|
23
23
|
|
|
24
24
|
## Chrome extension variant
|
|
25
25
|
|
|
26
26
|
When scaffolding a Chrome extension, override the installed golden configs:
|
|
27
27
|
|
|
28
|
-
- `vite.config.ts`: use `crx({ manifest })` and `zip()` from `@crxjs/vite-plugin` instead of `react()` alone.
|
|
28
|
+
- `vite.config.ts`: use `crx({ manifest })` and `zip()` from `@crxjs/vite-plugin` instead of `react()` alone. Keep the derived `server.port` and `server.strictPort: true`, set `server.hmr.clientPort` to the same derived value, and add `chrome-extension://` to CORS origins. Drop `VITE_BASE_URL`.
|
|
29
29
|
- `vitest.config.ts`: use a standalone `defineConfig` (no `mergeConfig`). crxjs plugin breaks Vitest. Declare `@vitejs/plugin-react` and `@tailwindcss/vite` directly. Add `**/release/**` to excludes and `manifest.config.ts`, `**/*.d.ts` to coverage excludes.
|
|
30
30
|
- `playwright.config.ts`: chromium-only (Firefox and WebKit cannot run extensions). Bundled `chromium` channel. No `baseURL` or `webServer`. Tests load the built extension directly from `dist/`.
|
|
31
31
|
- `e2e/fixtures.ts`: extend Playwright base `test` with `context` (persistent context loading the extension from `dist/`) and `extensionId` (extracted from service worker URL). Rename `use` to `apply` to avoid the React hooks ESLint rule. `waitForEvent('serviceworker')` blocks until the MV3 service worker registers.
|
|
@@ -45,7 +45,7 @@ When scaffolding a Chrome extension, override the installed golden configs:
|
|
|
45
45
|
|
|
46
46
|
Append to the `## Scripts` table:
|
|
47
47
|
|
|
48
|
-
| `bun run dev` | Start the Vite dev server on port 5173. |
|
|
48
|
+
| `bun run dev` | Start the Vite dev server on port 5173, plus this worktree's port offset. |
|
|
49
49
|
| `bun run build` | Typecheck then build the production bundle. |
|
|
50
50
|
| `bun run preview` | Serve the built bundle locally. |
|
|
51
51
|
| `bun run typecheck` | Run `tsc --noEmit`. |
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Prints a port for this working directory: the base itself in a normal
|
|
5
|
+
# checkout, and the base plus a per-worktree offset in a linked git worktree,
|
|
6
|
+
# so two worktrees of one repository never serve on one port.
|
|
7
|
+
|
|
8
|
+
base="${1:-0}"
|
|
9
|
+
band=50
|
|
10
|
+
|
|
11
|
+
offset() {
|
|
12
|
+
if [[ -n "${WORKTREE_PORT_OFFSET:-}" ]]; then
|
|
13
|
+
echo "$WORKTREE_PORT_OFFSET"
|
|
14
|
+
return
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
local git_dir common_dir name
|
|
18
|
+
git_dir=$(git rev-parse --git-dir 2>/dev/null) || {
|
|
19
|
+
echo 0
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
common_dir=$(git rev-parse --git-common-dir 2>/dev/null) || {
|
|
23
|
+
echo 0
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if [[ "$(cd "$git_dir" && pwd -P)" == "$(cd "$common_dir" && pwd -P)" ]]; then
|
|
28
|
+
echo 0
|
|
29
|
+
return
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
name=$(basename "$(git rev-parse --show-toplevel)")
|
|
33
|
+
echo $(($(printf '%s' "$name" | cksum | cut -d' ' -f1) % band + 1))
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
echo $((base + $(offset)))
|
|
@@ -42,13 +42,13 @@ packages = [
|
|
|
42
42
|
"test:run" = "vitest run --reporter=verbose"
|
|
43
43
|
"test:ui" = "vitest --ui"
|
|
44
44
|
"test:coverage" = "vitest run --coverage"
|
|
45
|
-
"test:e2e" = "playwright test"
|
|
46
|
-
"test:e2e:ui" = "playwright test --ui"
|
|
45
|
+
"test:e2e" = "WORKTREE_PORT_OFFSET=$(bash scripts/worktree-port.sh) playwright test"
|
|
46
|
+
"test:e2e:ui" = "WORKTREE_PORT_OFFSET=$(bash scripts/worktree-port.sh) playwright test --ui"
|
|
47
47
|
"test:e2e:report" = "playwright show-report"
|
|
48
48
|
"check:full" = "./scripts/verify.sh && bun run test:e2e"
|
|
49
49
|
|
|
50
50
|
[scripts.override]
|
|
51
|
-
"screenshot" = "bash scripts/screenshot.sh"
|
|
51
|
+
"screenshot" = "PREVIEW_PORT=$(bash scripts/worktree-port.sh 4173) bash scripts/screenshot.sh"
|
|
52
52
|
|
|
53
53
|
[gitignore]
|
|
54
54
|
"# Build" = ["dist/"]
|
package/tooling/web/reference.md
CHANGED
|
@@ -16,6 +16,7 @@ Golden config files live in `tooling/web/configs/` and are copied into the targe
|
|
|
16
16
|
- `.vscode/extensions.json` and `.vscode/settings.json`: editor wiring for ESLint, Tailwind, Playwright, Vitest.
|
|
17
17
|
- `.github/workflows/verify.yml`: `static-checks`, `unit-tests`, `build-verify`, and `e2e-tests` jobs.
|
|
18
18
|
- `scripts/verify.sh`: extends base verify with typecheck, lint, unit tests, and build in the full order.
|
|
19
|
+
- `scripts/worktree-port.sh`: prints a base port plus this working directory's offset. Called with no argument it prints the offset alone.
|
|
19
20
|
|
|
20
21
|
## What stays in per-stack adapters
|
|
21
22
|
|
|
@@ -32,6 +33,17 @@ Framework glue lives in `tooling/vite-react/configs/` or `tooling/astro/configs/
|
|
|
32
33
|
- Path alias `@` maps to `./src` in both tsconfig and the framework's build config.
|
|
33
34
|
- Tsconfig is unified at root with `noEmit: true` in Vite stacks. Astro uses the scaffold default from `@astrojs/check`.
|
|
34
35
|
|
|
36
|
+
## Ports
|
|
37
|
+
|
|
38
|
+
Two worktrees of one repository run the same stack, so a fixed port makes the second one attach to the first.
|
|
39
|
+
|
|
40
|
+
- Derive every served port from `scripts/worktree-port.sh`. Never write a port literal into a script string.
|
|
41
|
+
- Read `WORKTREE_PORT_OFFSET` in a config and add it to the stack's default port. Unset yields the default, so a plain clone keeps the port it has always served on.
|
|
42
|
+
- Draw the offset from a band of 50, hashed from the worktree folder name. Two worktrees can hash to one offset, so set `WORKTREE_PORT_OFFSET` by hand to break a tie.
|
|
43
|
+
- Force-replace `dev` and `preview` through `[scripts.override]`. Both stacks' scaffolds define those keys, and a plain `[scripts]` entry never replaces a key the scaffold already wrote.
|
|
44
|
+
- Set `strictPort` on every dev and preview server. A server that walks to the next free port serves where nothing is looking for it.
|
|
45
|
+
- Set Playwright `reuseExistingServer: false`. Reuse attaches to whatever answers on the port, which reports a pass against another branch's code and prints nothing to say so.
|
|
46
|
+
|
|
35
47
|
## Anti-patterns
|
|
36
48
|
|
|
37
49
|
Sticky negative knowledge. Do not relearn.
|