@m14i/sith 1.11.0 → 1.13.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
@@ -25,14 +25,16 @@ npx @m14i/sith@latest
25
25
  ### Quick Start
26
26
 
27
27
  ```bash
28
- # Interactive menu (recommended)
28
+ # Interactive terminal UI (default)
29
29
  sith
30
- # Options: Enter Shell | Configuration (Pull/Build)
30
+ # Type your prompt to start OpenCode with that task
31
+ # Or use slash commands: /shell, /config, /help
31
32
 
32
- # Direct commands (skip menu)
33
- sith --it # Launch shell immediately
33
+ # Direct commands
34
+ sith --it # Launch Docker shell immediately
34
35
  sith --pull # Pull prebuilt image
35
36
  sith --build # Build from scratch
37
+ sith --legacy # Use legacy menu interface
36
38
  ```
37
39
 
38
40
  ### Distribution Options
@@ -46,12 +48,29 @@ sith --build # Build from scratch
46
48
 
47
49
  | Command | Description |
48
50
  |---------|-------------|
49
- | `sith` | Interactive menu with options |
50
- | `sith --it` | Launch interactive shell in container |
51
+ | `sith` | Interactive terminal UI (Claude Code style) |
52
+ | `sith --it` | Launch Docker shell immediately |
51
53
  | `sith --pull` | Pull prebuilt image from GHCR |
52
54
  | `sith --build` | Build Docker image from scratch |
55
+ | `sith --legacy` | Use legacy menu interface |
53
56
  | `sith --help` | Show all available commands |
54
57
 
58
+ ### Terminal UI Usage
59
+
60
+ When you run `sith`, you get an interactive terminal interface:
61
+
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
65
+
66
+ **Slash commands:**
67
+ - `/shell` → Start Docker shell only (no OpenCode)
68
+ - `/config` → Open configuration menu (pull/build options)
69
+ - `/help` → Show available commands
70
+
71
+ **Navigation:**
72
+ - `Ctrl+C` or `Esc` → Exit terminal UI
73
+
55
74
  ### Prebuilt Image Details
56
75
 
57
76
  **Pull and verify:**
@@ -78,23 +97,24 @@ cosign verify \
78
97
 
79
98
  ## Authentication
80
99
 
81
- Sith uses **GitHub Copilot models by default**. Authentication requires a GitHub token.
100
+ Sith uses **Claude Sonnet 4.6 via GitHub Copilot** by default. Authentication requires a GitHub token with Copilot access.
82
101
 
83
102
  **Automatic (recommended):**
84
103
  If you have GitHub CLI (`gh`) installed and authenticated, Sith automatically fetches your token:
85
104
  ```bash
86
- sith --it # Auto-detects token via gh auth token
105
+ sith # Auto-detects token via gh auth token
87
106
  ```
88
107
 
89
108
  **Manual token:**
90
109
  If you don't have `gh` CLI or prefer manual setup:
91
110
 
92
- 1. Create a token at https://github.com/settings/tokens
93
- 2. Required scopes: `copilot`, `repo`, `read:org`
94
- 3. Export it:
111
+ 1. Ensure you have GitHub Copilot access
112
+ 2. Create a token at https://github.com/settings/tokens
113
+ 3. Required scopes: `copilot`, `repo`, `read:org`
114
+ 4. Export it:
95
115
  ```bash
96
116
  export GITHUB_TOKEN=gho_your_token_here
97
- sith --it
117
+ sith
98
118
  ```
99
119
 
100
120
  **Make it persistent (add to ~/.zshrc or ~/.bashrc):**
@@ -102,13 +122,21 @@ sith --it
102
122
  export GITHUB_TOKEN=$(gh auth token)
