@m14i/sith 1.22.0 → 1.23.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 CHANGED
@@ -8,163 +8,115 @@
8
8
 
9
9
  Standardize and share your OpenCode setup with a fully dockerized environment, designed for seamless collaboration and CI integration.
10
10
 
11
- ## Usage
11
+ ---
12
12
 
13
- ### Installation
13
+ ## Why?
14
14
 
15
- **Install globally (recommended):**
16
- ```bash
17
- npm install -g @m14i/sith
18
- ```
19
-
20
- **Or use npx (slower, pulls image every time):**
21
- ```bash
22
- npx @m14i/sith@latest
23
- ```
15
+ AI coding tools are powerful in isolation. They become fragile at scale:
24
16
 
25
- ### Quick Start
17
+ - **Context drift** — every developer has a different CLAUDE.md, different tool versions, different configs. The AI sees a different project depending on who's running it.
18
+ - **No CI path** — running `opencode` or `claude` in a pipeline requires wiring tokens, installing tools, and hoping the environment matches local.
19
+ - **Multiple tools** — Claude Code and OpenCode serve different use cases (Anthropic auth vs GitHub Copilot). Switching between them shouldn't require manual setup.
26
20
 
27
- ```bash
28
- # Interactive terminal UI (default)
29
- sith
30
- # Type your prompt to start OpenCode with that task
31
- # Or use slash commands: /shell, /config, /help
32
-
33
- # Direct commands
34
- sith --it # Launch Docker shell immediately
35
- sith --pull # Pull prebuilt image
36
- sith --build # Build from scratch
37
- sith --legacy # Use legacy menu interface
38
- ```
21
+ Sith solves this by packaging both tools, all config, and your team's context into a single Docker image. One pull, same environment, everywhere.
39
22
 
40
- ### Distribution Options
23
+ | Problem | Sith answer |
24
+ |---------|-------------|
25
+ | Inconsistent context across team | Shared `~/.sith/` skills + CLAUDE.md, mounted at runtime |
26
+ | AI tools hard to run in CI | Prebuilt signed image + token injection via env vars |
27
+ | Claude Code vs OpenCode friction | Both available, same container, same command |
28
+ | "Works on my machine" builds | Nix-pinned dependencies inside Docker |
41
29
 
42
- | Method | Command | Speed | Trust Model | Use Case |
43
- |--------|---------|-------|-------------|----------|
44
- | **Prebuilt (Recommended)** | `sith --pull` | ⚡ Fast | GitHub Actions + Cosign | Production, CI/CD |
45
- | **Local Build** | `sith --build` | 🐌 Slow | Your machine | Air-gapped, custom builds |
30
+ ---
46
31
 
47
- ### Commands
32
+ ## Docker
48
33
 
49
- | Command | Description |
50
- |---------|-------------|
51
- | `sith` | Interactive terminal UI (Claude Code style) |
52
- | `sith --it` | Launch Docker shell immediately |
53
- | `sith --pull` | Pull prebuilt image from GHCR |
54
- | `sith --build` | Build Docker image from scratch |
55
- | `sith --legacy` | Use legacy menu interface |
56
- | `sith --help` | Show all available commands |
34
+ The recommended path. One image, works locally and in CI.
57
35
 
58
- ### Terminal UI Usage
36
+ ### Install the CLI
59
37
 
60
- When you run `sith`, you get an interactive terminal interface:
38
+ ```bash
39
+ npm install -g @m14i/sith
40
+ ```
61
41
 
62
- **Prompt input:**
63
- - Type any text → Starts OpenCode with that prompt using Claude Sonnet 4.6
64
- - Example: `Fix authentication bug` → OpenCode launches with this task
42
+ Or without installing:
65
43
 
66
- **Slash commands:**
67
- - `/shell` → Start Docker shell only (no OpenCode)
68
- - `/config` → Open configuration menu (pull/build options)
69
- - `/help` → Show available commands
44
+ ```bash
45
+ npx @m14i/sith@latest
46
+ ```
70
47
 
71
- **Navigation:**
72
- - `Ctrl+C` or `Esc` → Exit terminal UI
48
+ ### Get the image
73
49
 
74
- ### Prebuilt Image Details
50
+ **Prebuilt (recommended) — pull a signed image from GHCR:**
75
51
 
76
- **Pull and verify:**
77
52
  ```bash
78
- # Pull (supports linux/amd64 and linux/arm64)
79
53
  sith --pull
54
+ ```
55
+
56
+ Supports `linux/amd64` and `linux/arm64`. Images are signed with cosign and include an SBOM.
80
57
 
81
- # Or use Docker directly
82
- docker pull ghcr.io/merzoukemanouri/sith:latest
58
+ **Verify the signature (optional):**
83
59
 
84
- # Verify signature (optional)
60
+ ```bash
85
61
  cosign verify \
86
62
  --certificate-identity-regexp="https://github.com/MerzoukeMansouri/sith" \
87
63
  --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
88
64
  ghcr.io/merzoukemanouri/sith:latest
89
65
  ```
90
66
 
91
- **Benefits:**
92
- - ✅ Fast - no build time
93
- - ✅ Multi-platform - amd64 and arm64
94
- - ✅ Signed - cosign verification
95
- - ✅ SBOM - supply chain transparency
96
- - ✅ Auto-updated - tracks releases
67
+ **Build from scratch — full control, no external trust:**
97
68
 
98
- ## Authentication
99
-
100
- Sith supports two AI providers: **Claude Code** (via Anthropic) and **OpenCode** (via GitHub Copilot).
101
-
102
- ### Claude Code (claude CLI)
103
-
104
- Sith ships with the `claude` CLI. Authenticate it with your Anthropic account using a long-lived OAuth token — no API key required.
105
-
106
- **Step 1 — Generate the token (once, on your local machine):**
107
69
  ```bash
108
- claude setup-token
70
+ sith --build
109
71
  ```
110
- Follow the browser prompt, then copy the printed token. It is valid for one year and scoped to inference only.
111
72
 
112
- **Step 2 Export it:**
113
- ```bash
114
- export CLAUDE_CODE_OAUTH_TOKEN=your_token_here
115
- ```
73
+ | | `sith --pull` | `sith --build` |
74
+ |--|--------------|----------------|
75
+ | Speed | Fast | Slow |
76
+ | Trust | GitHub Actions + Cosign | Your machine |
77
+ | Use case | Daily use, CI/CD | Air-gapped, custom builds |
116
78
 
117
- **Make it persistent (add to ~/.zshrc or ~/.bashrc):**
118
- ```bash
119
- export CLAUDE_CODE_OAUTH_TOKEN=your_token_here
120
- ```
79
+ ### Use it
80
+
81
+ **Interactive TUI** — type a prompt or use slash commands:
121
82
 
122
- **Verify:**
123
83
  ```bash
124
- claude auth status
125
- # Should show: "loggedIn": true, "authMethod": "claude.ai"
84
+ sith
126
85
  ```
127
86
 
128
- **Requirements:** Claude Pro, Max, Team, or Enterprise subscription.
87
+ | In the TUI | What it does |
88
+ |------------|-------------|
89
+ | Type any text + Enter | Starts OpenCode with that prompt |
90
+ | `/shell` | Drop into Docker shell (no AI) |
91
+ | `/claude` | Switch active tool to Claude Code |
92
+ | `/opencode` | Switch active tool to OpenCode |
93
+ | `/config` | Pull / build options |
94
+ | `/help` | Show commands |
95
+ | `Ctrl+C` / `Esc` | Exit |
129
96
 
130
- ### GitHub Copilot (opencode CLI)
97
+ **Direct commands** skip the TUI:
131
98
 
132
- Sith uses **Claude Sonnet 4.6 via GitHub Copilot** by default for OpenCode. Requires a GitHub token with Copilot access.
133
-
134
- **Automatic (recommended):**
135
- If you have GitHub CLI (`gh`) installed and authenticated, Sith automatically fetches your token:
136
99
  ```bash
137
- sith # Auto-detects token via gh auth token
100
+ sith shell # Raw Nix shell inside Docker (alias: sith --it)
101
+ sith opencode -p "fix the bug" # OpenCode starts immediately with your task
102
+ sith claude -p "fix the bug" # Claude Code starts immediately with your task
138
103
  ```
139
104
 
140
- **Manual token:**
141
- If you don't have `gh` CLI or prefer manual setup:
105
+ **Skills:**
142
106
 
143
- 1. Ensure you have GitHub Copilot access
144
- 2. Create a token at https://github.com/settings/tokens
145
- 3. Required scopes: `copilot`, `repo`, `read:org`
146
- 4. Export it:
147
107
  ```bash
148
- export GITHUB_TOKEN=gho_your_token_here
149
- sith
108
+ sith skills # Install / manage skills from catalog (~/.sith/skills/)
150
109
  ```
151
110
 
152
- **Make it persistent (add to ~/.zshrc or ~/.bashrc):**
153
- ```bash
154
- export GITHUB_TOKEN=$(gh auth token)
155
- ```
111
+ ### Cleanup & Uninstall
156
112
 
157
- **Inside container:**
158
- Once OpenCode starts, authenticate with GitHub Copilot:
159
113
  ```bash
160
- opencode providers login
161
- # Follow prompts to authenticate with GitHub
114
+ sith --docker-cleanup # Remove sith Docker images (sith:latest + prebuilt GHCR image)
115
+ sith --uninstall # Remove ~/.sith/ (skills, config, nix files)
162
116
  ```
163
117
 
164
118
  ### CI / GitHub Actions
165
119
 
166
- Add both tokens as repository secrets, then pass them to the container:
167
-
168
120
  ```yaml
169
121
  - name: Run sith
170
122
  env:
@@ -177,98 +129,70 @@ Add both tokens as repository secrets, then pass them to the container:
177
129
  ghcr.io/merzoukemanouri/sith:latest "claude auth status"
178
130
  ```
179
131
 
180
- Generate `CLAUDE_CODE_OAUTH_TOKEN` once with `claude setup-token` and store it in **Settings → Secrets → Actions** as `CLAUDE_CODE_OAUTH_TOKEN`.
132
+ See [Authentication](./doc/AUTH_CLAUDE.md) for how to generate the tokens.
181
133
 
182
- ## Features
134
+ ---
183
135
 
184
- - **Claude Code-style UI**: Interactive terminal interface with prompt input and slash commands
185
- - **OpenCode Integration**: Start coding with a simple text prompt
186
- - **Model Selection**: Uses Claude Sonnet 4.6 via GitHub Copilot by default
187
- - **Prebuilt Images**: Pull verified images from GitHub Container Registry
188
- - **Image Signing**: All images signed with cosign for supply chain security
189
- - **SBOM Attestation**: Software Bill of Materials included with every image
190
- - **Dockerized Environment**: Consistent setup across machines
191
- - **Nix Integration**: Full development environment with all tools
192
- - **CI-Ready**: Standardize builds across local and CI pipelines
193
- - **Non-root User**: Images run as non-root user (UID 1000) for better security
136
+ ## Direct Nix
194
137
 
195
- ## Security
138
+ No Docker. Runs the same Nix environment natively on your machine.
196
139
 
197
- ### Image Verification
140
+ ```bash
141
+ sith --nix-install # Install Nix package manager (once)
142
+ sith --nix # Launch Nix shell directly
143
+ ```
198
144
 
199
- All Docker images published to `ghcr.io/merzoukemanouri/sith` are:
200
- - **Signed with cosign** using keyless signing (OIDC)
201
- - **Include SBOM** (Software Bill of Materials) for transparency
202
- - **Built automatically** via GitHub Actions with provenance
145
+ Or via the `nix` subcommand:
146
+
147
+ ```bash
148
+ sith nix --install # Install Nix
149
+ sith nix --shell # Run Nix shell
150
+ ```
203
151
 
204
- See [SECURITY.md](./SECURITY.md) for detailed security practices and considerations.
152
+ **Cleanup:**
205
153
 
206
- ### Trust Model
154
+ ```bash
155
+ sith --nix-cleanup # Remove ~/.sith/nix/ + run nix-collect-garbage -d
156
+ sith --nix-uninstall # Fully remove Nix from system (daemon, /nix/store) — needs sudo
157
+ ```
207
158
 
208
- **Prebuilt Images:**
209
- - Built by GitHub Actions on public infrastructure
210
- - Signed with Sigstore keyless signing
211
- - Verifiable provenance chain from source to image
212
- - Trade-off: Trust GitHub's build infrastructure
159
+ See [doc/NIX_INSTALLATION.md](./doc/NIX_INSTALLATION.md) for full setup guide.
213
160
 
214
- **Local Builds:**
215
- - Full control over build environment
216
- - Can inspect Dockerfile before building
217
- - No dependency on external registries
218
- - Trade-off: Slower, manual security updates
161
+ ---
219
162
 
