Compare commits

...
Author SHA1 Message Date
Tabish Bidiwale 313afbb4c7 ci: add ESLint step to lint job
Run `pnpm lint` in CI to enforce the no-restricted-imports rule
that prevents static @inquirer imports.
2025-12-23 09:49:19 +11:00
Tabish Bidiwale e4a02174f3 chore: add ESLint with no-restricted-imports rule for @inquirer
Add ESLint configuration that prevents static imports of @inquirer/*
modules. This prevents future regressions of the pre-commit hook hang
issue fixed in this PR.

The rule shows a helpful error message pointing to issue #367 for context.
init.ts is exempted since it's already dynamically imported from the CLI.
2025-12-23 09:48:00 +11:00
Tabish Bidiwale ce79ec0bab fix(cli): use dynamic import for @inquirer/prompts in config command
The config command (added in #382) reintroduced the pre-commit hook hang
issue that was fixed in #380. The static import of @inquirer/prompts at
module load time causes stdin event listeners to be registered even when
running non-interactive commands, preventing clean process exit when
stdin is piped (as pre-commit does).

Convert the static import to a dynamic import that only loads inquirer
when the `config reset` command is actually used interactively.

Fixes #367
2025-12-23 09:26:10 +11:00
5 changed files with 811 additions and 1 deletions
+3
View File
@@ -142,6 +142,9 @@ jobs:
- name: Type check
run: pnpm exec tsc --noEmit
- name: Lint
run: pnpm lint
- name: Check for build artifacts
run: |
if [ ! -d "dist" ]; then
+42
View File
@@ -0,0 +1,42 @@
import tseslint from 'typescript-eslint';
export default tseslint.config(
{
files: ['src/**/*.ts'],
extends: [...tseslint.configs.recommended],
rules: {
// Prevent static imports of @inquirer modules to avoid pre-commit hook hangs.
// These modules have side effects that can keep the Node.js event loop alive
// when stdin is piped. Use dynamic import() instead.
// See: https://github.com/Fission-AI/OpenSpec/issues/367
'no-restricted-imports': [
'error',
{
patterns: [
{
group: ['@inquirer/*'],
message:
'Use dynamic import() for @inquirer modules to prevent pre-commit hook hangs. See #367.',
},
],
},
],
// Disable rules that need broader cleanup - focus on critical issues only
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'no-empty': 'off',
'prefer-const': 'off',
},
},
{
// init.ts is dynamically imported from cli/index.ts, so static @inquirer
// imports there are safe - they won't be loaded at CLI startup
files: ['src/core/init.ts'],
rules: {
'no-restricted-imports': 'off',
},
},
{
ignores: ['dist/**', 'node_modules/**', '*.js', '*.mjs'],
}
);
+3
View File
@@ -38,6 +38,7 @@
"!dist/**/*.map"
],
"scripts": {
"lint": "eslint src/",
"build": "node build.js",
"dev": "tsc --watch",
"dev:cli": "pnpm build && node bin/openspec.js",
@@ -62,7 +63,9 @@
"@changesets/cli": "^2.27.7",
"@types/node": "^24.2.0",
"@vitest/ui": "^3.2.4",
"eslint": "^9.39.2",
"typescript": "^5.9.3",
"typescript-eslint": "^8.50.1",
"vitest": "^3.2.4"
},
"dependencies": {
+762
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,5 +1,4 @@
import { Command } from 'commander';
import { confirm } from '@inquirer/prompts';
import { spawn } from 'node:child_process';
import * as fs from 'node:fs';
import {
@@ -153,6 +152,7 @@ export function registerConfigCommand(program: Command): void {
}
if (!options.yes) {
const { confirm } = await import('@inquirer/prompts');
const confirmed = await confirm({
message: 'Reset all configuration to defaults?',
default: false,