103
123
  ```
104
124
 
125
+ **Inside container:**
126
+ Once OpenCode starts, authenticate with GitHub Copilot:
127
+ ```bash
128
+ opencode providers login
129
+ # Follow prompts to authenticate with GitHub
130
+ ```
131
+
105
132
  ## Features
106
133
 
134
+ - **Claude Code-style UI**: Interactive terminal interface with prompt input and slash commands
135
+ - **OpenCode Integration**: Start coding with a simple text prompt
136
+ - **Model Selection**: Uses Claude Sonnet 4.6 via GitHub Copilot by default
107
137
  - **Prebuilt Images**: Pull verified images from GitHub Container Registry
108
138
  - **Image Signing**: All images signed with cosign for supply chain security
109
139
  - **SBOM Attestation**: Software Bill of Materials included with every image
110
- - **Interactive Menu**: Navigate with arrow keys, select with Enter
111
- - **Direct Commands**: Build or shell access without menu
112
140
  - **Dockerized Environment**: Consistent setup across machines
113
141
  - **Nix Integration**: Full development environment with all tools
114
142
  - **CI-Ready**: Standardize builds across local and CI pipelines
@@ -0,0 +1,8 @@
1
+ import React from "react";
2
+ interface ConfigModalProps {
3
+ onClose: () => void;
4
+ onMessage: (message: string, type?: "success" | "error" | "info") => void;
5
+ }
6
+ export declare function ConfigModal({ onClose, onMessage }: ConfigModalProps): React.ReactElement;
7
+ export {};
8
+ //# sourceMappingURL=ConfigModal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfigModal.d.ts","sourceRoot":"","sources":["file:///home/runner/work/sith/sith/src/components/ConfigModal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAuCxC,UAAU,gBAAgB;IACxB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,KAAK,IAAI,CAAC;CAC3E;AAED,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,gBAAgB,GAAG,KAAK,CAAC,YAAY,CAkHxF"}
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ export declare function TerminalUI(): React.ReactElement;
3
+ export declare function renderTerminalUI(): void;
4
+ //# sourceMappingURL=TerminalUI.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TerminalUI.d.ts","sourceRoot":"","sources":["file:///home/runner/work/sith/sith/src/components/TerminalUI.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAC;AA0JrD,wBAAgB,UAAU,IAAI,KAAK,CAAC,YAAY,CAkL/C;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC"}
package/dist/index.js CHANGED
@@ -43306,6 +43306,414 @@ __webpack_async_result__();
43306
43306
 
43307
43307
  /***/ }),
43308
43308
 
43309
+ /***/ 3636:
43310
+ /***/ ((module, __webpack_exports__, __nccwpck_require__) => {
43311
+
43312
+ __nccwpck_require__.a(module, async (__webpack_handle_async_dependencies__, __webpack_async_result__) => { try {
43313
+ /* harmony export */ __nccwpck_require__.d(__webpack_exports__, {
43314
+ /* harmony export */ y: () => (/* binding */ ConfigModal)
43315
+ /* harmony export */ });
43316
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __nccwpck_require__(2864);
43317
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__nccwpck_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
43318
+ /* harmony import */ var ink__WEBPACK_IMPORTED_MODULE_1__ = __nccwpck_require__(3816);
43319
+ /* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_6__ = __nccwpck_require__(6181);
43320
+ /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_2__ = __nccwpck_require__(9896);
43321
+ /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__nccwpck_require__.n(fs__WEBPACK_IMPORTED_MODULE_2__);
43322
+ /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __nccwpck_require__(6928);
43323
+ /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__nccwpck_require__.n(path__WEBPACK_IMPORTED_MODULE_3__);
43324
+ /* harmony import */ var url__WEBPACK_IMPORTED_MODULE_4__ = __nccwpck_require__(7016);
43325
+ /* harmony import */ var url__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__nccwpck_require__.n(url__WEBPACK_IMPORTED_MODULE_4__);
43326
+ /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_5__ = __nccwpck_require__(6878);
43327
+ var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([ink__WEBPACK_IMPORTED_MODULE_1__]);
43328
+ ink__WEBPACK_IMPORTED_MODULE_1__ = (__webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__)[0];
43329
+
43330
+
43331
+
43332
+
43333
+
43334
+
43335
+
43336
+ const __dirname = path__WEBPACK_IMPORTED_MODULE_3___default().dirname((0,url__WEBPACK_IMPORTED_MODULE_4__.fileURLToPath)(import.meta.url));
43337
+ function findProjectRoot(startDir) {
43338
+ let currentDir = startDir;
43339
+ const rootPath = path__WEBPACK_IMPORTED_MODULE_3___default().parse(currentDir).root;
43340
+ while (currentDir !== rootPath) {
43341
+ const dockerPath = path__WEBPACK_IMPORTED_MODULE_3___default().join(currentDir, _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.folderName);
43342
+ if (fs__WEBPACK_IMPORTED_MODULE_2___default().existsSync(dockerPath) && fs__WEBPACK_IMPORTED_MODULE_2___default().statSync(dockerPath).isDirectory()) {
43343
+ return currentDir;
43344
+ }
43345
+ currentDir = path__WEBPACK_IMPORTED_MODULE_3___default().dirname(currentDir);
43346
+ }
43347
+ throw new Error(`Could not find project root (${_config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.folderName}/ folder not found)`);
43348
+ }
43349
+ const rootDir = findProjectRoot(__dirname);
43350
+ const configOptions = [
43351
+ { label: "Pull prebuilt image (recommended)", value: "pull", icon: "📦" },
43352
+ { label: "Build Docker image from scratch", value: "build", icon: "🔨" },
43353
+ { label: "Back", value: "back", icon: "◀️" },
43354
+ ];
43355
+ function ConfigModal({ onClose, onMessage }) {
43356
+ const [selectedIndex, setSelectedIndex] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(0);
43357
+ const [isProcessing, setIsProcessing] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
43358
+ const [processStep, setProcessStep] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)("");
43359
+ (0,ink__WEBPACK_IMPORTED_MODULE_1__/* .useInput */ .Ge)((_input, key) => {
43360
+ if (isProcessing) {
43361
+ return;
43362
+ }
43363
+ if (key.upArrow) {
43364
+ setSelectedIndex((prev) => (prev > 0 ? prev - 1 : configOptions.length - 1));
43365
+ }
43366
+ else if (key.downArrow) {
43367
+ setSelectedIndex((prev) => (prev < configOptions.length - 1 ? prev + 1 : 0));
43368
+ }
43369
+ else if (key.return) {
43370
+ handleSelection(configOptions[selectedIndex].value);
43371
+ }
43372
+ else if (key.escape) {
43373
+ onClose();
43374
+ }
43375
+ });
43376
+ async function handleSelection(value) {
43377
+ switch (value) {
43378
+ case "back":
43379
+ onClose();
43380
+ break;
43381
+ case "pull":
43382
+ await handlePull();
43383
+ break;
43384
+ case "build":
43385
+ await handleBuild();
43386
+ break;
43387
+ }
43388
+ }
43389
+ async function handlePull() {
43390
+ setIsProcessing(true);
43391
+ setProcessStep("Pulling prebuilt Docker image...");
43392
+ try {
43393
+ await (0,execa__WEBPACK_IMPORTED_MODULE_6__/* .execa */ .Ho)("docker", ["pull", _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.prebuiltImage], { stdio: "inherit" });
43394
+ await (0,execa__WEBPACK_IMPORTED_MODULE_6__/* .execa */ .Ho)("docker", ["tag", _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.prebuiltImage, _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.imageName], {
43395
+ stdio: "inherit",
43396
+ });
43397
+ onMessage(`✅ Docker image ready: ${_config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.imageName}`, "success");
43398
+ onClose();
43399
+ }
43400
+ catch (error) {
43401
+ const message = error instanceof Error ? error.message : "Pull failed";
43402
+ onMessage(`❌ ${message}`, "error");
43403
+ setIsProcessing(false);
43404
+ }
43405
+ }
43406
+ async function handleBuild() {
43407
+ setIsProcessing(true);
43408
+ setProcessStep("Building Docker image from scratch...");
43409
+ try {
43410
+ const dockerfilePath = path__WEBPACK_IMPORTED_MODULE_3___default().join(rootDir, _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.folderName, _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.dockerfileName);
43411
+ if (!fs__WEBPACK_IMPORTED_MODULE_2___default().existsSync(dockerfilePath)) {
43412
+ throw new Error(`Dockerfile not found at: ${dockerfilePath}`);
43413
+ }
43414
+ await (0,execa__WEBPACK_IMPORTED_MODULE_6__/* .execa */ .Ho)("docker", ["build", "-f", dockerfilePath, "-t", _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.imageName, rootDir], {
43415
+ stdio: "inherit",
43416
+ });
43417
+ onMessage(`✅ Docker image built: ${_config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.imageName}`, "success");
43418
+ onClose();
43419
+ }
43420
+ catch (error) {
43421
+ const message = error instanceof Error ? error.message : "Build failed";
43422
+ onMessage(`❌ ${message}`, "error");
43423
+ setIsProcessing(false);
43424
+ }
43425
+ }
43426
+ if (isProcessing) {
43427
+ return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 1 },
43428
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { color: "cyan", bold: true }, "\u2699\uFE0F Configuration"),
43429
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { marginTop: 1 },
43430
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { color: "yellow" }, processStep))));
43431
+ }
43432
+ return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 1 },
43433
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { color: "cyan", bold: true }, "\u2699\uFE0F Configuration"),
43434
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { flexDirection: "column", marginTop: 1 }, configOptions.map((option, index) => {
43435
+ const isSelected = index === selectedIndex;
43436
+ return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { key: option.value, marginY: 0 },
43437
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { color: isSelected ? "cyan" : undefined },
43438
+ isSelected ? "❯ " : " ",
43439
+ option.icon,
43440
+ " ",
43441
+ option.label)));
43442
+ })),
43443
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { marginTop: 1 },
43444
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { dimColor: true }, "Use arrow keys to navigate, Enter to select, Esc to close"))));
43445
+ }
43446
+
43447
+ __webpack_async_result__();
43448
+ } catch(e) { __webpack_async_result__(e); } });
43449
+
43450
+ /***/ }),
43451
+
43452
+ /***/ 3535:
43453
+ /***/ ((module, __webpack_exports__, __nccwpck_require__) => {
43454
+
43455
+ __nccwpck_require__.a(module, async (__webpack_handle_async_dependencies__, __webpack_async_result__) => { try {
43456
+ /* harmony export */ __nccwpck_require__.d(__webpack_exports__, {
43457
+ /* harmony export */ t: () => (/* binding */ renderTerminalUI)
43458
+ /* harmony export */ });
43459
+ /* unused harmony export TerminalUI */
43460
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __nccwpck_require__(2864);
43461
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__nccwpck_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
43462
+ /* harmony import */ var ink__WEBPACK_IMPORTED_MODULE_1__ = __nccwpck_require__(3816);
43463
+ /* harmony import */ var ink_text_input__WEBPACK_IMPORTED_MODULE_2__ = __nccwpck_require__(9046);
43464
+ /* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_5__ = __nccwpck_require__(6181);
43465
+ /* harmony import */ var _ConfigModal_js__WEBPACK_IMPORTED_MODULE_3__ = __nccwpck_require__(3636);
43466
+ /* harmony import */ var _utils_slashCommands_js__WEBPACK_IMPORTED_MODULE_6__ = __nccwpck_require__(9987);
43467
+ /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_4__ = __nccwpck_require__(6878);
43468
+ var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([ink__WEBPACK_IMPORTED_MODULE_1__, ink_text_input__WEBPACK_IMPORTED_MODULE_2__, _ConfigModal_js__WEBPACK_IMPORTED_MODULE_3__]);
43469
+ ([ink__WEBPACK_IMPORTED_MODULE_1__, ink_text_input__WEBPACK_IMPORTED_MODULE_2__, _ConfigModal_js__WEBPACK_IMPORTED_MODULE_3__] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__);
43470
+
43471
+
43472
+
43473
+
43474
+
43475
+
43476
+
43477
+ function WelcomeScreen() {
43478
+ return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { flexDirection: "column", justifyContent: "center", alignItems: "center", paddingY: 2 },
43479
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { flexDirection: "column", marginBottom: 2 }, _config_js__WEBPACK_IMPORTED_MODULE_4__/* .ASCII_LOGO */ .mF.map((line, index) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { key: index, color: "red", bold: true }, line)))),
43480
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { flexDirection: "column", alignItems: "center", marginTop: 1 },
43481
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { dimColor: true }, "Turn your context to the dark side"),
43482
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { dimColor: true }, "Dockerized OpenCode environment")),
43483
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { marginTop: 2, flexDirection: "column", alignItems: "center" },
43484
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { color: "cyan" }, "Type your prompt to start coding"),
43485
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { dimColor: true }, "or use slash commands:")),
43486
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { flexDirection: "column", marginTop: 1, marginLeft: 2 },
43487
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { dimColor: true }, " /shell - Start Docker shell"),
43488
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { dimColor: true }, " /config - Configuration"),
43489
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { dimColor: true }, " /help - Show help"))));
43490
+ }
43491
+ function getMessageColor(messageType) {
43492
+ switch (messageType) {
43493
+ case "success":
43494
+ return "green";
43495
+ case "error":
43496
+ return "red";
43497
+ case "info":
43498
+ return "cyan";
43499
+ case "user":
43500
+ return "white";
43501
+ case "system":
43502
+ return "gray";
43503
+ default:
43504
+ return undefined;
43505
+ }
43506
+ }
43507
+ function getMessagePrefix(messageType) {
43508
+ switch (messageType) {
43509
+ case "user":
43510
+ return "› ";
43511
+ case "system":
43512
+ return "⚡ ";
43513
+ default:
43514
+ return "";
43515
+ }
43516
+ }
43517
+ function MessageItem({ message }) {
43518
+ const color = getMessageColor(message.type);
43519
+ const prefix = getMessagePrefix(message.type);
43520
+ return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { marginBottom: 0 },
43521
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { color: color },
43522
+ prefix,
43523
+ message.text)));
43524
+ }
43525
+ async function getGitHubToken() {
43526
+ // Check environment variable first
43527
+ const envToken = process.env.GITHUB_TOKEN;
43528
+ if (envToken) {
43529
+ return envToken;
43530
+ }
43531
+ // Try to get token from gh CLI
43532
+ try {
43533
+ const { stdout } = await (0,execa__WEBPACK_IMPORTED_MODULE_5__/* .execa */ .Ho)("gh", ["auth", "token"]);
43534
+ return stdout.trim();
43535
+ }
43536
+ catch {
43537
+ // Return empty string if gh CLI is not available
43538
+ return "";
43539
+ }
43540
+ }
43541
+ function buildDockerShellCommand(githubToken) {
43542
+ return [
43543
+ "run",
43544
+ "--rm",
43545
+ "-it",
43546
+ "-v",
43547
+ `${process.cwd()}:${_config_js__WEBPACK_IMPORTED_MODULE_4__/* .DOCKER_CONFIG */ .e6.workspaceMount}`,
43548
+ "-e",
43549
+ `GITHUB_TOKEN=${githubToken}`,
43550
+ "--entrypoint",
43551
+ "nix-shell",
43552
+ _config_js__WEBPACK_IMPORTED_MODULE_4__/* .DOCKER_CONFIG */ .e6.imageName,
43553
+ _config_js__WEBPACK_IMPORTED_MODULE_4__/* .DOCKER_CONFIG */ .e6.shellEntrypoint,
43554
+ ];
43555
+ }
43556
+ function buildDockerOpencodeCommand(githubToken, prompt) {
43557
+ const dockerArgs = [
43558
+ "run",
43559
+ "--rm",
43560
+ "-it",
43561
+ "-v",
43562
+ `${process.cwd()}:${_config_js__WEBPACK_IMPORTED_MODULE_4__/* .DOCKER_CONFIG */ .e6.workspaceMount}`,
43563
+ "-e",
43564
+ `GITHUB_TOKEN=${githubToken}`,
43565
+ "--entrypoint",
43566
+ "bash",
43567
+ _config_js__WEBPACK_IMPORTED_MODULE_4__/* .DOCKER_CONFIG */ .e6.imageName,
43568
+ "-c",
43569
+ ];
43570
+ // Build opencode command - always interactive, use Sonnet 4.6
43571
+ let opencodeCommand = "source /opt/sith/nix/nix-scripts/setup.sh && cd /workspace && opencode -m github-copilot/claude-sonnet-4.6";
43572
+ if (prompt) {
43573
+ // Escape single quotes in prompt and use --prompt flag for interactive mode
43574
+ const escapedPrompt = prompt.replace(/'/g, "'\\''");
43575
+ opencodeCommand += ` --prompt '${escapedPrompt}'`;
43576
+ }
43577
+ dockerArgs.push(opencodeCommand);
43578
+ return dockerArgs;
43579
+ }
43580
+ function TerminalUI() {
43581
+ const { exit } = (0,ink__WEBPACK_IMPORTED_MODULE_1__/* .useApp */ .nm)();
43582
+ const [input, setInput] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)("");
43583
+ const [messages, setMessages] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)([]);
43584
+ const [showConfigModal, setShowConfigModal] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
43585
+ const [nextMessageId, setNextMessageId] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(1);
43586
+ const addMessage = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)((text, type = "system") => {
43587
+ const newMessage = {
43588
+ id: nextMessageId,
43589
+ text,
43590
+ type,
43591
+ timestamp: new Date(),
43592
+ };
43593
+ setMessages((previousMessages) => [...previousMessages, newMessage]);
43594
+ setNextMessageId((previousId) => previousId + 1);
43595
+ }, [nextMessageId]);
43596
+ const handleDockerShell = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(async () => {
43597
+ exit();
43598
+ console.log("🚀 Starting Docker shell...");
43599
+ console.log(`Mounting current directory to ${_config_js__WEBPACK_IMPORTED_MODULE_4__/* .DOCKER_CONFIG */ .e6.workspaceMount}`);
43600
+ console.log('Press Ctrl+D or type "exit" to leave');
43601
+ console.log();
43602
+ const githubToken = await getGitHubToken();
43603
+ const dockerArgs = buildDockerShellCommand(githubToken);
43604
+ try {
43605
+ await (0,execa__WEBPACK_IMPORTED_MODULE_5__/* .execa */ .Ho)("docker", dockerArgs, { stdio: "inherit" });
43606
+ console.log();
43607
+ console.log("✅ Exited shell");
43608
+ }
43609
+ catch (error) {
43610
+ const errorMessage = error instanceof Error ? error.message : "Failed to start shell";
43611
+ console.error(`❌ ${errorMessage}`);
43612
+ process.exit(1);
43613
+ }
43614
+ }, [exit]);
43615
+ const handleOpenCode = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(async (prompt) => {
43616
+ exit();
43617
+ console.log("🚀 Starting OpenCode...");
43618
+ console.log(`Mounting current directory to ${_config_js__WEBPACK_IMPORTED_MODULE_4__/* .DOCKER_CONFIG */ .e6.workspaceMount}`);
43619
+ if (prompt) {
43620
+ console.log(`Prompt: ${prompt}`);
43621
+ }
43622
+ console.log();
43623
+ const githubToken = await getGitHubToken();
43624
+ const dockerArgs = buildDockerOpencodeCommand(githubToken, prompt);
43625
+ try {
43626
+ await (0,execa__WEBPACK_IMPORTED_MODULE_5__/* .execa */ .Ho)("docker", dockerArgs, { stdio: "inherit" });
43627
+ console.log();
43628
+ console.log("✅ Exited OpenCode");
43629
+ }
43630
+ catch (error) {
43631
+ const errorMessage = error instanceof Error ? error.message : "Failed to start OpenCode";
43632
+ console.error(`❌ ${errorMessage}`);
43633
+ process.exit(1);
43634
+ }
43635
+ }, [exit]);
43636
+ const handleSlashCommand = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(async (command, userInput) => {
43637
+ if (!command) {
43638
+ return;
43639
+ }
43640
+ addMessage(userInput, "user");
43641
+ switch (command.type) {
43642
+ case "shell":
43643
+ await handleDockerShell();
43644
+ break;
43645
+ case "config":
43646
+ setShowConfigModal(true);
43647
+ break;
43648
+ case "help":
43649
+ addMessage("Available commands:", "info");
43650
+ const availableCommands = (0,_utils_slashCommands_js__WEBPACK_IMPORTED_MODULE_6__/* .getAvailableCommands */ .K)();
43651
+ for (const cmd of availableCommands) {
43652
+ addMessage(` ${cmd.command} - ${cmd.description}`, "info");
43653
+ }
43654
+ break;
43655
+ }
43656
+ }, [addMessage, handleDockerShell]);
43657
+ const handleSubmit = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(async (value) => {
43658
+ const trimmedValue = value.trim();
43659
+ if (!trimmedValue) {
43660
+ return;
43661
+ }
43662
+ setInput("");
43663
+ const command = (0,_utils_slashCommands_js__WEBPACK_IMPORTED_MODULE_6__/* .parseSlashCommand */ .M)(trimmedValue);
43664
+ if (command) {
43665
+ await handleSlashCommand(command, trimmedValue);
43666
+ }
43667
+ else if (trimmedValue.startsWith("/")) {
43668
+ addMessage(trimmedValue, "user");
43669
+ addMessage(`Unknown command: ${trimmedValue}. Type /help for available commands.`, "error");
43670
+ }
43671
+ else {
43672
+ // Regular text input - start OpenCode with this prompt
43673
+ await handleOpenCode(trimmedValue);
43674
+ }
43675
+ }, [addMessage, handleOpenCode, handleSlashCommand]);
43676
+ const handleConfigModalClose = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(() => {
43677
+ setShowConfigModal(false);
43678
+ }, []);
43679
+ const handleConfigModalMessage = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)((text, type) => {
43680
+ addMessage(text, type || "system");
43681
+ }, [addMessage]);
43682
+ (0,ink__WEBPACK_IMPORTED_MODULE_1__/* .useInput */ .Ge)((input, key) => {
43683
+ if (showConfigModal) {
43684
+ // Let modal handle input
43685
+ return;
43686
+ }
43687
+ const shouldExit = key.escape || (key.ctrl && input === "c");
43688
+ if (shouldExit) {
43689
+ exit();
43690
+ }
43691
+ });
43692
+ if (showConfigModal) {
43693
+ return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { flexDirection: "column" },
43694
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_ConfigModal_js__WEBPACK_IMPORTED_MODULE_3__/* .ConfigModal */ .y, { onClose: handleConfigModalClose, onMessage: handleConfigModalMessage })));
43695
+ }
43696
+ const shouldShowWelcome = messages.length === 0;
43697
+ const recentMessages = messages.slice(-10);
43698
+ return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { flexDirection: "column", height: "100%" },
43699
+ shouldShowWelcome ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(WelcomeScreen, null)) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { flexDirection: "column", flexGrow: 1, marginBottom: 1 }, recentMessages.map((message) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(MessageItem, { key: message.id, message: message }))))),
43700
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { flexDirection: "column" },
43701
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { borderStyle: "single", borderColor: "gray", paddingX: 1 },
43702
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { color: "cyan", bold: true }, "\u203A"),
43703
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, null, " "),
43704
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink_text_input__WEBPACK_IMPORTED_MODULE_2__/* ["default"] */ .A, { value: input, onChange: setInput, onSubmit: handleSubmit, placeholder: "Enter your prompt..." })),
43705
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { marginTop: 1, paddingX: 1 },
43706
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { dimColor: true }, "Ctrl+C to exit")))));
43707
+ }
43708
+ function renderTerminalUI() {
43709
+ (0,ink__WEBPACK_IMPORTED_MODULE_1__/* .render */ .XX)(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(TerminalUI, null));
43710
+ }
43711
+
43712
+ __webpack_async_result__();
43713
+ } catch(e) { __webpack_async_result__(e); } });
43714
+
43715
+ /***/ }),
43716
+
43309
43717
  /***/ 6878:
43310
43718
  /***/ ((__unused_webpack_module, __webpack_exports__, __nccwpck_require__) => {
43311
43719
 
@@ -43352,11 +43760,13 @@ __nccwpck_require__.a(module, async (__webpack_handle_async_dependencies__, __we
43352
43760
  /* harmony import */ var url__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__nccwpck_require__.n(url__WEBPACK_IMPORTED_MODULE_2__);
43353
43761
  /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __nccwpck_require__(6928);
43354
43762
  /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__nccwpck_require__.n(path__WEBPACK_IMPORTED_MODULE_3__);
43355
- /* harmony import */ var update_notifier__WEBPACK_IMPORTED_MODULE_5__ = __nccwpck_require__(6213);
43356
- /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_6__ = __nccwpck_require__(9611);
43763
+ /* harmony import */ var update_notifier__WEBPACK_IMPORTED_MODULE_6__ = __nccwpck_require__(6213);
43764
+ /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_7__ = __nccwpck_require__(9611);
43357
43765
  /* harmony import */ var _commands_docker_js__WEBPACK_IMPORTED_MODULE_4__ = __nccwpck_require__(5515);
43358
- var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([_commands_docker_js__WEBPACK_IMPORTED_MODULE_4__]);
43359
- _commands_docker_js__WEBPACK_IMPORTED_MODULE_4__ = (__webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__)[0];
43766
+ /* harmony import */ var _components_TerminalUI_js__WEBPACK_IMPORTED_MODULE_5__ = __nccwpck_require__(3535);
43767
+ var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([_commands_docker_js__WEBPACK_IMPORTED_MODULE_4__, _components_TerminalUI_js__WEBPACK_IMPORTED_MODULE_5__]);
43768
+ ([_commands_docker_js__WEBPACK_IMPORTED_MODULE_4__, _components_TerminalUI_js__WEBPACK_IMPORTED_MODULE_5__] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__);
43769
+
43360
43770
 
43361
43771
 
43362
43772
 
@@ -43372,12 +43782,12 @@ const PROGRAM_NAME = 'sith';
43372
43782
  const PROGRAM_VERSION = pkg.version;
43373
43783
  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.';
43374
43784
  // Check for updates (automatic background check)
43375
- const notifier = (0,update_notifier__WEBPACK_IMPORTED_MODULE_5__/* ["default"] */ .A)({ pkg });
43785
+ const notifier = (0,update_notifier__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .A)({ pkg });
43376
43786
  notifier.notify();
43377
43787
  async function checkForUpdates() {
43378
- console.log(chalk__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .Ay.cyan('Checking for updates...'));
43788
+ console.log(chalk__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .Ay.cyan('Checking for updates...'));
43379
43789
  // Force update check by setting updateCheckInterval to 0
43380
- const notifier = (0,update_notifier__WEBPACK_IMPORTED_MODULE_5__/* ["default"] */ .A)({
43790
+ const notifier = (0,update_notifier__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .A)({
43381
43791
  pkg,
43382
43792
  updateCheckInterval: 0
43383
43793
  });
@@ -43386,12 +43796,12 @@ async function checkForUpdates() {
43386
43796
  const update = notifier.update;
43387
43797
  if (update && update.latest !== pkg.version) {
43388
43798
  console.log();
43389
- console.log(chalk__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .Ay.green(`Update available: ${chalk__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .Ay.dim(pkg.version)} → ${chalk__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .Ay.bold(update.latest)}`));
43390
- console.log(chalk__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .Ay.cyan(`Run ${chalk__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .Ay.bold(`npm install -g ${pkg.name}`)} to update`));
43799
+ console.log(chalk__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .Ay.green(`Update available: ${chalk__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .Ay.dim(pkg.version)} → ${chalk__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .Ay.bold(update.latest)}`));
43800
+ console.log(chalk__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .Ay.cyan(`Run ${chalk__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .Ay.bold(`npm install -g ${pkg.name}`)} to update`));
43391
43801
  console.log();
43392
43802
  }
43393
43803
  else {
43394
- console.log(chalk__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .Ay.green(`✓ You're on the latest version (${pkg.version})`));
43804
+ console.log(chalk__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .Ay.green(`✓ You're on the latest version (${pkg.version})`));
43395
43805
  }