220
- For more details, see the [Docker Distribution Guide](./doc/QUICKSTART.md#docker-distribution).
163
+ ## Authentication
221
164
 
222
- ## Development
165
+ Two AI providers, two token setups:
223
166
 
224
- For contributors working on the CLI:
167
+ - **Claude Code** (Anthropic OAuth) → [doc/AUTH_CLAUDE.md](./doc/AUTH_CLAUDE.md)
168
+ - **OpenCode** (GitHub Copilot) → [doc/AUTH_OPENCODE.md](./doc/AUTH_OPENCODE.md)
225
169
 
226
- ```bash
227
- # Install dependencies
228
- pnpm install
170
+ ---
229
171
 
230
- # Run in development mode (no build)
231
- pnpm dev
172
+ ## Development
232
173
 
233
- # Build and test
174
+ ```bash
175
+ pnpm install # Install dependencies
176
+ pnpm dev # Run in development mode (no build)
234
177
  pnpm dev:build # Build and run CLI
235
178
  pnpm dev:shell # Build and launch shell
236
-
237
- # Type checking
238
- pnpm typecheck
239
-
240
- # Clean build artifacts
241
- pnpm clean
179
+ pnpm typecheck # Type checking
180
+ pnpm clean # Clean build artifacts
242
181
  ```
243
182
 
244
- ## Publishing
245
-
246
- Automated releases using semantic-release and conventional commits.
183
+ ---
247
184
 
248
- ### For Maintainers
185
+ ## Publishing
249
186
 
250
- **Commit Format:**
251
- - `feat:` - New feature (triggers minor version bump)
252
- - `fix:` - Bug fix (triggers patch version bump)
253
- - `BREAKING CHANGE:` - Breaking change (triggers major version bump)
254
- - `chore:`, `docs:`, `style:` - No release
187
+ Automated via semantic-release and conventional commits.
255
188
 
256
- **Release Process:**
257
- 1. Commit changes following conventional commit format
258
- 2. Push to `main` branch
259
- 3. GitHub Action automatically:
260
- - Analyzes commits and determines version bump
261
- - Generates CHANGELOG.md
262
- - Creates GitHub release
263
- - Publishes to npm
189
+ | Prefix | Effect |
190
+ |--------|--------|
191
+ | `feat:` | Minor version bump |
192
+ | `fix:` | Patch version bump |
193
+ | `BREAKING CHANGE:` | Major version bump |
194
+ | `chore:` `docs:` `style:` | No release |
264
195
 
265
- **Example:**
266
- ```bash
267
- git commit -m "feat: add new interactive menu option"
268
- git push origin main
269
- # Automatic release triggered!
270
- ```
196
+ Push to `main` → GitHub Action bumps version, generates CHANGELOG, publishes to npm.
271
197
 
272
- **Requirements:**
273
- - `NPM_TOKEN` secret configured in GitHub repository settings
274
- - Commits must follow conventional commit format
198
+ **Requirements:** `NPM_TOKEN` secret in repository settings.
@@ -1,4 +1,3 @@
1
1
  import type { DockerCommandOptions } from "../types.js";
2
2
  export declare function dockerCommand(options: DockerCommandOptions): Promise<void>;
3
- export declare function runShellDirect(): Promise<void>;
4
3
  //# sourceMappingURL=docker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["file:///home/runner/work/sith/sith/src/commands/docker.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAEX,oBAAoB,EAEpB,MAAM,aAAa,CAAC;AAqTrB,wBAAsB,aAAa,CAClC,OAAO,EAAE,oBAAoB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAoBf;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAEpD"}
1
+ {"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["file:///home/runner/work/sith/sith/src/commands/docker.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAwBxD,wBAAsB,aAAa,CAClC,OAAO,EAAE,oBAAoB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAUf"}
@@ -0,0 +1,5 @@
1
+ export declare function dockerCleanupCommand(): Promise<void>;
2
+ export declare function nixCleanupCommand(): Promise<void>;
3
+ export declare function nixUninstallCommand(): Promise<void>;
4
+ export declare function uninstallCommand(): Promise<void>;
5
+ //# sourceMappingURL=maintenance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maintenance.d.ts","sourceRoot":"","sources":["file:///home/runner/work/sith/sith/src/commands/maintenance.ts"],"names":[],"mappings":"AAkBA,wBAAsB,oBAAoB,kBAwBzC;AAED,wBAAsB,iBAAiB,kBAqBtC;AAED,wBAAsB,mBAAmB,kBAmExC;AAED,wBAAsB,gBAAgB,kBAwBrC"}
package/dist/index.js CHANGED
@@ -42961,35 +42961,20 @@ which.sync = whichSync
42961
42961
 
42962
42962
  /***/ }),
42963
42963
 
42964
- /***/ 5515:
42965
- /***/ ((module, __webpack_exports__, __nccwpck_require__) => {
42964
+ /***/ 3361:
42965
+ /***/ ((__unused_webpack_module, __webpack_exports__, __nccwpck_require__) => {
42966
42966
 
42967
- __nccwpck_require__.a(module, async (__webpack_handle_async_dependencies__, __webpack_async_result__) => { try {
42968
42967
  /* harmony export */ __nccwpck_require__.d(__webpack_exports__, {
42969
42968
  /* harmony export */ Q: () => (/* binding */ dockerCommand)
42970
42969
  /* harmony export */ });
42971
- /* unused harmony export runShellDirect */
42972
42970
  /* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_0__ = __nccwpck_require__(3024);
42973
42971
  /* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__nccwpck_require__.n(node_fs__WEBPACK_IMPORTED_MODULE_0__);
42974
42972
  /* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_1__ = __nccwpck_require__(6760);
42975
42973
  /* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__nccwpck_require__.n(node_path__WEBPACK_IMPORTED_MODULE_1__);
42976
42974
  /* harmony import */ var node_url__WEBPACK_IMPORTED_MODULE_2__ = __nccwpck_require__(3136);
42977
42975
  /* harmony import */ var node_url__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__nccwpck_require__.n(node_url__WEBPACK_IMPORTED_MODULE_2__);
42978
- /* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_9__ = __nccwpck_require__(6181);
42979
- /* harmony import */ var ink__WEBPACK_IMPORTED_MODULE_3__ = __nccwpck_require__(3816);
42980
- /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_4__ = __nccwpck_require__(2864);
42981
- /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__nccwpck_require__.n(react__WEBPACK_IMPORTED_MODULE_4__);
42982
- /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_5__ = __nccwpck_require__(6878);
42983
- /* harmony import */ var _utils_launcher_js__WEBPACK_IMPORTED_MODULE_6__ = __nccwpck_require__(5800);
42984
- /* harmony import */ var _nix_js__WEBPACK_IMPORTED_MODULE_7__ = __nccwpck_require__(9922);
42985
- /* harmony import */ var _skills_js__WEBPACK_IMPORTED_MODULE_8__ = __nccwpck_require__(9805);
42986
- var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([ink__WEBPACK_IMPORTED_MODULE_3__, _skills_js__WEBPACK_IMPORTED_MODULE_8__]);
42987
- ([ink__WEBPACK_IMPORTED_MODULE_3__, _skills_js__WEBPACK_IMPORTED_MODULE_8__] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__);
42988
-
42989
-
42990
-
42991
-
42992
-
42976
+ /* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_4__ = __nccwpck_require__(6181);
42977
+ /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __nccwpck_require__(6878);
42993
42978
 
42994
42979
 
42995
42980
 
@@ -43001,217 +42986,15 @@ function findProjectRoot(startDir) {
43001
42986
  let currentDir = startDir;
43002
42987
  const rootPath = node_path__WEBPACK_IMPORTED_MODULE_1___default().parse(currentDir).root;
43003
42988
  while (currentDir !== rootPath) {
43004
- const dockerPath = node_path__WEBPACK_IMPORTED_MODULE_1___default().join(currentDir, _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.folderName);
42989
+ const dockerPath = node_path__WEBPACK_IMPORTED_MODULE_1___default().join(currentDir, _config_js__WEBPACK_IMPORTED_MODULE_3__/* .DOCKER_CONFIG */ .e6.folderName);
43005
42990
  if (node_fs__WEBPACK_IMPORTED_MODULE_0___default().existsSync(dockerPath) && node_fs__WEBPACK_IMPORTED_MODULE_0___default().statSync(dockerPath).isDirectory()) {
43006
42991
  return currentDir;
43007
42992
  }
43008
42993
  currentDir = node_path__WEBPACK_IMPORTED_MODULE_1___default().dirname(currentDir);
43009
42994
  }
43010
- throw new Error(`Could not find project root (${_config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.folderName}/ folder not found)`);
42995
+ throw new Error(`Could not find project root (${_config_js__WEBPACK_IMPORTED_MODULE_3__/* .DOCKER_CONFIG */ .e6.folderName}/ folder not found)`);
43011
42996
  }
43012
42997
  const rootDir = findProjectRoot(__dirname);
43013
- const menuItems = [
43014
- { label: "Enter Shell", value: "shell", icon: "🚀" },
43015
- { label: "Manage Skills", value: "skills", icon: "🧠" },
43016
- { label: "Configuration", value: "config", icon: "⚙️" },
43017
- ];
43018
- const configMenuItems = [
43019
- { label: "Pull prebuilt image (recommended)", value: "pull", icon: "📦" },
43020
- { label: "Build Docker image from scratch", value: "build", icon: "🔨" },
43021
- { label: "Install Nix locally (no Docker)", value: "nix", icon: "❄️" },
43022
- { label: "Back", value: "back", icon: "◀️" },
43023
- ];
43024
- function Logo() {
43025
- return (react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Box */ .az, { flexDirection: "column", marginBottom: 1 },
43026
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Box */ .az, { flexDirection: "column" }, _config_js__WEBPACK_IMPORTED_MODULE_5__/* .ASCII_LOGO */ .mF.map((line, index) => (
43027
- // biome-ignore lint/suspicious/noArrayIndexKey: static array, order never changes
43028
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Text */ .EY, { key: index, color: "red", bold: true }, line)))),
43029
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Box */ .az, { borderStyle: "double", borderColor: "red", paddingX: 2, marginTop: 1 },
43030
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Text */ .EY, { color: "red", bold: true }, "SITH - Docker Manager"))));
43031
- }
43032
- function BuildingSpinner({ step }) {
43033
- const [frame, setFrame] = (0,react__WEBPACK_IMPORTED_MODULE_4__.useState)(0);
43034
- (0,react__WEBPACK_IMPORTED_MODULE_4__.useEffect)(() => {
43035
- const timer = setInterval(() => {
43036
- setFrame((prev) => (prev + 1) % _config_js__WEBPACK_IMPORTED_MODULE_5__/* .SPINNER_CONFIG */ .ZC.frames.length);
43037
- }, _config_js__WEBPACK_IMPORTED_MODULE_5__/* .SPINNER_CONFIG */ .ZC.interval);
43038
- return () => clearInterval(timer);
43039
- }, []);
43040
- return (react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Box */ .az, { flexDirection: "column", marginTop: 1 },
43041
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Text */ .EY, { color: "cyan" },
43042
- _config_js__WEBPACK_IMPORTED_MODULE_5__/* .SPINNER_CONFIG */ .ZC.frames[frame],
43043
- " ",
43044
- step)));
43045
- }
43046
- function Menu() {
43047
- const { exit } = (0,ink__WEBPACK_IMPORTED_MODULE_3__/* .useApp */ .nm)();
43048
- const [selectedIndex, setSelectedIndex] = (0,react__WEBPACK_IMPORTED_MODULE_4__.useState)(0);
43049
- const [isProcessing, setIsProcessing] = (0,react__WEBPACK_IMPORTED_MODULE_4__.useState)(false);
43050
- const [processStep, setProcessStep] = (0,react__WEBPACK_IMPORTED_MODULE_4__.useState)("");
43051
- const [processComplete, setProcessComplete] = (0,react__WEBPACK_IMPORTED_MODULE_4__.useState)(false);
43052
- const [processError, setProcessError] = (0,react__WEBPACK_IMPORTED_MODULE_4__.useState)(null);
43053
- const [currentMenu, setCurrentMenu] = (0,react__WEBPACK_IMPORTED_MODULE_4__.useState)("main");
43054
- (0,ink__WEBPACK_IMPORTED_MODULE_3__/* .useInput */ .Ge)((_input, key) => {
43055
- if (isProcessing) {
43056
- return;
43057
- }
43058
- // Exit on any key press when process is complete or errored
43059
- if (processComplete || processError) {
43060
- exit();
43061
- return;
43062
- }
43063
- const items = currentMenu === "main" ? menuItems : configMenuItems;
43064
- if (key.upArrow) {
43065
- setSelectedIndex((prev) => (prev > 0 ? prev - 1 : items.length - 1));
43066
- }
43067
- else if (key.downArrow) {
43068
- setSelectedIndex((prev) => (prev < items.length - 1 ? prev + 1 : 0));
43069
- }
43070
- else if (key.return) {
43071
- handleSelection(items[selectedIndex].value);
43072
- }
43073
- });
43074
- async function handleSelection(value) {
43075
- switch (value) {
43076
- case "shell":
43077
- exit();
43078
- await (0,_utils_launcher_js__WEBPACK_IMPORTED_MODULE_6__/* .launchShell */ .k1)();
43079
- return;
43080
- case "skills":
43081
- exit();
43082
- (0,_skills_js__WEBPACK_IMPORTED_MODULE_8__/* .skillsCommand */ .a)();
43083
- return;
43084
- case "config":
43085
- setCurrentMenu("config");
43086
- setSelectedIndex(0);
43087
- return;
43088
- case "back":
43089
- setCurrentMenu("main");
43090
- setSelectedIndex(0);
43091
- return;
43092
- case "pull":
43093
- await handlePullCommand();
43094
- break;
43095
- case "build":
43096
- await handleBuildCommand();
43097
- break;
43098
- case "nix":
43099
- await handleNixCommand();
43100
- break;
43101
- default:
43102
- break;
43103
- }
43104
- }
43105
- async function handlePullCommand() {
43106
- setIsProcessing(true);
43107
- setProcessStep("Pulling prebuilt Docker image...");
43108
- try {
43109
- await (0,execa__WEBPACK_IMPORTED_MODULE_9__/* .execa */ .Ho)("docker", ["pull", _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.prebuiltImage], {
43110
- stdio: "inherit",
43111
- });
43112
- // Tag the pulled image with local name for compatibility
43113
- await (0,execa__WEBPACK_IMPORTED_MODULE_9__/* .execa */ .Ho)("docker", ["tag", _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.prebuiltImage, _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.imageName], {
43114
- stdio: "inherit",
43115
- });
43116
- setIsProcessing(false);
43117
- setProcessComplete(true);
43118
- setProcessStep("");
43119
- }
43120
- catch (error) {
43121
- setIsProcessing(false);
43122
- setProcessError(error instanceof Error ? error.message : "Pull failed");
43123
- }
43124
- }
43125
- async function handleNixCommand() {
43126
- setIsProcessing(true);
43127
- setProcessStep("Installing Nix locally...");
43128
- try {
43129
- await (0,_nix_js__WEBPACK_IMPORTED_MODULE_7__/* .installNix */ .Fh)();
43130
- await (0,_nix_js__WEBPACK_IMPORTED_MODULE_7__/* .copyNixFiles */ .Qi)();
43131
- setIsProcessing(false);
43132
- setProcessComplete(true);
43133
- setProcessStep("");
43134
- }
43135
- catch (error) {
43136
- setIsProcessing(false);
43137
- setProcessError(error instanceof Error ? error.message : "Nix installation failed");
43138
- }
43139
- }
43140
- async function handleBuildCommand() {
43141
- setIsProcessing(true);
43142
- setProcessStep("Building Docker image from scratch...");
43143
- try {
43144
- const dockerfilePath = node_path__WEBPACK_IMPORTED_MODULE_1___default().join(rootDir, _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.folderName, _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.dockerfileName);
43145
- if (!node_fs__WEBPACK_IMPORTED_MODULE_0___default().existsSync(dockerfilePath)) {
43146
- throw new Error(`Dockerfile not found at: ${dockerfilePath}`);
43147
- }
43148
- await (0,execa__WEBPACK_IMPORTED_MODULE_9__/* .execa */ .Ho)("docker", ["build", "-f", dockerfilePath, "-t", _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.imageName, rootDir], {
43149
- stdio: "inherit",
43150
- });
43151
- setIsProcessing(false);
43152
- setProcessComplete(true);
43153
- setProcessStep("");
43154
- }
43155
- catch (error) {
43156
- setIsProcessing(false);
43157
- setProcessError(error instanceof Error ? error.message : "Operation failed");
43158
- }
43159
- }
43160
- // Render error state
43161
- if (processError) {
43162
- return (react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Box */ .az, { flexDirection: "column" },
43163
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(Logo, null),
43164
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Box */ .az, { marginTop: 1 },
43165
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Text */ .EY, { color: "red" },
43166
- "\u274C Operation failed: ",
43167
- processError)),
43168
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Box */ .az, { marginTop: 1 },
43169
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Text */ .EY, { dimColor: true }, "Press any key to exit..."))));
43170
- }
43171
- // Render success state
43172
- if (processComplete) {
43173
- return (react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Box */ .az, { flexDirection: "column" },
43174
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(Logo, null),
43175
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Box */ .az, { marginTop: 1 },
43176
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Text */ .EY, { color: "green" }, "\u2705 Docker image ready!")),
43177
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Box */ .az, { marginTop: 1 },
43178
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Text */ .EY, { dimColor: true },
43179
- "Image: ",
43180
- _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.imageName)),
43181
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Box */ .az, { marginTop: 1 },
43182
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Text */ .EY, { dimColor: true }, "Run: sith --it")),
43183
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Box */ .az, { marginTop: 1 },
43184
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Text */ .EY, { dimColor: true }, "Press any key to exit..."))));
43185
- }
43186
- // Render processing state
43187
- if (isProcessing) {
43188
- return (react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Box */ .az, { flexDirection: "column" },
43189
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(Logo, null),
43190
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(BuildingSpinner, { step: processStep }),
43191
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Box */ .az, { marginTop: 1 },
43192
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Text */ .EY, { dimColor: true },
43193
- "Root: ",
43194
- rootDir))));
43195
- }
43196
- // Render menu state
43197
- const items = currentMenu === "main" ? menuItems : configMenuItems;
43198
- const menuTitle = currentMenu === "main" ? "What would you like to do?" : "Configuration";
43199
- return (react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Box */ .az, { flexDirection: "column" },
43200
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(Logo, null),
43201
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Box */ .az, { flexDirection: "column", marginTop: 1 },
43202
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Text */ .EY, { bold: true }, menuTitle),
43203
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Box */ .az, { flexDirection: "column", marginTop: 1 }, items.map((item, index) => {
43204
- const isSelected = index === selectedIndex;
43205
- return (react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Box */ .az, { key: item.value, marginY: 0 },
43206
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Text */ .EY, { color: isSelected ? "cyan" : undefined },
43207
- isSelected ? "❯ " : " ",
43208
- item.icon,
43209
- " ",
43210
- item.label)));
43211
- }))),
43212
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Box */ .az, { marginTop: 1 },
43213
- react__WEBPACK_IMPORTED_MODULE_4___default().createElement(ink__WEBPACK_IMPORTED_MODULE_3__/* .Text */ .EY, { dimColor: true }, "Use arrow keys to navigate, Enter to select"))));
43214
- }
43215
42998
  async function dockerCommand(options) {
43216
42999
  if (options.build) {
43217
43000
  await buildDocker();
@@ -43221,36 +43004,25 @@ async function dockerCommand(options) {
43221
43004
  await pullDocker();
43222
43005
  return;
43223
43006
  }
43224
- // Check if stdin supports raw mode (interactive terminal)
43225
- if (!process.stdin.isTTY) {
43226
- console.error("Error: Interactive mode requires a TTY terminal");
43227
- console.error("Use --build or --pull flag for non-interactive mode");
43228
- process.exit(1);
43229
- }
43230
- // Render the interactive menu
43231
- (0,ink__WEBPACK_IMPORTED_MODULE_3__/* .render */ .XX)(react__WEBPACK_IMPORTED_MODULE_4___default().createElement(Menu, null));
43232
- }
43233
- async function runShellDirect() {
43234
- await launchShell();
43235
43007
  }
43236
43008
  async function pullDocker() {
43237
43009
  console.log("📦 Pulling prebuilt Docker image...");
43238
43010
  console.log();
43239
43011
  try {
43240
- console.log(`Source: ${_config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.prebuiltImage}`);
43241
- console.log(`Target: ${_config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.imageName}`);
43012
+ console.log(`Source: ${_config_js__WEBPACK_IMPORTED_MODULE_3__/* .DOCKER_CONFIG */ .e6.prebuiltImage}`);
43013
+ console.log(`Target: ${_config_js__WEBPACK_IMPORTED_MODULE_3__/* .DOCKER_CONFIG */ .e6.imageName}`);
43242
43014
  console.log();
43243
- await (0,execa__WEBPACK_IMPORTED_MODULE_9__/* .execa */ .Ho)("docker", ["pull", _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.prebuiltImage], {
43015
+ await (0,execa__WEBPACK_IMPORTED_MODULE_4__/* .execa */ .Ho)("docker", ["pull", _config_js__WEBPACK_IMPORTED_MODULE_3__/* .DOCKER_CONFIG */ .e6.prebuiltImage], {
43244
43016
  stdio: "inherit",
43245
43017
  });
43246
43018
  console.log();
43247
43019
  console.log("🏷️ Tagging image for local use...");
43248
- await (0,execa__WEBPACK_IMPORTED_MODULE_9__/* .execa */ .Ho)("docker", ["tag", _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.prebuiltImage, _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.imageName], {
43020
+ await (0,execa__WEBPACK_IMPORTED_MODULE_4__/* .execa */ .Ho)("docker", ["tag", _config_js__WEBPACK_IMPORTED_MODULE_3__/* .DOCKER_CONFIG */ .e6.prebuiltImage, _config_js__WEBPACK_IMPORTED_MODULE_3__/* .DOCKER_CONFIG */ .e6.imageName], {
43249
43021
  stdio: "inherit",
43250
43022
  });
43251
43023
  console.log();
43252
43024
  console.log("✅ Docker image ready!");
43253
- console.log(`Image: ${_config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.imageName}`);
43025
+ console.log(`Image: ${_config_js__WEBPACK_IMPORTED_MODULE_3__/* .DOCKER_CONFIG */ .e6.imageName}`);
43254
43026
  console.log();
43255
43027
  console.log("Run: sith --it");
43256
43028
  }
@@ -43266,19 +43038,19 @@ async function buildDocker() {
43266
43038
  console.log("🔨 Building Docker image from scratch...");
43267
43039
  console.log();
43268
43040
  try {
43269
- const dockerfilePath = node_path__WEBPACK_IMPORTED_MODULE_1___default().join(rootDir, _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.folderName, _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.dockerfileName);
43041
+ const dockerfilePath = node_path__WEBPACK_IMPORTED_MODULE_1___default().join(rootDir, _config_js__WEBPACK_IMPORTED_MODULE_3__/* .DOCKER_CONFIG */ .e6.folderName, _config_js__WEBPACK_IMPORTED_MODULE_3__/* .DOCKER_CONFIG */ .e6.dockerfileName);
43270
43042
  if (!node_fs__WEBPACK_IMPORTED_MODULE_0___default().existsSync(dockerfilePath)) {
43271
43043
  throw new Error(`Dockerfile not found at: ${dockerfilePath}`);
43272
43044
  }
43273
43045
  console.log(`Root: ${rootDir}`);
43274
43046
  console.log(`Dockerfile: ${dockerfilePath}`);
43275
43047
  console.log();
43276
- await (0,execa__WEBPACK_IMPORTED_MODULE_9__/* .execa */ .Ho)("docker", ["build", "-f", dockerfilePath, "-t", _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.imageName, rootDir], {
43048
+ await (0,execa__WEBPACK_IMPORTED_MODULE_4__/* .execa */ .Ho)("docker", ["build", "-f", dockerfilePath, "-t", _config_js__WEBPACK_IMPORTED_MODULE_3__/* .DOCKER_CONFIG */ .e6.imageName, rootDir], {
43277
43049
  stdio: "inherit",
43278
43050
  });
43279
43051
  console.log();
43280
43052
  console.log("✅ Docker image built successfully!");
43281
- console.log(`Image: ${_config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.imageName}`);
43053
+ console.log(`Image: ${_config_js__WEBPACK_IMPORTED_MODULE_3__/* .DOCKER_CONFIG */ .e6.imageName}`);
43282
43054
  console.log();
43283
43055
  console.log("Run: sith --it");
43284
43056
  }
@@ -43291,8 +43063,162 @@ async function buildDocker() {
43291
43063
  }
43292
43064
  }
43293
43065
 
43294
- __webpack_async_result__();
43295
- } catch(e) { __webpack_async_result__(e); } });
43066
+
43067
+ /***/ }),
43068
+
43069
+ /***/ 6656:
43070
+ /***/ ((__unused_webpack_module, __webpack_exports__, __nccwpck_require__) => {
43071
+
43072
+
43073
+ // EXPORTS
43074
+ __nccwpck_require__.d(__webpack_exports__, {
43075
+ Yb: () => (/* binding */ dockerCleanupCommand),
43076
+ V: () => (/* binding */ nixCleanupCommand),
43077
+ be: () => (/* binding */ nixUninstallCommand),
43078
+ Wd: () => (/* binding */ uninstallCommand)
43079
+ });
43080
+
43081
+ // EXTERNAL MODULE: external "node:child_process"
43082
+ var external_node_child_process_ = __nccwpck_require__(1421);
43083
+ // EXTERNAL MODULE: external "node:fs"
43084
+ var external_node_fs_ = __nccwpck_require__(3024);
43085
+ // EXTERNAL MODULE: external "node:os"
43086
+ var external_node_os_ = __nccwpck_require__(8161);
43087
+ // EXTERNAL MODULE: external "node:path"
43088
+ var external_node_path_ = __nccwpck_require__(6760);
43089
+ ;// CONCATENATED MODULE: external "node:readline"
43090
+ const external_node_readline_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:readline");
43091
+ // EXTERNAL MODULE: ./node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/index.js + 3 modules
43092
+ var source = __nccwpck_require__(9611);
43093
+ // EXTERNAL MODULE: ./src/config.ts
43094
+ var config = __nccwpck_require__(6878);
43095
+ ;// CONCATENATED MODULE: ./src/commands/maintenance.ts
43096
+
43097
+
43098
+
43099
+
43100
+
43101
+
43102
+
43103
+ async function maintenance_confirm(question) {
43104
+ const rl = (0,external_node_readline_namespaceObject.createInterface)({ input: process.stdin, output: process.stdout });
43105
+ return new Promise((resolve) => {
43106
+ rl.question(question, (answer) => {
43107
+ rl.close();
43108
+ resolve(answer.toLowerCase() === "y");
43109
+ });
43110
+ });
43111
+ }
43112
+ async function dockerCleanupCommand() {
43113
+ console.log(source/* default */.Ay.cyan("Cleaning up sith Docker images..."));
43114
+ const images = [config/* DOCKER_CONFIG */.e6.imageName, config/* DOCKER_CONFIG */.e6.prebuiltImage];
43115
+ let removed = 0;
43116
+ for (const image of images) {
43117
+ try {
43118
+ (0,external_node_child_process_.execSync)(`docker image inspect ${image} 2>/dev/null`, {
43119
+ stdio: "ignore",
43120
+ });
43121
+ console.log(source/* default */.Ay.dim(` Removing ${image}...`));
43122
+ (0,external_node_child_process_.execSync)(`docker rmi ${image}`, { stdio: "inherit" });
43123
+ removed++;
43124
+ }
43125
+ catch {
43126
+ // image not present
43127
+ }
43128
+ }
43129
+ if (removed === 0) {
43130
+ console.log(source/* default */.Ay.yellow("No sith Docker images found."));
43131
+ }
43132
+ else {
43133
+ console.log(source/* default */.Ay.green(`✓ Removed ${removed} image(s).`));
43134
+ }
43135
+ }
43136
+ async function nixCleanupCommand() {
43137
+ const nixDir = (0,external_node_path_.join)((0,external_node_os_.homedir)(), ".sith", "nix");
43138
+ console.log(source/* default */.Ay.cyan("Cleaning up sith Nix files..."));
43139
+ if ((0,external_node_fs_.existsSync)(nixDir)) {
43140
+ (0,external_node_fs_.rmSync)(nixDir, { recursive: true, force: true });
43141
+ console.log(source/* default */.Ay.green(`✓ Removed ${nixDir}`));
43142
+ }
43143
+ else {
43144
+ console.log(source/* default */.Ay.yellow(`${nixDir} not found — nothing to remove.`));
43145
+ }
43146
+ console.log(source/* default */.Ay.cyan("Running nix-collect-garbage..."));
43147
+ try {
43148
+ (0,external_node_child_process_.execSync)("nix-collect-garbage -d", { stdio: "inherit" });
43149
+ console.log(source/* default */.Ay.green("✓ Nix store garbage collected."));
43150
+ }
43151
+ catch {
43152
+ console.log(source/* default */.Ay.yellow("nix-collect-garbage failed — Nix may not be installed."));
43153
+ }
43154
+ }
43155
+ async function nixUninstallCommand() {
43156
+ console.log(source/* default */.Ay.yellow("This will fully remove Nix from your system:"));
43157
+ console.log(source/* default */.Ay.dim(" /nix/store, Nix daemon, shell profile entries"));
43158
+ console.log();
43159
+ const ok = await maintenance_confirm(source/* default */.Ay.red("Continue? [y/N] "));
43160
+ if (!ok) {
43161
+ console.log(source/* default */.Ay.dim("Aborted."));
43162
+ return;
43163
+ }
43164
+ const platform = process.platform;
43165
+ if (platform === "darwin") {
43166
+ console.log(source/* default */.Ay.cyan("Uninstalling Nix (macOS multi-user)..."));
43167
+ try {
43168
+ // Official macOS uninstall sequence
43169
+ (0,external_node_child_process_.execSync)("sudo launchctl unload /Library/LaunchDaemons/org.nixos.nix-daemon.plist 2>/dev/null || true", { stdio: "inherit" });
43170
+ (0,external_node_child_process_.execSync)("sudo rm -f /Library/LaunchDaemons/org.nixos.nix-daemon.plist", {
43171
+ stdio: "inherit",
43172
+ });
43173
+ (0,external_node_child_process_.execSync)("sudo diskutil apfs deleteVolume /nix 2>/dev/null || sudo rm -rf /nix", { stdio: "inherit" });
43174
+ (0,external_node_child_process_.execSync)("sudo rm -rf /etc/nix /etc/profile.d/nix.sh /etc/bashrc.d/nix.sh", { stdio: "inherit" });
43175
+ console.log(source/* default */.Ay.green("✓ Nix removed. Remove nix lines from ~/.zshrc / ~/.bashrc manually if present."));
43176
+ }
43177
+ catch (_e) {
43178
+ console.log(source/* default */.Ay.red("Uninstall failed. Run with sudo or check errors above."));
43179
+ }
43180
+ }
43181
+ else if (platform === "linux") {
43182
+ console.log(source/* default */.Ay.cyan("Uninstalling Nix (Linux)..."));
43183
+ try {
43184
+ (0,external_node_child_process_.execSync)("sudo systemctl stop nix-daemon 2>/dev/null || true", {
43185
+ stdio: "inherit",
43186
+ });
43187
+ (0,external_node_child_process_.execSync)("sudo systemctl disable nix-daemon 2>/dev/null || true", {
43188
+ stdio: "inherit",
43189
+ });
43190
+ (0,external_node_child_process_.execSync)("sudo rm -rf /nix /etc/nix", { stdio: "inherit" });
43191
+ console.log(source/* default */.Ay.green("✓ Nix removed. Remove nix lines from ~/.profile / ~/.bashrc manually if present."));
43192
+ }
43193
+ catch {
43194
+ console.log(source/* default */.Ay.red("Uninstall failed. Run with sudo or check errors above."));
43195
+ }
43196
+ }
43197
+ else {
43198
+ console.log(source/* default */.Ay.red(`Unsupported platform: ${platform}. Uninstall manually.`));
43199
+ }
43200
+ }
43201
+ async function uninstallCommand() {
43202
+ const sithDir = (0,external_node_path_.join)((0,external_node_os_.homedir)(), ".sith");
43203
+ console.log(source/* default */.Ay.yellow("This will delete:"));
43204
+ console.log(source/* default */.Ay.dim(` ${sithDir} (skills, config, nix files)`));
43205
+ console.log();
43206
+ const ok = await maintenance_confirm(source/* default */.Ay.red("Continue? [y/N] "));
43207
+ if (!ok) {
43208
+ console.log(source/* default */.Ay.dim("Aborted."));
43209
+ return;
43210
+ }
43211
+ if ((0,external_node_fs_.existsSync)(sithDir)) {
43212
+ (0,external_node_fs_.rmSync)(sithDir, { recursive: true, force: true });
43213
+ console.log(source/* default */.Ay.green(`✓ Removed ${sithDir}`));
43214
+ }
43215
+ else {
43216
+ console.log(source/* default */.Ay.yellow(`${sithDir} not found — nothing to remove.`));
43217
+ }
43218
+ console.log();
43219
+ console.log(source/* default */.Ay.dim(`Run ${source/* default */.Ay.bold("npm uninstall -g sith")} to remove the CLI.`));
43220
+ }
43221
+
43296
43222
 
43297
43223
  /***/ }),
43298
43224
 
@@ -43301,11 +43227,9 @@ __webpack_async_result__();
43301
43227
 
43302
43228
  /* harmony export */ __nccwpck_require__.d(__webpack_exports__, {
43303
43229
  /* harmony export */ Dv: () => (/* binding */ nixCommand),
43304
- /* harmony export */ Fh: () => (/* binding */ installNix),
43305
- /* harmony export */ Qi: () => (/* binding */ copyNixFiles),
43306
43230
  /* harmony export */ nb: () => (/* binding */ runNixShell)
43307
43231
  /* harmony export */ });
43308
- /* unused harmony exports parseNixVersionOutput, checkNixInstalled */
43232
+ /* unused harmony exports parseNixVersionOutput, checkNixInstalled, installNix, copyNixFiles */
43309
43233
  /* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_0__ = __nccwpck_require__(3024);
43310
43234
  /* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__nccwpck_require__.n(node_fs__WEBPACK_IMPORTED_MODULE_0__);
43311
43235
  /* harmony import */ var node_os__WEBPACK_IMPORTED_MODULE_1__ = __nccwpck_require__(8161);
@@ -44018,10 +43942,10 @@ __webpack_async_result__();
44018
43942
  /* harmony export */ __nccwpck_require__.d(__webpack_exports__, {
44019
43943
  /* harmony export */ XI: () => (/* binding */ SKILLS_CATALOG),
44020
43944
  /* harmony export */ Z3: () => (/* binding */ NIX_CONFIG),
44021
- /* harmony export */ ZC: () => (/* binding */ SPINNER_CONFIG),
44022
43945
  /* harmony export */ e6: () => (/* binding */ DOCKER_CONFIG),
44023
43946
  /* harmony export */ mF: () => (/* binding */ ASCII_LOGO)
44024
43947
  /* harmony export */ });
43948
+ /* unused harmony export SPINNER_CONFIG */
44025
43949
  // Predefined skill catalog — skills are installed to ~/.sith/skills/<name>/
44026
43950
  const SKILLS_CATALOG = [
44027
43951
  {
@@ -44119,16 +44043,18 @@ __nccwpck_require__.a(module, async (__webpack_handle_async_dependencies__, __we
44119
44043
  /* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__nccwpck_require__.n(node_path__WEBPACK_IMPORTED_MODULE_1__);
44120
44044
  /* harmony import */ var node_url__WEBPACK_IMPORTED_MODULE_2__ = __nccwpck_require__(3136);
44121
44045
  /* harmony import */ var node_url__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__nccwpck_require__.n(node_url__WEBPACK_IMPORTED_MODULE_2__);
44122
- /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_10__ = __nccwpck_require__(9611);
44046
+ /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_11__ = __nccwpck_require__(9611);
44123
44047
  /* harmony import */ var commander__WEBPACK_IMPORTED_MODULE_3__ = __nccwpck_require__(2202);
44124
- /* harmony import */ var update_notifier__WEBPACK_IMPORTED_MODULE_9__ = __nccwpck_require__(6213);
44125
- /* harmony import */ var _commands_docker_js__WEBPACK_IMPORTED_MODULE_4__ = __nccwpck_require__(5515);
44126
- /* harmony import */ var _commands_nix_js__WEBPACK_IMPORTED_MODULE_5__ = __nccwpck_require__(9922);
44127
- /* harmony import */ var _commands_skills_js__WEBPACK_IMPORTED_MODULE_6__ = __nccwpck_require__(9805);
44128
- /* harmony import */ var _components_TerminalUI_js__WEBPACK_IMPORTED_MODULE_7__ = __nccwpck_require__(3535);
44129
- /* harmony import */ var _utils_launcher_js__WEBPACK_IMPORTED_MODULE_8__ = __nccwpck_require__(5800);
44130
- var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([_commands_docker_js__WEBPACK_IMPORTED_MODULE_4__, _commands_skills_js__WEBPACK_IMPORTED_MODULE_6__, _components_TerminalUI_js__WEBPACK_IMPORTED_MODULE_7__]);
44131
- ([_commands_docker_js__WEBPACK_IMPORTED_MODULE_4__, _commands_skills_js__WEBPACK_IMPORTED_MODULE_6__, _components_TerminalUI_js__WEBPACK_IMPORTED_MODULE_7__] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__);
44048
+ /* harmony import */ var update_notifier__WEBPACK_IMPORTED_MODULE_10__ = __nccwpck_require__(6213);
44049
+ /* harmony import */ var _commands_docker_js__WEBPACK_IMPORTED_MODULE_4__ = __nccwpck_require__(3361);
44050
+ /* harmony import */ var _commands_maintenance_js__WEBPACK_IMPORTED_MODULE_5__ = __nccwpck_require__(6656);
44051
+ /* harmony import */ var _commands_nix_js__WEBPACK_IMPORTED_MODULE_6__ = __nccwpck_require__(9922);
44052
+ /* harmony import */ var _commands_skills_js__WEBPACK_IMPORTED_MODULE_7__ = __nccwpck_require__(9805);
44053
+ /* harmony import */ var _components_TerminalUI_js__WEBPACK_IMPORTED_MODULE_8__ = __nccwpck_require__(3535);
44054
+ /* harmony import */ var _utils_launcher_js__WEBPACK_IMPORTED_MODULE_9__ = __nccwpck_require__(5800);
44055
+ var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([_commands_skills_js__WEBPACK_IMPORTED_MODULE_7__, _components_TerminalUI_js__WEBPACK_IMPORTED_MODULE_8__]);
44056
+ ([_commands_skills_js__WEBPACK_IMPORTED_MODULE_7__, _components_TerminalUI_js__WEBPACK_IMPORTED_MODULE_8__] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__);
44057
+
44132
44058
 
44133
44059
 
44134
44060
 
@@ -44148,12 +44074,12 @@ const PROGRAM_NAME = "sith";
44148
44074
  const PROGRAM_VERSION = pkg.version;
44149
44075
  const PROGRAM_DESCRIPTION = "Turn your context to the dark side. Standardize and share your OpenCode setup with a fully dockerized environment, designed for seamless collaboration and CI integration.";
44150
44076
  // Check for updates (automatic background check)
44151
- const notifier = (0,update_notifier__WEBPACK_IMPORTED_MODULE_9__/* ["default"] */ .A)({ pkg });
44077
+ const notifier = (0,update_notifier__WEBPACK_IMPORTED_MODULE_10__/* ["default"] */ .A)({ pkg });
44152
44078
  notifier.notify();
44153
44079
  async function checkForUpdates() {
44154
- console.log(chalk__WEBPACK_IMPORTED_MODULE_10__/* ["default"] */ .Ay.cyan("Checking for updates..."));
44080
+ console.log(chalk__WEBPACK_IMPORTED_MODULE_11__/* ["default"] */ .Ay.cyan("Checking for updates..."));
44155
44081
  // Force update check by setting updateCheckInterval to 0
44156
- const notifier = (0,update_notifier__WEBPACK_IMPORTED_MODULE_9__/* ["default"] */ .A)({
44082
+ const notifier = (0,update_notifier__WEBPACK_IMPORTED_MODULE_10__/* ["default"] */ .A)({
44157
44083
  pkg,
44158
44084
  updateCheckInterval: 0,
44159
44085
  });
@@ -44162,12 +44088,12 @@ async function checkForUpdates() {
44162
44088
  const update = notifier.update;
44163
44089
  if (update && update.latest !== pkg.version) {
44164
44090
  console.log();
44165
- console.log(chalk__WEBPACK_IMPORTED_MODULE_10__/* ["default"] */ .Ay.green(`Update available: ${chalk__WEBPACK_IMPORTED_MODULE_10__/* ["default"] */ .Ay.dim(pkg.version)} → ${chalk__WEBPACK_IMPORTED_MODULE_10__/* ["default"] */ .Ay.bold(update.latest)}`));
44166
- console.log(chalk__WEBPACK_IMPORTED_MODULE_10__/* ["default"] */ .Ay.cyan(`Run ${chalk__WEBPACK_IMPORTED_MODULE_10__/* ["default"] */ .Ay.bold(`npm install -g ${pkg.name}`)} to update`));
44091
+ console.log(chalk__WEBPACK_IMPORTED_MODULE_11__/* ["default"] */ .Ay.green(`Update available: ${chalk__WEBPACK_IMPORTED_MODULE_11__/* ["default"] */ .Ay.dim(pkg.version)} → ${chalk__WEBPACK_IMPORTED_MODULE_11__/* ["default"] */ .Ay.bold(update.latest)}`));
44092
+ console.log(chalk__WEBPACK_IMPORTED_MODULE_11__/* ["default"] */ .Ay.cyan(`Run ${chalk__WEBPACK_IMPORTED_MODULE_11__/* ["default"] */ .Ay.bold(`npm install -g ${pkg.name}`)} to update`));
44167
44093
  console.log();
44168
44094
  }
44169
44095
  else {
44170
- console.log(chalk__WEBPACK_IMPORTED_MODULE_10__/* ["default"] */ .Ay.green(`✓ You're on the latest version (${pkg.version})`));
44096
+ console.log(chalk__WEBPACK_IMPORTED_MODULE_11__/* ["default"] */ .Ay.green(`✓ You're on the latest version (${pkg.version})`));
44171
44097
  }
44172
44098
  }
44173
44099
  function createProgram() {
@@ -44182,52 +44108,57 @@ function createProgram() {
44182
44108
  .option("--nix", "Use native Nix shell (no Docker)")
44183
44109
  .option("--nix-install", "Install Nix package manager locally")
44184
44110
  .option("--update", "Check for updates")
44185
- .option("--legacy", "Use legacy menu interface");
44186
- // Default action - show terminal UI or legacy menu
44111
+ .option("--docker-cleanup", "Remove sith Docker images from local machine")
44112
+ .option("--nix-cleanup", "Remove ~/.sith/nix and run nix-collect-garbage")
44113
+ .option("--nix-uninstall", "Fully remove Nix from the system (daemon, /nix/store)")
44114
+ .option("--uninstall", "Remove ~/.sith config directory");
44115
+ // Default action - show terminal UI
44187
44116
  program.action(async (options) => {
44188
- if (options.update) {
44117
+ if (options.dockerCleanup) {
44118
+ await (0,_commands_maintenance_js__WEBPACK_IMPORTED_MODULE_5__/* .dockerCleanupCommand */ .Yb)();
44119
+ }
44120
+ else if (options.nixCleanup) {
44121
+ await (0,_commands_maintenance_js__WEBPACK_IMPORTED_MODULE_5__/* .nixCleanupCommand */ .V)();
44122
+ }
44123
+ else if (options.nixUninstall) {
44124
+ await (0,_commands_maintenance_js__WEBPACK_IMPORTED_MODULE_5__/* .nixUninstallCommand */ .be)();
44125
+ }
44126
+ else if (options.uninstall) {
44127
+ await (0,_commands_maintenance_js__WEBPACK_IMPORTED_MODULE_5__/* .uninstallCommand */ .Wd)();
44128
+ }
44129
+ else if (options.update) {
44189
44130
  await checkForUpdates();
44190
44131
  }
44191
44132
  else if (options.nix) {
44192
- await (0,_commands_nix_js__WEBPACK_IMPORTED_MODULE_5__/* .runNixShell */ .nb)();
44133
+ await (0,_commands_nix_js__WEBPACK_IMPORTED_MODULE_6__/* .runNixShell */ .nb)();
44193
44134
  }
44194
44135
  else if (options.nixInstall) {
44195
- await (0,_commands_nix_js__WEBPACK_IMPORTED_MODULE_5__/* .nixCommand */ .Dv)({ install: true });
44136
+ await (0,_commands_nix_js__WEBPACK_IMPORTED_MODULE_6__/* .nixCommand */ .Dv)({ install: true });
44196
44137
  }
44197
44138
  else if (options.it) {
44198
- await (0,_utils_launcher_js__WEBPACK_IMPORTED_MODULE_8__/* .launchShell */ .k1)();
44139
+ await (0,_utils_launcher_js__WEBPACK_IMPORTED_MODULE_9__/* .launchShell */ .k1)();
44199
44140
  }
44200
- else if (options.legacy || options.pull || options.build) {
44201
- // Use legacy menu for explicit pull/build or --legacy flag
44141
+ else if (options.pull || options.build) {
44202
44142
  await (0,_commands_docker_js__WEBPACK_IMPORTED_MODULE_4__/* .dockerCommand */ .Q)(options);
44203
44143
  }
44204
44144
  else {
44205
44145
  // Default: show new terminal UI
44206
- (0,_components_TerminalUI_js__WEBPACK_IMPORTED_MODULE_7__/* .renderTerminalUI */ .t)();
44146
+ (0,_components_TerminalUI_js__WEBPACK_IMPORTED_MODULE_8__/* .renderTerminalUI */ .t)();
44207
44147
  }
44208
44148
  });
44209
- // Docker command - explicit Docker management
44210
- program
44211
- .command("docker")
44212
- .description("Manage Docker environment")
44213
- .option("--pull", "Pull prebuilt Docker image (recommended)")
44214
- .option("--build", "Build the Docker image from scratch")
44215
- .action(async (options) => {
44216
- await (0,_commands_docker_js__WEBPACK_IMPORTED_MODULE_4__/* .dockerCommand */ .Q)(options);
44217
- });
44218
44149
  // Shell command - direct interactive shell (bypasses menu)
44219
44150
  program
44220
44151
  .command("shell")
44221
44152
  .description("Run interactive shell in Docker container")
44222
44153
  .action(async () => {
44223
- await (0,_utils_launcher_js__WEBPACK_IMPORTED_MODULE_8__/* .launchShell */ .k1)();
44154
+ await (0,_utils_launcher_js__WEBPACK_IMPORTED_MODULE_9__/* .launchShell */ .k1)();
44224
44155
  });
44225
44156
  // Skills command - install/uninstall skills from catalog
44226
44157
  program
44227
44158
  .command("skills")
44228
44159
  .description("Manage skills (~/.sith/skills/)")
44229
44160
  .action(() => {
44230
- (0,_commands_skills_js__WEBPACK_IMPORTED_MODULE_6__/* .skillsCommand */ .a)();
44161
+ (0,_commands_skills_js__WEBPACK_IMPORTED_MODULE_7__/* .skillsCommand */ .a)();
44231
44162
  });
44232
44163
  // Nix command - native Nix environment
44233
44164
  program
@@ -44236,7 +44167,7 @@ function createProgram() {
44236
44167
  .option("--install", "Install Nix package manager")
44237
44168
  .option("--shell", "Run Nix shell")
44238
44169
  .action(async (options) => {
44239
- await (0,_commands_nix_js__WEBPACK_IMPORTED_MODULE_5__/* .nixCommand */ .Dv)(options);
44170
+ await (0,_commands_nix_js__WEBPACK_IMPORTED_MODULE_6__/* .nixCommand */ .Dv)(options);
44240
44171
  });
44241
44172
  // OpenCode command - launch OpenCode in Docker
44242
44173
  program
@@ -44244,7 +44175,7 @@ function createProgram() {
44244
44175
  .description("Launch OpenCode in Docker")
44245
44176
  .option("-p, --prompt <prompt>", "Prompt to pass to OpenCode")
44246
44177
  .action(async (options) => {
44247
- await (0,_utils_launcher_js__WEBPACK_IMPORTED_MODULE_8__/* .launchOpencode */ .Tg)(options.prompt);
44178
+ await (0,_utils_launcher_js__WEBPACK_IMPORTED_MODULE_9__/* .launchOpencode */ .Tg)(options.prompt);
44248
44179
  });
44249
44180
  // Claude command - launch Claude Code in Docker
44250
44181
  program
@@ -44252,7 +44183,7 @@ function createProgram() {
44252
44183
  .description("Launch Claude Code in Docker")
44253
44184
  .option("-p, --prompt <prompt>", "Prompt to pass to Claude Code")
44254
44185
  .action(async (options) => {
44255
- await (0,_utils_launcher_js__WEBPACK_IMPORTED_MODULE_8__/* .launchClaude */ .Q7)(options.prompt);
44186
+ await (0,_utils_launcher_js__WEBPACK_IMPORTED_MODULE_9__/* .launchClaude */ .Q7)(options.prompt);
44256
44187
  });
44257
44188
  return program;
44258
44189
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m14i/sith",
3
- "version": "1.22.0",
3
+ "version": "1.23.0",
4
4
  "description": "Turn your context to the dark side. Standardize and share your OpenCode setup with a fully dockerized environment, designed for seamless collaboration and CI integration.",
5
5
  "type": "module",
6
6
  "repository": {