stackfix 0.2.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.
package/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # StackFix
2
+
3
+ > Terminal-first agentic CLI that fixes failing commands using AI
4
+
5
+ StackFix is a developer productivity tool that brings AI-powered assistance directly to your terminal. Describe what you want in natural language, wrap failing commands to get automated fixes, or use the interactive TUI for complex workflows.
6
+
7
+ ## Features
8
+
9
+ - 🤖 **Natural language prompts** — Ask questions, get code suggestions
10
+ - 🔧 **Command wrapping** — Automatically diagnose and fix failing commands
11
+ - 🎨 **Syntax-highlighted diffs** — Clear visualization of proposed changes
12
+ - 💬 **Interactive TUI** — Rich terminal interface with slash commands
13
+ - 🔌 **Provider-agnostic** — Works with OpenAI, Nebius, or any compatible API
14
+ - 📝 **Session persistence** — Resume previous conversations
15
+
16
+ ## Installation
17
+
18
+ ### npm (recommended)
19
+
20
+ ```bash
21
+ npm install -g stackfix
22
+ ```
23
+
24
+ ### pip
25
+
26
+ ```bash
27
+ pip install stackfix
28
+ ```
29
+
30
+ ### From source
31
+
32
+ ```bash
33
+ git clone https://github.com/stackfix/stackfix.git
34
+ cd stackfix
35
+ pip install -e .
36
+ ```
37
+
38
+ ## Quick Start
39
+
40
+ ```bash
41
+ # Launch interactive TUI
42
+ stackfix
43
+
44
+ # Single prompt (non-interactive)
45
+ stackfix --prompt "explain this error: ImportError: No module named 'foo'"
46
+
47
+ # Wrap a failing command
48
+ stackfix -- pytest -q
49
+ ```
50
+
51
+ ## Configuration
52
+
53
+ Set environment variables for your LLM provider:
54
+
55
+ ```bash
56
+ # OpenAI
57
+ export MODEL_BASE_URL="https://api.openai.com/v1"
58
+ export MODEL_API_KEY="sk-..."
59
+ export MODEL_NAME="gpt-4"
60
+
61
+ # Nebius
62
+ export MODEL_BASE_URL="https://api.tokenfactory.nebius.com/v1"
63
+ export MODEL_API_KEY="..."
64
+ export MODEL_NAME="openai/gpt-oss-120b"
65
+
66
+ # Local (Ollama)
67
+ export MODEL_BASE_URL="http://localhost:11434/v1"
68
+ export MODEL_NAME="codellama:13b"
69
+ ```
70
+
71
+ ## TUI Commands
72
+
73
+ | Command | Description |
74
+ |---------|-------------|
75
+ | `/help` | Show all available commands |
76
+ | `/exit` | Exit the TUI |
77
+ | `/model <name>` | View or switch the model |
78
+ | `/approvals <mode>` | Set approval mode (suggest, auto-edit, full-auto) |
79
+ | `/status` | Show current configuration |
80
+ | `/diff` | Show pending git changes |
81
+ | `/history` | Show last run summary |
82
+ | `/new` | Start a new session |
83
+ | `/resume <id>` | Resume a saved session |
84
+
85
+ Use `!command` to run shell commands directly.
86
+
87
+ ## Project Context
88
+
89
+ Create an `AGENTS.md` file in your project root to provide persistent context:
90
+
91
+ ```markdown
92
+ # Project Guidelines
93
+
94
+ - Use pytest for testing
95
+ - Follow PEP 8 style
96
+ - Prefer type hints
97
+ ```
98
+
99
+ ## Development
100
+
101
+ ```bash
102
+ # Install with dev dependencies
103
+ pip install -e ".[dev]"
104
+
105
+ # Run tests
106
+ pytest tests/ -v
107
+ ```
108
+
109
+ ## License
110
+
111
+ MIT
package/bin/stackfix ADDED
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawn } = require('child_process');
4
+ const path = require('path');
5
+ const fs = require('fs');
6
+
7
+ // Get the package root directory
8
+ const packageRoot = path.resolve(__dirname, '..');
9
+ const venvPath = path.join(packageRoot, '.venv');
10
+
11
+ // Determine Python executable path
12
+ function getPythonPath() {
13
+ const isWindows = process.platform === 'win32';
14
+
15
+ // Check for venv first
16
+ if (fs.existsSync(venvPath)) {
17
+ const venvPython = isWindows
18
+ ? path.join(venvPath, 'Scripts', 'python.exe')
19
+ : path.join(venvPath, 'bin', 'python');
20
+ if (fs.existsSync(venvPython)) {
21
+ return venvPython;
22
+ }
23
+ }
24
+
25
+ // Fall back to system Python
26
+ return isWindows ? 'python' : 'python3';
27
+ }
28
+
29
+ // Run stackfix
30
+ const pythonPath = getPythonPath();
31
+ const args = ['-m', 'stackfix', ...process.argv.slice(2)];
32
+
33
+ const child = spawn(pythonPath, args, {
34
+ stdio: 'inherit',
35
+ cwd: process.cwd(),
36
+ env: {
37
+ ...process.env,
38
+ PYTHONPATH: packageRoot
39
+ }
40
+ });
41
+
42
+ child.on('error', (err) => {
43
+ if (err.code === 'ENOENT') {
44
+ console.error('Error: Python not found. Please install Python 3.9+');
45
+ console.error(' Windows: https://www.python.org/downloads/');
46
+ console.error(' macOS: brew install python3');
47
+ console.error(' Linux: apt install python3 python3-pip');
48
+ process.exit(1);
49
+ }
50
+ console.error('Error:', err.message);
51
+ process.exit(1);
52
+ });
53
+
54
+ child.on('exit', (code) => {
55
+ process.exit(code || 0);
56
+ });
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "stackfix",
3
+ "version": "0.2.0",
4
+ "description": "Terminal-first agentic CLI that fixes failing commands using AI",
5
+ "keywords": [
6
+ "cli",
7
+ "ai",
8
+ "developer-tools",
9
+ "agent",
10
+ "llm",
11
+ "terminal",
12
+ "debugging"
13
+ ],
14
+ "author": "StackFix Contributors",
15
+ "license": "MIT",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/dyglo/stackfix.git"
19
+ },
20
+ "bin": "bin/stackfix",
21
+ "scripts": {
22
+ "postinstall": "node scripts/postinstall.js"
23
+ },
24
+ "engines": {
25
+ "node": ">=16.0.0"
26
+ },
27
+ "os": [
28
+ "darwin",
29
+ "linux",
30
+ "win32"
31
+ ],
32
+ "files": [
33
+ "bin/",
34
+ "scripts/",
35
+ "stackfix/",
36
+ "pyproject.toml",
37
+ "README.md"
38
+ ]
39
+ }
package/pyproject.toml ADDED
@@ -0,0 +1,23 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "stackfix"
7
+ version = "0.2.0"
8
+ description = "Terminal-first agentic CLI that fixes failing commands using AI"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ dependencies = [
12
+ "requests>=2.31",
13
+ "textual>=0.55",
14
+ ]
15
+
16
+ [project.optional-dependencies]
17
+ dev = ["pytest>=7.0", "pytest-asyncio>=0.21"]
18
+
19
+ [project.scripts]
20
+ stackfix = "stackfix.cli:main"
21
+
22
+ [tool.setuptools.packages.find]
23
+ include = ["stackfix*"]
@@ -0,0 +1,13 @@
1
+ import json
2
+ from stackfix.agent import _parse_agent_response
3
+
4
+ cases = [
5
+ '{"summary":"ok","confidence":0.5,"patch_unified_diff":"","rerun_command":["pytest","-q"]}',
6
+ '{"summary":"ok","confidence":"0.8","patch_unified_diff":null,"rerun_command":"pytest -q"}',
7
+ '{"summary":"ok"}',
8
+ 'plain text response',
9
+ ]
10
+
11
+ for i, content in enumerate(cases, 1):
12
+ result = _parse_agent_response(content)
13
+ print(f"case {i}: summary={result.get('summary')!r} rerun={result.get('rerun_command')} warning={result.get('_warning')}")
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * StackFix postinstall script
5
+ * Sets up Python virtual environment and installs dependencies
6
+ */
7
+
8
+ const { execSync, spawn } = require('child_process');
9
+ const path = require('path');
10
+ const fs = require('fs');
11
+
12
+ const packageRoot = path.resolve(__dirname, '..');
13
+ const venvPath = path.join(packageRoot, '.venv');
14
+ const isWindows = process.platform === 'win32';
15
+
16
+ // ANSI colors
17
+ const GREEN = '\x1b[32m';
18
+ const YELLOW = '\x1b[33m';
19
+ const RED = '\x1b[31m';
20
+ const RESET = '\x1b[0m';
21
+ const BOLD = '\x1b[1m';
22
+
23
+ function log(msg) {
24
+ console.log(`${BOLD}[stackfix]${RESET} ${msg}`);
25
+ }
26
+
27
+ function success(msg) {
28
+ console.log(`${GREEN}✓${RESET} ${msg}`);
29
+ }
30
+
31
+ function warn(msg) {
32
+ console.log(`${YELLOW}⚠${RESET} ${msg}`);
33
+ }
34
+
35
+ function error(msg) {
36
+ console.error(`${RED}✗${RESET} ${msg}`);
37
+ }
38
+
39
+ // Find Python 3.9+
40
+ function findPython() {
41
+ const candidates = isWindows
42
+ ? ['python', 'python3', 'py -3']
43
+ : ['python3', 'python'];
44
+
45
+ for (const cmd of candidates) {
46
+ try {
47
+ const version = execSync(`${cmd} --version 2>&1`, { encoding: 'utf8' }).trim();
48
+ const match = version.match(/Python (\d+)\.(\d+)/);
49
+ if (match) {
50
+ const major = parseInt(match[1], 10);
51
+ const minor = parseInt(match[2], 10);
52
+ if (major === 3 && minor >= 9) {
53
+ return { cmd, version };
54
+ }
55
+ }
56
+ } catch {
57
+ // Try next candidate
58
+ }
59
+ }
60
+ return null;
61
+ }
62
+
63
+ // Main installation
64
+ async function main() {
65
+ log('Setting up StackFix...');
66
+
67
+ // Find Python
68
+ const python = findPython();
69
+ if (!python) {
70
+ error('Python 3.9+ is required but not found.');
71
+ console.log('');
72
+ console.log('Please install Python 3.9 or later:');
73
+ console.log(' Windows: https://www.python.org/downloads/');
74
+ console.log(' macOS: brew install python3');
75
+ console.log(' Linux: apt install python3 python3-pip');
76
+ process.exit(1);
77
+ }
78
+
79
+ success(`Found ${python.version} (${python.cmd})`);
80
+
81
+ // Create venv if it doesn't exist
82
+ if (!fs.existsSync(venvPath)) {
83
+ log('Creating virtual environment...');
84
+ try {
85
+ execSync(`${python.cmd} -m venv "${venvPath}"`, {
86
+ cwd: packageRoot,
87
+ stdio: 'inherit'
88
+ });
89
+ success('Virtual environment created');
90
+ } catch (err) {
91
+ error('Failed to create virtual environment');
92
+ console.log('Try running: pip install --user stackfix');
93
+ process.exit(1);
94
+ }
95
+ } else {
96
+ success('Virtual environment exists');
97
+ }
98
+
99
+ // Determine pip path
100
+ const pipPath = isWindows
101
+ ? path.join(venvPath, 'Scripts', 'pip.exe')
102
+ : path.join(venvPath, 'bin', 'pip');
103
+
104
+ // Install package in editable mode
105
+ log('Installing StackFix...');
106
+ try {
107
+ execSync(`"${pipPath}" install -e "${packageRoot}" --quiet`, {
108
+ cwd: packageRoot,
109
+ stdio: 'inherit'
110
+ });
111
+ success('StackFix installed successfully');
112
+ } catch (err) {
113
+ error('Failed to install StackFix');
114
+ process.exit(1);
115
+ }
116
+
117
+ console.log('');
118
+ log('Setup complete! Run "stackfix" to start.');
119
+ console.log('');
120
+ console.log('Quick start:');
121
+ console.log(' stackfix # Launch interactive TUI');
122
+ console.log(' stackfix --prompt "..." # Single prompt mode');
123
+ console.log(' stackfix -- pytest -v # Wrap and fix a command');
124
+ console.log('');
125
+ }
126
+
127
+ main().catch((err) => {
128
+ error(err.message);
129
+ process.exit(1);
130
+ });
@@ -0,0 +1 @@
1
+ __all__ = ["cli"]
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+ if __name__ == "__main__":
4
+ main()