43396
43806
  }
43397
43807
  function createProgram() {
@@ -43403,8 +43813,9 @@ function createProgram() {
43403
43813
  .option('--pull', 'Pull prebuilt Docker image (recommended)')
43404
43814
  .option('--build', 'Build the Docker image from scratch')
43405
43815
  .option('--it', 'Launch interactive shell in Docker container')
43406
- .option('--update', 'Check for updates');
43407
- // Default action - show interactive menu or run shell with --it
43816
+ .option('--update', 'Check for updates')
43817
+ .option('--legacy', 'Use legacy menu interface');
43818
+ // Default action - show terminal UI or legacy menu
43408
43819
  program
43409
43820
  .action(async (options) => {
43410
43821
  if (options.update) {
@@ -43413,9 +43824,14 @@ function createProgram() {
43413
43824
  else if (options.it) {
43414
43825
  await (0,_commands_docker_js__WEBPACK_IMPORTED_MODULE_4__/* .runShellDirect */ .l)();
43415
43826
  }
43416
- else {
43827
+ else if (options.legacy || options.pull || options.build) {
43828
+ // Use legacy menu for explicit pull/build or --legacy flag
43417
43829
  await (0,_commands_docker_js__WEBPACK_IMPORTED_MODULE_4__/* .dockerCommand */ .Q)(options);
43418
43830
  }
43831
+ else {
43832
+ // Default: show new terminal UI
43833
+ (0,_components_TerminalUI_js__WEBPACK_IMPORTED_MODULE_5__/* .renderTerminalUI */ .t)();
43834
+ }
43419
43835
  });
43420
43836
  // Docker command - explicit Docker management
43421
43837
  program
@@ -43442,6 +43858,41 @@ program.parse();
43442
43858
  __webpack_async_result__();
43443
43859
  } catch(e) { __webpack_async_result__(e); } });
43444
43860
 
43861
+ /***/ }),
43862
+
43863
+ /***/ 9987:
43864
+ /***/ ((__unused_webpack_module, __webpack_exports__, __nccwpck_require__) => {
43865
+
43866
+ /* harmony export */ __nccwpck_require__.d(__webpack_exports__, {
43867
+ /* harmony export */ K: () => (/* binding */ getAvailableCommands),
43868
+ /* harmony export */ M: () => (/* binding */ parseSlashCommand)
43869
+ /* harmony export */ });
43870
+ function parseSlashCommand(input) {
43871
+ const trimmed = input.trim();
43872
+ if (!trimmed.startsWith("/")) {
43873
+ return null;
43874
+ }
43875
+ const command = trimmed.slice(1).toLowerCase();
43876
+ switch (command) {
43877
+ case "shell":
43878
+ return { type: "shell", raw: trimmed };
43879
+ case "config":
43880
+ return { type: "config", raw: trimmed };
43881
+ case "help":
43882
+ return { type: "help", raw: trimmed };
43883
+ default:
43884
+ return null;
43885
+ }
43886
+ }
43887
+ function getAvailableCommands() {
43888
+ return [
43889
+ { command: "/shell", description: "Start Docker shell (no OpenCode)" },
43890
+ { command: "/config", description: "Open configuration menu" },
43891
+ { command: "/help", description: "Show available commands" },
43892
+ ];
43893
+ }
43894
+
43895
+
43445
43896
  /***/ }),
43446
43897
 
43447
43898
  /***/ 2613:
@@ -58268,6 +58719,142 @@ function indentString(string, count = 1, options = {}) {
58268
58719
  }
58269
58720
 
58270
58721
 
58722
+ /***/ }),
58723
+
58724
+ /***/ 9046:
58725
+ /***/ ((__webpack_module__, __webpack_exports__, __nccwpck_require__) => {
58726
+
58727
+ __nccwpck_require__.a(__webpack_module__, async (__webpack_handle_async_dependencies__, __webpack_async_result__) => { try {
58728
+ /* harmony export */ __nccwpck_require__.d(__webpack_exports__, {
58729
+ /* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__)
58730
+ /* harmony export */ });
58731
+ /* unused harmony export UncontrolledTextInput */
58732
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __nccwpck_require__(2864);
58733
+ /* harmony import */ var ink__WEBPACK_IMPORTED_MODULE_1__ = __nccwpck_require__(3816);
58734
+ /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_2__ = __nccwpck_require__(9611);
58735
+ var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([ink__WEBPACK_IMPORTED_MODULE_1__]);
58736
+ ink__WEBPACK_IMPORTED_MODULE_1__ = (__webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__)[0];
58737
+
58738
+
58739
+
58740
+ function TextInput({ value: originalValue, placeholder = '', focus = true, mask, highlightPastedText = false, showCursor = true, onChange, onSubmit, }) {
58741
+ const [state, setState] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)({
58742
+ cursorOffset: (originalValue || '').length,
58743
+ cursorWidth: 0,
58744
+ });
58745
+ const { cursorOffset, cursorWidth } = state;
58746
+ (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
58747
+ setState(previousState => {
58748
+ if (!focus || !showCursor) {
58749
+ return previousState;
58750
+ }
58751
+ const newValue = originalValue || '';
58752
+ if (previousState.cursorOffset > newValue.length - 1) {
58753
+ return {
58754
+ cursorOffset: newValue.length,
58755
+ cursorWidth: 0,
58756
+ };
58757
+ }
58758
+ return previousState;
58759
+ });
58760
+ }, [originalValue, focus, showCursor]);
58761
+ const cursorActualWidth = highlightPastedText ? cursorWidth : 0;
58762
+ const value = mask ? mask.repeat(originalValue.length) : originalValue;
58763
+ let renderedValue = value;
58764
+ let renderedPlaceholder = placeholder ? chalk__WEBPACK_IMPORTED_MODULE_2__/* ["default"] */ .Ay.grey(placeholder) : undefined;
58765
+ // Fake mouse cursor, because it's too inconvenient to deal with actual cursor and ansi escapes
58766
+ if (showCursor && focus) {
58767
+ renderedPlaceholder =
58768
+ placeholder.length > 0
58769
+ ? chalk__WEBPACK_IMPORTED_MODULE_2__/* ["default"] */ .Ay.inverse(placeholder[0]) + chalk__WEBPACK_IMPORTED_MODULE_2__/* ["default"] */ .Ay.grey(placeholder.slice(1))
58770
+ : chalk__WEBPACK_IMPORTED_MODULE_2__/* ["default"] */ .Ay.inverse(' ');
58771
+ renderedValue = value.length > 0 ? '' : chalk__WEBPACK_IMPORTED_MODULE_2__/* ["default"] */ .Ay.inverse(' ');
58772
+ let i = 0;
58773
+ for (const char of value) {
58774
+ renderedValue +=
58775
+ i >= cursorOffset - cursorActualWidth && i <= cursorOffset
58776
+ ? chalk__WEBPACK_IMPORTED_MODULE_2__/* ["default"] */ .Ay.inverse(char)
58777
+ : char;
58778
+ i++;
58779
+ }
58780
+ if (value.length > 0 && cursorOffset === value.length) {
58781
+ renderedValue += chalk__WEBPACK_IMPORTED_MODULE_2__/* ["default"] */ .Ay.inverse(' ');
58782
+ }
58783
+ }
58784
+ (0,ink__WEBPACK_IMPORTED_MODULE_1__/* .useInput */ .Ge)((input, key) => {
58785
+ if (key.upArrow ||
58786
+ key.downArrow ||
58787
+ (key.ctrl && input === 'c') ||
58788
+ key.tab ||
58789
+ (key.shift && key.tab)) {
58790
+ return;
58791
+ }
58792
+ if (key.return) {
58793
+ if (onSubmit) {
58794
+ onSubmit(originalValue);
58795
+ }
58796
+ return;
58797
+ }
58798
+ let nextCursorOffset = cursorOffset;
58799
+ let nextValue = originalValue;
58800
+ let nextCursorWidth = 0;
58801
+ if (key.leftArrow) {
58802
+ if (showCursor) {
58803
+ nextCursorOffset--;
58804
+ }
58805
+ }
58806
+ else if (key.rightArrow) {
58807
+ if (showCursor) {
58808
+ nextCursorOffset++;
58809
+ }
58810
+ }
58811
+ else if (key.backspace || key.delete) {
58812
+ if (cursorOffset > 0) {
58813
+ nextValue =
58814
+ originalValue.slice(0, cursorOffset - 1) +
58815
+ originalValue.slice(cursorOffset, originalValue.length);
58816
+ nextCursorOffset--;
58817
+ }
58818
+ }
58819
+ else {
58820
+ nextValue =
58821
+ originalValue.slice(0, cursorOffset) +
58822
+ input +
58823
+ originalValue.slice(cursorOffset, originalValue.length);
58824
+ nextCursorOffset += input.length;
58825
+ if (input.length > 1) {
58826
+ nextCursorWidth = input.length;
58827
+ }
58828
+ }
58829
+ if (cursorOffset < 0) {
58830
+ nextCursorOffset = 0;
58831
+ }
58832
+ if (cursorOffset > originalValue.length) {
58833
+ nextCursorOffset = originalValue.length;
58834
+ }
58835
+ setState({
58836
+ cursorOffset: nextCursorOffset,
58837
+ cursorWidth: nextCursorWidth,
58838
+ });
58839
+ if (nextValue !== originalValue) {
58840
+ onChange(nextValue);
58841
+ }
58842
+ }, { isActive: focus });
58843
+ return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, null, placeholder
58844
+ ? value.length > 0
58845
+ ? renderedValue
58846
+ : renderedPlaceholder
58847
+ : renderedValue));
58848
+ }
58849
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (TextInput);
58850
+ function UncontrolledTextInput({ initialValue = '', ...props }) {
58851
+ const [value, setValue] = useState(initialValue);
58852
+ return React.createElement(TextInput, { ...props, value: value, onChange: setValue });
58853
+ }
58854
+ //# sourceMappingURL=index.js.map
58855
+ __webpack_async_result__();
58856
+ } catch(e) { __webpack_async_result__(e); } });
58857
+
58271
58858
  /***/ }),
58272
58859
 
58273
58860
  /***/ 3061:
package/dist/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@m14i/sith","version":"1.11.0","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.","type":"module","repository":{"type":"git","url":"https://github.com/MerzoukeMansouri/sith.git"},"bin":{"sith":"./dist/index.js"},"scripts":{"build":"ncc build src/index.ts -o dist && rm -rf dist/assets && cp -r assets dist/","dev":"tsx src/index.ts","dev:build":"pnpm build && node dist/index.js","dev:shell":"pnpm build && node dist/index.js shell","typecheck":"tsc --noEmit","clean":"rm -rf dist","prepublishOnly":"pnpm build"},"files":["dist","assets","docker"],"keywords":["opencode","docker","ci","automation","cli","nix"],"author":"","license":"MIT","dependencies":{"@inquirer/prompts":"^5.0.0","chalk":"^5.3.0","commander":"^12.1.0","execa":"^9.0.0","ink":"^7.0.3","react":"^19.2.6","update-notifier":"^7.3.1"},"devDependencies":{"@semantic-release/changelog":"^6.0.3","@semantic-release/git":"^10.0.1","@semantic-release/github":"^11.0.1","@semantic-release/npm":"^12.0.1","@types/node":"^20.12.7","@types/react":"^19.2.14","@types/update-notifier":"^6.0.8","@vercel/ncc":"^0.38.1","semantic-release":"^24.2.0","tsx":"^4.7.2","typescript":"^5.4.5"},"engines":{"node":">=18"}}
1
+ {"name":"@m14i/sith","version":"1.13.0","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.","type":"module","repository":{"type":"git","url":"https://github.com/MerzoukeMansouri/sith.git"},"bin":{"sith":"./dist/index.js"},"scripts":{"build":"ncc build src/index.ts -o dist && rm -rf dist/assets && cp -r assets dist/","dev":"tsx src/index.ts","dev:build":"pnpm build && node dist/index.js","dev:shell":"pnpm build && node dist/index.js shell","typecheck":"tsc --noEmit","clean":"rm -rf dist","prepublishOnly":"pnpm build"},"files":["dist","assets","docker"],"keywords":["opencode","docker","ci","automation","cli","nix"],"author":"","license":"MIT","dependencies":{"@inquirer/prompts":"^5.0.0","chalk":"^5.3.0","commander":"^12.1.0","execa":"^9.0.0","ink":"^7.0.3","ink-text-input":"^6.0.0","react":"^19.2.6","update-notifier":"^7.3.1"},"devDependencies":{"@semantic-release/changelog":"^6.0.3","@semantic-release/git":"^10.0.1","@semantic-release/github":"^11.0.1","@semantic-release/npm":"^12.0.1","@types/node":"^20.12.7","@types/react":"^19.2.14","@types/update-notifier":"^6.0.8","@vercel/ncc":"^0.38.1","semantic-release":"^24.2.0","tsx":"^4.7.2","typescript":"^5.4.5"},"engines":{"node":">=18"}}
@@ -0,0 +1,11 @@
1
+ export type SlashCommandType = "shell" | "config" | "help";
2
+ export interface SlashCommand {
3
+ type: SlashCommandType;
4
+ raw: string;
5
+ }
6
+ export declare function parseSlashCommand(input: string): SlashCommand | null;
7
+ export declare function getAvailableCommands(): Array<{
8
+ command: string;
9
+ description: string;
10
+ }>;
11
+ //# sourceMappingURL=slashCommands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slashCommands.d.ts","sourceRoot":"","sources":["file:///home/runner/work/sith/sith/src/utils/slashCommands.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE3D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,gBAAgB,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAmBpE;AAED,wBAAgB,oBAAoB,IAAI,KAAK,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAMtF"}
@@ -1,14 +1,2 @@
1
1
  #!/bin/bash
2
2
  # Banner and version display
3
-
4
- echo "╔══════════════════════════════════════════════════════════╗"
5
- echo "║ 🚀 OpenCode CI - Nix Environment (CI/CD Ready) ║"
6
- echo "╚══════════════════════════════════════════════════════════╝"
7
- echo ""
8
- echo "📦 Versions installées:"
9
- echo " • Bash: $(bash --version | head -n1)"
10
- echo " • Node.js: $(node --version)"
11
- echo " • Python: $(python3 --version)"
12
- echo " • Git: $(git --version | cut -d' ' -f3)"
13
- echo " • jq: $(jq --version)"
14
- echo ""
@@ -3,16 +3,3 @@
3
3
 
4
4
  # Configurer le PATH pour OpenCode
5
5
  export PATH="$HOME/.opencode/bin:$PATH"
6
-
7
- if command -v opencode &> /dev/null; then
8
- OPENCODE_VERSION=$(opencode --version 2>&1 | head -n1 || echo 'ok')
9
- OPENCODE_PATH=$(command -v opencode)
10
- echo "✅ OpenCode CLI disponible"
11
- echo " Version: $OPENCODE_VERSION"
12
- echo " Chemin: $OPENCODE_PATH"
13
- else
14
- echo "⚠️ OpenCode CLI non trouvé"
15
- echo " Installer: curl -fsSL https://opencode.ai/install | bash"
16
- fi
17
-
18
- echo ""
@@ -1,42 +1,28 @@
1
1
  #!/bin/bash
2
2
  # Token optimization skills installation (RTK + Caveman)
3
3
 
4
- echo "=== Installation des Skills d'Optimisation de Tokens ==="
5
- echo ""
6
-
7
4
  mkdir -p /root/.agents/skills
8
5
 
6
+ # Track installed skills
7
+ declare -a INSTALLED_SKILLS=()
8
+
9
9
  # 1. RTK (Rust Token Killer)
10
- # NOTE: RTK n'est actuellement pas disponible publiquement
11
- # Désactivé par défaut - peut être activé si vous avez le binaire
12
10
  if [ "${RTK_ENABLED:-false}" = "true" ]; then
13
- echo "📦 Installation de RTK (Rust Token Killer)..."
14
-
15
11
  mkdir -p /root/.agents/skills/rtk/bin
16
12
  mkdir -p /root/.agents/skills/rtk/config
17
-
18
- if [ ! -f /root/.agents/skills/rtk/bin/rtk ]; then
19
- echo " ⚠️ RTK binaire non disponible publiquement"
20
- echo " Pour utiliser RTK:"
21
- echo " 1. Copier votre binaire RTK dans l'image"
22
- echo " 2. Ou monter: -v /path/to/rtk:/root/.agents/skills/rtk/bin/rtk"
23
- else
24
- echo " ✅ RTK déjà installé: $(/root/.agents/skills/rtk/bin/rtk --version 2>&1)"
25
- fi
26
-
27
- # Copier la configuration RTK
13
+
28
14
  if [ -f /opt/sith/skills/rtk-config.toml ]; then
29
15
  cp /opt/sith/skills/rtk-config.toml /root/.agents/skills/rtk/config/config.toml
30
16
  mkdir -p /root/.config/rtk
31
17
  ln -sf /root/.agents/skills/rtk/config/config.toml /root/.config/rtk/config.toml
32
- echo " ✅ Configuration RTK prête (binaire requis)"
33
18
  fi
34
-
35
- # Initialiser le hook bash pour RTK
19
+
36
20
  if command -v rtk &> /dev/null; then
21
+ RTK_VERSION=$(rtk --version 2>&1 | head -n1 | awk '{print $2}' || echo "unknown")
22
+ INSTALLED_SKILLS+=("RTK|$RTK_VERSION|https://github.com/rust-token-killer/rtk")
23
+
37
24
  if [ -f /root/.bashrc ] && ! grep -q "rtk hook" /root/.bashrc; then
38
25
  echo 'eval "$(rtk hook bash)"' >> /root/.bashrc
39
- echo " ✅ RTK hook bash configuré"
40
26
  fi
41
27
  eval "$(rtk hook bash)" 2>/dev/null || true
42
28
  fi
@@ -44,20 +30,15 @@ fi
44
30
 
45
31
  # 2. Caveman (mode ultra)
46
32
  if [ "${CAVEMAN_AUTO:-true}" = "true" ]; then
47
- echo "📦 Installation de Caveman skill (mode ultra)..."
48
-
49
33
  mkdir -p /root/.agents/skills
50
34
 
51
- # Download Caveman if not present
52
35
  if [ ! -d /opt/sith/skills/caveman ]; then
53
- echo " 📥 Downloading Caveman from GitHub..."
54
36
  mkdir -p /opt/sith/skills
55
37
  cd /opt/sith/skills
56
- curl -fsSL https://github.com/JuliusBrussee/caveman/archive/refs/heads/main.zip -o caveman.zip
57
- unzip -q caveman.zip
58
- mv caveman-main caveman
59
- rm caveman.zip
60
- echo " ✅ Caveman downloaded"
38
+ curl -fsSL https://github.com/JuliusBrussee/caveman/archive/refs/heads/main.zip -o caveman.zip 2>/dev/null
39
+ unzip -q caveman.zip 2>/dev/null
40
+ mv caveman-main caveman 2>/dev/null
41
+ rm caveman.zip 2>/dev/null
61
42
  fi
62
43
 
63
44
  if [ -d /opt/sith/skills/caveman ]; then
@@ -68,9 +49,8 @@ mode=ultra
68
49
  auto_activate=true
69
50
  EOF
70
51
 
71
- echo " ✅ Caveman installé en mode ultra (compression maximale)"
72
- else
73
- echo " ⚠️ Caveman skill non trouvé - continuant sans Caveman"
52
+ CAVEMAN_VERSION=$(grep -oP '(?<=version: ).*' /root/.agents/skills/caveman/skill.json 2>/dev/null || echo "main")
53
+ INSTALLED_SKILLS+=("Caveman|$CAVEMAN_VERSION|https://github.com/JuliusBrussee/caveman")
74
54
  fi
75
55
  fi
76
56
 
@@ -80,13 +60,18 @@ if [ -f /opt/sith/skills/opencode-skills-config.json ]; then
80
60
  cp /opt/sith/skills/opencode-skills-config.json /root/.local/share/opencode/skills/config.json
81
61
  fi
82
62
 
83
- # Résumé
84
- echo ""
85
- echo "🎯 Skills d'optimisation de tokens:"
86
- if command -v rtk &> /dev/null && [ "${RTK_ENABLED:-true}" = "true" ]; then
87
- echo " RTK: Actif (60-90% réduction sur commandes CLI)"
88
- fi
89
- if [ -d /root/.agents/skills/caveman ] && [ "${CAVEMAN_AUTO:-true}" = "true" ]; then
90
- echo " ✅ Caveman: Mode ultra (75%+ compression de langage)"
63
+ # Display table if any skills installed
64
+ if [ ${#INSTALLED_SKILLS[@]} -gt 0 ]; then
65
+ echo ""
66
+ echo "┌─────────────────┬──────────┬─────────────────────────────────────────┐"
67
+ echo " Skill │ Version │ GitHub │"
68
+ echo "├─────────────────┼──────────┼─────────────────────────────────────────┤"
69
+
70
+ for skill_info in "${INSTALLED_SKILLS[@]}"; do
71
+ IFS='|' read -r name version github <<< "$skill_info"
72
+ printf "│ %-15s │ %-8s │ %-39s │\n" "$name" "$version" "$github"
73
+ done
74
+
75
+ echo "└─────────────────┴──────────┴─────────────────────────────────────────┘"
76
+ echo ""
91
77
  fi
92
- echo ""
@@ -1,6 +1,12 @@
1
1
  #!/bin/bash
2
2
  # Ready message
3
3
 
4
- echo "🎯 Environnement prêt pour CI/CD"
4
+ if command -v catimg &> /dev/null && [ -f /workspace/assets/images/logo.png ]; then
5
+ catimg -w 80 /workspace/assets/images/logo.png 2>/dev/null
6
+ echo ""
7
+ fi
8
+
9
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
10
+ echo " Environment Ready"
5
11
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
6
12
  echo ""
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m14i/sith",
3
- "version": "1.11.0",
3
+ "version": "1.13.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": {
@@ -40,6 +40,7 @@
40
40
  "commander": "^12.1.0",
41
41
  "execa": "^9.0.0",
42
42
  "ink": "^7.0.3",
43
+ "ink-text-input": "^6.0.0",
43
44
  "react": "^19.2.6",
44
45
  "update-notifier": "^7.3.1"
45
46
  },