Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
7cbd4f6
chore(repo): align skills, knip, hooks, and dependencies
peternhale Apr 13, 2026
bb9ea35
feat(infra): introduce effect platform worker infrastructure Steps 0-4
peternhale Apr 13, 2026
f66bafd
feat(infra): implement Steps 5-10 of effect worker topology
peternhale Apr 13, 2026
f83806d
feat(infra): wire real workload offload to worker topology (Step 11)
peternhale Apr 13, 2026
3cd7464
feat(infra): transport isolation, settings, and ADR (Steps 12-13)
peternhale Apr 13, 2026
3fc48e7
fix: prevent worker protocol collisions and web platform crashes
peternhale Apr 13, 2026
bb35a37
chore: merge origin/main into phale/workers
peternhale Apr 13, 2026
90ea061
refactor: consolidate worker code patterns and eliminate duplication
peternhale Apr 14, 2026
f426c5c
refactor: decompose symbol manager into Effect services and standalon…
peternhale Apr 14, 2026
8403ebe
refactor!: make ISymbolManager and SymbolProvider fully async
peternhale Apr 14, 2026
f4f97ba
refactor: extract resolution ops from ApexSymbolManager (Phases 1-3)
peternhale Apr 14, 2026
3e8c999
fix(apex-lsp-compliant-services): remove scope-fallback from processH…
peternhale Apr 15, 2026
ebd47f1
feat(apex-lsp-compliant-services): add version-aware write-back protocol
peternhale Apr 16, 2026
8277d06
fix(apex-lsp-compliant-services): resolve write-back Effect double-wr…
peternhale Apr 16, 2026
7e350fa
feat(apex-ls): enable worker debug logging with unified log level
peternhale Apr 16, 2026
7760010
feat(apex-ls): enable worker-based enrichment for diagnostics
peternhale Apr 16, 2026
1e35f4b
fix(apex-ls): add write-back logic to DispatchDiagnostic handler
peternhale Apr 16, 2026
d7681d1
chore: improve worker initialization and reduce noise in logs
peternhale Apr 17, 2026
ccd9543
feat(apex-ls): enable worker-based enrichment for definition requests
peternhale Apr 17, 2026
7597f52
fix(apex-ls): reconstruct SymbolTable from IPC wire format for stdlib…
peternhale Apr 17, 2026
133f471
fix(apex-lsp-extension): prevent process.exit in web test setup for w…
peternhale Apr 17, 2026
e66e9c4
fix(apex-lsp-compliant-services): remove scope fallback from hover re…
peternhale Apr 17, 2026
2d72a78
feat(apex-lsp-extension): pre-fetch cross-file dependencies on enrich…
peternhale Apr 17, 2026
679ca5e
chore(repo): remove tracked .eslintcache files
peternhale Apr 17, 2026
e9208b1
fix(apex-lsp-parser-ast): restore Effect Ref sync in deferred referen…
peternhale Apr 17, 2026
9a3ce14
chore(repo): gitignore .claude/settings.json
peternhale Apr 17, 2026
2e3a869
chore(repo): merge origin/main into phale/workers
peternhale Apr 17, 2026
fc2a236
chore(repo): merge origin/main into phale/workers
peternhale Apr 17, 2026
32f4240
chore(repo): remove tracked apex-parser-ast/resources build artifacts
peternhale Apr 17, 2026
c0ab49a
chore(repo): untrack .session-files and add to .gitignore
peternhale Apr 17, 2026
6d32cda
chore(repo): untrack .vscode-test-web and add to .gitignore
peternhale Apr 17, 2026
4607e31
feat(repo): add dedicated compilation worker for public-api compilation
peternhale Apr 20, 2026
371e11f
feat(repo): cascade profiling, debug ports, and heap size to worker t…
peternhale Apr 20, 2026
be1ce30
chore(repo): checkpoint pending worker topology changes before graph …
peternhale Apr 21, 2026
f5b28ee
feat(repo): route apex/graphData to data-owner worker for full worksp…
peternhale Apr 21, 2026
6d46869
docs(repo): update README and ADR with worker topology and graph rout…
peternhale Apr 21, 2026
ead5cac
Kdev/workers updated (#333)
kylewalke Apr 21, 2026
1aefb4c
feat(apex-lsp-web): add browser worker topology with non-protocol mes…
peternhale Apr 22, 2026
0a74218
fix(apex-lsp-web): dual-channel browser worker ports to fix premature…
peternhale Apr 23, 2026
16bfcdf
refactor(apex-lsp-web): promote coordinator/worker init logs to alway…
peternhale Apr 23, 2026
aa7a106
feat(apex-lsp-extension): replace workspace load toast with status ba…
peternhale Apr 23, 2026
5163414
Merge branch 'phale/workers' of github.com:forcedotcom/apex-language-…
peternhale Apr 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions .claude/hooks/verify-stop.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,17 @@ rm -f "$SESSION_MARKER"
run_step "compile" "npm run compile" && echo "[verify-stop] compile ok" >&2
run_step "lint" "npm run lint" && echo "[verify-stop] lint ok" >&2

# Effect LS: only uncommitted .ts files
ts_files=$(git diff --name-only HEAD 2>/dev/null | grep '\.ts$' || true)
if [ -n "$ts_files" ]; then
# Effect LS: only uncommitted .ts files inside packages that use Effect
ts_files=$(git diff --name-only HEAD 2>/dev/null | grep '\.ts$' | grep -v '^e2e-tests/' | grep -v '^scripts/' || true)
if [ -n "$ts_files" ] && command -v effect-language-service >/dev/null 2>&1; then
for f in $ts_files; do
[ -f "$f" ] && run_step "effect LS ($f)" "npx -y effect-language-service diagnostics --file $f"
done
elif [ -n "$ts_files" ]; then
echo "[verify-stop] effect LS skipped (effect-language-service not available)" >&2
else
echo "[verify-stop] effect LS skipped (no uncommitted .ts in packages)" >&2
fi
[ -z "$ts_files" ] && echo "[verify-stop] effect LS skipped (no uncommitted .ts)" >&2

run_step "test" "npm run test" && echo "[verify-stop] test ok" >&2
run_step "bundle" "npm run bundle" && echo "[verify-stop] bundle ok" >&2
Expand Down
111 changes: 111 additions & 0 deletions .claude/skills/language-server-architecture/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
name: language-server-architecture
description: Apex Language Server data architecture — type sources, worker topology, and data ownership. Use when working on type resolution, worker communication, resource loading, hover, definition, diagnostics, or any code in apex-ls/src/server/ or apex-parser-ast/src/symbols/.
---

# Language Server Architecture

## Three Sources of Apex Types

The language server works with three distinct sources of Apex type artifacts:

### 1. Workspace (customer code)
- `.cls`, `.trigger`, `.apex` files authored by the user
- Managed by the **data owner worker** via didOpen/didChange/didSave
- Compiled on-demand by the parser; symbols registered in the symbol graph

### 2. Faux SObject classes
- Files representing fields found in SObjects (Account, Contact, Property__c, etc.)
- Produced by an **external process outside this repository** at the user's request
- Placed at a well-known path in the workspace (`.sfdx/tools/`)
- Presented to the language server using the same document operations as customer code
- Their URI comes from a path the language server controls
- **NOT part of the standard Apex library** — do not confuse with stdlib

### 3. Standard Apex Library (stdlib)
- System.String, System.Assert, Database.QueryLocator, ConnectApi.*, etc.
- Owned exclusively by the **resource loader worker**
- Backed by three read-only precompiled artifacts in `apex-parser-ast/resources/`:
- `apex-type-registry.pb.gz` — protobuf metadata about stdlib symbols (6112 types, 59 namespaces)
- `apex-stdlib.pb.gz` — precompiled symbol data
- `StandardApexLibrary.zip` — source `.cls` files for stdlib classes
- All access to these artifacts MUST go through the resource loader worker

## Worker Topology

```
Coordinator (main thread)
├── Data owner worker — owns symbol tables for workspace + faux SObject files
├── Enrichment workers (2+) — handle hover, definition, diagnostics
└── Resource loader worker — owns standard Apex library (read-only)
```

### Data owner worker
- Single worker, source of truth for customer code and faux SObject class symbols
- Receives document lifecycle events (open, change, save, close)
- Serves symbol data to enrichment workers via QuerySymbolSubset
- Accepts write-backs of enriched symbols from enrichment workers

### Enrichment workers
- Pool of workers for parallel LSP request processing
- Get file symbols from data owner, process requests, write back enriched data
- Access stdlib via remote ResourceLoaderService layer (assistance channel → coordinator → resource loader worker)
- Do NOT have local copies of protobuf caches, stdlib ZIP, or GlobalTypeRegistry
- The sync namespace cache (populated during stdlib warmup) is the only local stdlib state

### Resource loader worker
- Single worker, owns all standard Apex library data
- Loads and serves stdlib symbol tables, resolves class FQNs, provides namespace index
- All stdlib access from other workers routes through this worker

## GlobalTypeRegistry

Defined in `apex-parser-ast/src/services/GlobalTypeRegistryService.ts`.

GlobalTypeRegistry is an **in-process, mutable type index** — NOT just a stdlib cache. It tracks types from ALL three sources as they are compiled and registered:

- Stdlib types registered at startup via `ResourceLoader.initializeTypeRegistry()` (`isStdlib: true`)
- User types registered via `ApexSymbolManager.addSymbolTable()` (`isStdlib: false`)
- Provides O(1) cross-file type resolution via `resolveType()`

It is a **module-level singleton** (`globalRegistryInstance`). Each Node.js process gets its own instance:
- **Coordinator process**: populated with stdlib + user types as files are compiled
- **Enrichment workers**: EMPTY — enrichment workers don't compile files or load protobuf caches

When modifying resolution code in `apex-parser-ast/src/symbols/ops/`:
- Code runs on BOTH coordinator and enrichment workers
- Do not remove GlobalTypeRegistry usage — it provides cross-file resolution on the coordinator
- Ensure enrichment worker fallback paths work correctly (they bypass the empty registry)

## LSP Request Routing (DISPATCH_ROUTING)

Defined in `apex-ls/src/server/WorkerCoordinator.ts`.

| Request | Target | Notes |
|---------|--------|-------|
| documentOpen/Change/Save/Close | dataOwner | Document lifecycle |
| hover | enrichmentPool | With write-back |
| definition | enrichmentPool | With write-back |
| diagnostics | enrichmentPool | With write-back |
| completion, references, etc. | coordinatorOnly | Not yet moved to workers |

## Worker Profiling & Debugging

Workers inherit profiling, debug, and heap-size flags from the main process via `WorkerExecArgvBuilder`. Key behaviors:

- **Profiling** (`apex.environment.profilingMode: "full"`): Workers get `--cpu-prof` / `--heap-prof` with role-specific subdirectories (e.g. `<output>/dataOwner/`)
- **Debug** (`apex.debug: "inspect"`): Workers get `--inspect=0` (auto-assigned port). The main process keeps its fixed port (default 6009).
- **Heap size**: `--max-old-space-size` passes through unchanged.
- **Thread naming**: Workers are named `apex-worker-<role>` (visible in Chrome DevTools).
- **Stderr forwarding**: Worker stderr is line-buffered and logged with role labels. Debug port assignments appear in the Output panel.

## Key Paths

- Worker entry: `packages/apex-ls/src/worker.platform.ts`
- Worker coordinator: `packages/apex-ls/src/server/WorkerCoordinator.ts`
- Worker execArgv builder: `packages/apex-ls/src/server/WorkerExecArgvBuilder.ts`
- Assistance mediator: `packages/apex-ls/src/server/CoordinatorAssistanceMediator.ts`
- Symbol resolution ops: `packages/apex-parser-ast/src/symbols/ops/`
- GlobalTypeRegistry: `packages/apex-parser-ast/src/services/GlobalTypeRegistryService.ts`
- Resource loader: `packages/apex-parser-ast/src/utils/resourceLoader.ts`
- Enrichment bootstrap: `packages/lsp-compliant-services/src/workers/WorkerBackendBootstrap.ts`
27 changes: 23 additions & 4 deletions .claude/skills/verification/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
name: verification
description: Verification steps for code changes. Use after ANY code change to ensure quality, or when creating plans because those should include verification steps.
description: Verification steps for code changes. Debug mode defers lint; full checklist before merge. Use after changes or when planning.
---

# Verification

Do each of these steps, in order. Do not move to a step unless all previous are passing. Run these commands from the repo level. If you make any changes, go back to step 1.
Do each step in order; do not skip a step unless all previous are passing **except in [debug mode](#debug-mode)**. Run from repo root; use `-w` for a single package. After changes outside debug mode, restart from step 1.

1. `npm run compile` — [references/compile.md](references/compile.md) (TS4023: [ts4023-effect-errors](../ts4023-effect-errors/SKILL.md), TS1261: [ts1261-filename-casing](../ts1261-filename-casing/SKILL.md))
2. `npm run lint` - fix any new errors or warnings
2. `npm run lint` fix new errors/warnings **(defer in debug mode — see [Debug mode](#debug-mode))**
3. Effect code: `npx effect-language-service diagnostics --project tsconfig.json` (or `--file <path>`) — fix reported issues; `read_lints` does not surface Effect LS
4. `npm run test` - See [references/unit-tests.md](references/unit-tests.md)
5. `npm run bundle` to ensure bundles still build
Expand All @@ -22,6 +22,25 @@ Do each of these steps, in order. Do not move to a step unless all previous are

8. check for dupes `npm run check:dupes` and then look in `jscpd-report` (and parser-ast report if using `check:dupes:parser-ast`) to make sure none of your changes are flagged.

## Debug mode

Use when **actively debugging** a bug (repro, instrumentation, iterative fixes) — including Cursor **Debug mode** with runtime logging.

- **Goal**: reproduce, understand, fix the bug. Full verification is **after** the fix is validated.
- **Still do**: compile touched packages / scope so code runs (`npm run compile` or `-w` as needed). Fix compile errors that block running tests or the app.
- **Do not block on**: **`npm run lint`** (ESLint/Prettier). Clean up lint **before merge / PR**, not between repro iterations.
- **Usually defer**: knip (7), check:dupes (8), full test suite (4), bundle (5), Effect LS (3) — run when wrapping up or before merge unless needed to prove the fix.

### Lint suspended (explicit user request)

If the user asks to **suspend lint**, **stop running lint**, or says lint is **getting in the way** of debugging:

- Do **not** run `npm run lint` or use lint results to block progress until they ask to resume verification or move to pre-PR.
- Do **not** spend turns only fixing Prettier/ESLint unless a change is required for **compile** or the user asks.
- Note: workspace **stop hooks** may still run lint on agent stop; the user may need to ignore or disable that locally while debugging.

Return to the full ordered checklist when leaving debug (e.g. pre-PR, session end).

## Rules

- Don't change /src AND /test together (except imports/renames)
Expand All @@ -35,7 +54,7 @@ Do each of these steps, in order. Do not move to a step unless all previous are

## Plans

When creating plans in plan mode, always include verification steps after the "actual" todos. The verification steps should follow this checklist.
When creating plans in plan mode, include verification after the "actual" todos (full checklist; in debug work, note lint/knip/dupes run before merge).

## References

Expand Down
Loading