From 2e644271235adba54b608c7250fa39615ffd7f58 Mon Sep 17 00:00:00 2001 From: fi3ework Date: Tue, 18 Aug 2026 14:59:45 +0800 Subject: [PATCH 1/2] chore(lint): forbid value imports of tool packages in extension source Resolve-from-project (adaptation #3) means the extension may only take types from @rslint/core, @rstest/core, rstack and jiti at compile time; runtime modules are loaded from the user's project through explicit paths. Enforce it with @typescript-eslint/no-restricted-imports (allowTypeImports) over packages/vscode/src so a static value import fails lint instead of bundling or require()-ing the wrong copy. --- packages/vscode/AGENTS.md | 2 +- rstack.config.ts | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/vscode/AGENTS.md b/packages/vscode/AGENTS.md index 838a97e..78d4df9 100644 --- a/packages/vscode/AGENTS.md +++ b/packages/vscode/AGENTS.md @@ -11,7 +11,7 @@ One extension replacing the standalone `rstack.rslint` and `rstack.rstest` exten 1. **Shell activation** — stacks never self-activate; `register()` returns fast and never blocks on starting a server/worker. 2. **Namespace** — everything user-visible is `rstack.*`. Legacy `rslint.*` / `rstest.*` names appear only in the migration mapping. Command IDs were renamed without aliases (breaking old keybindings was an accepted cost). -3. **Resolve-from-project** — no tool binaries or tool packages in the VSIX; everything resolves from the user's project so the editor runs the CLI's exact versions. Version floors surface as a status, never a crash. All cooperating lint pieces (binary, config loader, plugin host) must come from one resolution root. +3. **Resolve-from-project** — no tool binaries or tool packages in the VSIX; everything resolves from the user's project so the editor runs the CLI's exact versions. Version floors surface as a status, never a crash. All cooperating lint pieces (binary, config loader, plugin host) must come from one resolution root. Enforced by lint: `@typescript-eslint/no-restricted-imports` in the root `rstack.config.ts` rejects any non-type import of `@rslint/core`, `@rstest/core`, `rstack` or `jiti` under `src/` — types only at compile time, runtime modules through explicit project paths. 4. **Status aggregation** — stacks own no UI chrome; they report to the shell's single status bar item, which always exists. In CI the test stack's `MasterLogger` also mirrors every entry to stderr (`RSTACK_E2E_MIRROR_LOGS=1`, set by `e2e/rstest/runTest.ts`) — the output channel is unreadable there; rationale in `stacks/test/logger.ts`. 5. **Worker-cwd decoupling** (test) — a project's cwd is explicit, not derived from the config file path; for native configs behavior stays byte-identical to upstream. 6. **Node runtime selection** (lint, test, fmt) — the Node a project-loading child process runs on is a **User Node runtime** chosen by the extension against one uniform floor, never assumed from PATH; the recovery path is the user's own shell, and the dividing line is the **load bound** (terms in CONTEXT.md; the full rule and rationale in `docs/adr/0001-node-runtime-selection.md`). All three callers — the lint worker, the rstest worker and the `rs fmt --lsp` server — take the decision from the one shared module (`shared/nodeResolution.ts`) and share one escape hatch, the resource-scoped `rstack.nodeExecutable` (`shared/nodeExecutableSetting.ts`); each appends its own consequence to the shared preflight message. diff --git a/rstack.config.ts b/rstack.config.ts index cc56300..45f985a 100644 --- a/rstack.config.ts +++ b/rstack.config.ts @@ -25,6 +25,37 @@ define.lint(async () => { '@typescript-eslint/no-require-imports': 'off', }, }, + { + // Resolve-from-project (packages/vscode/AGENTS.md, adaptation #3): the + // extension ships no tool packages, so extension source may only take + // *types* from them at compile time. Runtime modules come from the + // user's project through explicit paths — a static value import would + // bundle or `require()` the wrong copy. + files: ['packages/vscode/src/**/*.ts'], + rules: { + '@typescript-eslint/no-restricted-imports': [ + 'error', + { + patterns: [ + { + group: [ + '@rslint/core', + '@rslint/core/*', + '@rstest/core', + '@rstest/core/*', + 'rstack', + 'rstack/*', + 'jiti', + ], + allowTypeImports: true, + message: + 'Extension source may only import types from tool packages; load the runtime module from the project (see AGENTS.md, resolve-from-project).', + }, + ], + }, + ], + }, + }, { languageOptions: { parserOptions: { From 808560adb69f077b13700af94dd5e955a8f1d106 Mon Sep 17 00:00:00 2001 From: fi3ework Date: Tue, 18 Aug 2026 15:03:55 +0800 Subject: [PATCH 2/2] chore(lint): also restrict jiti subpath value imports --- rstack.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/rstack.config.ts b/rstack.config.ts index 45f985a..306e7f6 100644 --- a/rstack.config.ts +++ b/rstack.config.ts @@ -46,6 +46,7 @@ define.lint(async () => { 'rstack', 'rstack/*', 'jiti', + 'jiti/*', ], allowTypeImports: true, message: