wrosecode 0.0.0-stage → 1.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 WROSECODE contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,233 @@
1
- # Temporary Holding Version
1
+ <p align="center">
2
+ <img src="docs/assets/wrosecode-logo.webp" alt="WROSECODE neon rose terminal logo" width="160">
3
+ </p>
2
4
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
5
+ <h1 align="center">WROSECODE</h1>
6
+
7
+ <p align="center">
8
+ <strong>A native Rust AI coding agent for your terminal.</strong><br>
9
+ <em>Build software. Explore code. Solve authorized CTF labs. Document security findings.</em>
10
+ </p>
11
+
12
+ <p align="center">
13
+ <a href="https://github.com/whiterose717/WROSECODE-CLI/actions/workflows/ci.yml"><img src="https://github.com/whiterose717/WROSECODE-CLI/actions/workflows/ci.yml/badge.svg" alt="GitHub Actions CI status"></a>
14
+ <a href="https://www.npmjs.com/package/wrosecode"><img src="https://img.shields.io/npm/v/wrosecode?logo=npm&amp;label=npm" alt="Published npm version"></a>
15
+ <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-16a34a.svg" alt="MIT license"></a>
16
+ <a href="https://www.rust-lang.org/"><img src="https://img.shields.io/badge/Built%20with-Rust-orange?logo=rust" alt="Built with Rust"></a>
17
+ <img src="https://img.shields.io/badge/platforms-Linux%20%7C%20macOS%20%7C%20Windows-4063d8" alt="Linux, macOS and Windows">
18
+ </p>
19
+
20
+ <p align="center">
21
+ <a href="#installation"><strong>Get started</strong></a> ·
22
+ <a href="#screenshots">Screenshots</a> ·
23
+ <a href="#features">Features</a> ·
24
+ <a href="#security-research-workflows">CTF &amp; VAPT</a> ·
25
+ <a href="#documentation">Documentation</a>
26
+ </p>
27
+
28
+ ---
29
+
30
+ WROSECODE combines a streaming, keyboard-driven **terminal UI** with repository-aware tools, configurable AI providers, persistent sessions, optional MCP integrations, built-in checks, and controlled execution. It is designed for everyday development and for **permissioned** CTF, VAPT, and bug-bounty workflows.
31
+
32
+ > [!NOTE]
33
+ > The `main` branch contains the v1.0.1 source update. The public npm version is shown by the npm badge above and may be older until the corresponding native GitHub Release is published.
34
+
35
+ ## Screenshots
36
+
37
+ ### Native Rust terminal UI
38
+
39
+ Real screenshots captured from the WROSECODE executable using an isolated demo workspace, without account credentials or real target data.
40
+
41
+ <div align="center">
42
+ <a href="docs/assets/terminal-start.png"><img src="docs/assets/terminal-start.png" alt="Native WROSECODE terminal start screen with cyan wordmark and status footer" width="900"></a>
43
+ <sub>Start screen · provider and mode overview · compact status footer</sub>
44
+ </div>
45
+
46
+ <br>
47
+
48
+ <div align="center">
49
+ <a href="docs/assets/terminal-commands.png"><img src="docs/assets/terminal-commands.png" alt="Native WROSECODE CLI displaying the built-in slash command help" width="900"></a>
50
+ <sub>Built-in command help and keyboard-first navigation</sub>
51
+ </div>
52
+
53
+ ### Optional companion Web Console
54
+
55
+ These are previews of the **separate companion Web Console**, not the native CLI window. Connecting a device and configuring a backend may be required to use them.
56
+
57
+ | Web chat | CTF workbench |
58
+ |:--:|:--:|
59
+ | <a href="docs/assets/web-console-chat.png"><img src="docs/assets/web-console-chat.png" alt="WROSECODE companion Web Console chat with device pairing and agent mode selection" width="460"></a> | <a href="docs/assets/web-console-ctf.png"><img src="docs/assets/web-console-ctf.png" alt="WROSECODE companion Web Console CTF challenge configuration and flag results panel" width="460"></a> |
60
+ | Paired-device chat and agent mode selection | Local challenge input, analysis workflow and results panel |
61
+
62
+ ## Installation
63
+
64
+ ### Option 1 — npm (recommended for end users)
65
+
66
+ Requires **Node.js 18+** and network access on the first installation/run to download the native executable.
67
+
68
+ ```bash
69
+ npm install -g wrosecode
70
+ wrosecode --version
71
+ wrosecode
72
+ ```
73
+
74
+ Run without a permanent installation:
75
+
76
+ ```bash
77
+ npx wrosecode
78
+ ```
79
+
80
+ Update or uninstall:
81
+
82
+ ```bash
83
+ npm install -g wrosecode@latest
84
+ npm uninstall -g wrosecode
85
+ ```
86
+
87
+ The npm package is a small JavaScript launcher, not a bundled Rust binary. It downloads the **matching native release asset** from [GitHub Releases](https://github.com/whiterose717/WROSECODE-CLI/releases) and verifies its **SHA-256 checksum**. If your npm version disables lifecycle scripts by default, the launcher downloads the verified binary when first run.
88
+
89
+ Supported native release targets: **Linux x86_64 / ARM64**, **macOS x86_64 / Apple Silicon**, and **Windows x86_64 / ARM64**. Availability depends on the corresponding GitHub Release assets.
90
+
91
+ > Installing a version before its matching GitHub Release exists will not work. If `npm install -g` encounters a permission conflict with an older system-wide binary, use a user-owned npm prefix or back up the old binary first; do not weaken system directory permissions.
92
+
93
+ ### Option 2 — build from Rust source
94
+
95
+ Install a supported Rust toolchain and Cargo, then:
96
+
97
+ ```bash
98
+ git clone https://github.com/whiterose717/WROSECODE-CLI.git
99
+ cd WROSECODE-CLI
100
+ cargo build --release --locked
101
+ ./target/release/wrosecode --version
102
+ ./target/release/wrosecode
103
+ ```
104
+
105
+ You can also install the checked-out source using `cargo install --path . --locked`.
106
+
107
+ ## Quick start
108
+
109
+ Open the CLI from the repository you want to work in:
110
+
111
+ ```bash
112
+ cd /path/to/your/project
113
+ wrosecode
114
+ ```
115
+
116
+ Try a one-shot development task:
117
+
118
+ ```bash
119
+ wrosecode --mode build "Review this repository and suggest a small, testable improvement."
120
+ ```
121
+
122
+ Inside the interactive UI:
123
+
124
+ ```text
125
+ /help Show available commands
126
+ /providers Configure, authenticate, or test model connections
127
+ /ctf Open the CTF workflow
128
+ /bugbounty Arm a scoped security assessment
129
+ /resume Continue a saved session
130
+ Ctrl+T Change thinking level
131
+ Ctrl+D Open the dashboard
132
+ ```
133
+
134
+ For provider setup, use `/providers` or the supported environment variables. **Never put API keys in Git commits, README examples, or issue screenshots.**
135
+
136
+ ## Features
137
+
138
+ | Capability | What it provides |
139
+ |---|---|
140
+ | **Native Rust TUI** | Responsive, streaming, keyboard-first interface with compact resource and progress information |
141
+ | **Multiple AI backends** | Provider profiles, compatible APIs and configurable model/thinking choices |
142
+ | **Repository awareness** | File context, project instructions, repository maps, code editing and local test workflows |
143
+ | **Tool integration** | Shell tools, optional MCP providers and developer workflows with permission controls |
144
+ | **Persistent sessions** | Resumable conversations, checkpoints, exports and session diagnostics |
145
+ | **Headless execution** | CLI automation, machine-readable events, budgets and bounded run limits |
146
+ | **CTF mode** | Challenge analysis, local solver development and evidence-based flag verification |
147
+ | **VAPT / Bug Bounty** | Program allowlists, OWASP-oriented checklists, controlled authorization testing and evidence-backed reports |
148
+
149
+ Features requiring a provider account, an external app, MCP server or other optional service are **not** enabled automatically.
150
+
151
+ ## Security research workflows
152
+
153
+ WROSECODE supports **authorized research only**. Set an explicit target scope and follow the program's testing rules. Do not use production customer data, attack out-of-scope infrastructure or assume automated findings are verified.
154
+
155
+ ### CTF labs
156
+
157
+ Use the interactive `/ctf` workflow or a task with CTF mode:
158
+
159
+ ```bash
160
+ wrosecode --mode ctf
161
+ ```
162
+
163
+ Analyze challenge material you are allowed to test, build a reproducible solver, and confirm the result with tool output. A model-generated flag alone is **not** proof of a solved challenge.
164
+
165
+ ### VAPT and bug bounty
166
+
167
+ Example syntax using a **placeholder domain**; replace it with the exact host authorized by your program:
168
+
169
+ ```bash
170
+ wrosecode bugbounty https://app.example.test \
171
+ --scope app.example.test \
172
+ --program "Authorized Assessment"
173
+ ```
174
+
175
+ The engagement workflow can create `.bugbounty/VAPT_ASSESSMENT.md`, containing an offline **OWASP WSTG / ASVS** checklist and an **API BOLA/IDOR role-object matrix** for researcher-owned test accounts. Scope guardrails, bounded HTTP behavior, response/evidence checks, and report verification support low-impact testing; they do not substitute for explicit authorization.
176
+
177
+ Findings follow an evidence-gated process:
178
+
179
+ ```text
180
+ Potential → Investigating → Reproduced → Verified → Reported
181
+ ```
182
+
183
+ Verified reports can include analyst-supplied **CWE, WSTG, ASVS, CVSS vector, severity rationale**, reproduction steps and remediation. Unconfirmed scanner hits should not be presented as confirmed vulnerabilities.
184
+
185
+ ## Permissions and responsible use
186
+
187
+ - Start with interactive approval (`ask`) or the appropriate bounded permission mode. Do not use broad `yolo` permissions on untrusted code or systems.
188
+ - Keep test data synthetic, honor target exclusions and rate limits, and stop testing when the program or service blocks requests.
189
+ - Keep credentials, CTF flags, raw request/response captures and personal data out of public issues and screenshots.
190
+ - See [sandbox implementation details](docs/CLI_REFERENCE.md#shell-sandbox) and [contribution guidance](CONTRIBUTING.md).
191
+
192
+ ## Development and quality checks
193
+
194
+ The release workflow uses Rust and Node.js checks. From a source checkout:
195
+
196
+ ```bash
197
+ npm ci --ignore-scripts
198
+ npm run check
199
+ cargo fmt --check
200
+ cargo clippy --all-targets -- -D warnings
201
+ cargo test --all-targets
202
+ cargo build --release --locked
203
+ ```
204
+
205
+ CI runs on **Linux, macOS and Windows**. The CI badge reports the current public workflow status; it is not a guarantee that every optional external provider is available.
206
+
207
+ ## Documentation
208
+
209
+ | Resource | Description |
210
+ |---|---|
211
+ | [Full CLI reference](docs/CLI_REFERENCE.md) | Original detailed README content, including TUI controls, providers and advanced workflows |
212
+ | [Architecture](ARCHITECTURE.md) | Internal design and components |
213
+ | [Feature reference](docs/features.md) | Detailed capabilities |
214
+ | [Agent API](API.md) | Local API and integration notes |
215
+ | [Benchmarks](BENCHMARKS.md) | Benchmark notes and methodology |
216
+ | [Contributing](CONTRIBUTING.md) | Development and testing expectations |
217
+ | [GitHub releases](https://github.com/whiterose717/WROSECODE-CLI/releases) | Native releases, versioned binaries and checksums |
218
+
219
+ ## License
220
+
221
+ WROSECODE is open source under the **MIT License**.
222
+
223
+ See the complete [LICENSE](LICENSE) file for legal terms and copyright information. The existing license text and attribution are preserved.
224
+
225
+ ---
226
+
227
+ <div align="center">
228
+
229
+ **Built for the terminal. Grounded in reproducible work.**
230
+
231
+ [GitHub](https://github.com/whiterose717/WROSECODE-CLI) · [npm](https://www.npmjs.com/package/wrosecode) · [Releases](https://github.com/whiterose717/WROSECODE-CLI/releases) · [Issues](https://github.com/whiterose717/WROSECODE-CLI/issues)
232
+
233
+ </div>
@@ -0,0 +1,164 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const pkg = require('../package.json');
6
+ const lock = require('../package-lock.json');
7
+ const cargoToml = fs.readFileSync(path.resolve(__dirname, '../Cargo.toml'), 'utf8');
8
+ const installer = require('./install.js');
9
+
10
+ const root = path.resolve(__dirname, '..');
11
+ const errors = [];
12
+ const expectedRepo = 'https://github.com/whiterose717/WROSECODE-CLI.git';
13
+ const expectedHomepage = 'https://github.com/whiterose717/WROSECODE-CLI#readme';
14
+ const expectedBugs = 'https://github.com/whiterose717/WROSECODE-CLI/issues';
15
+ const expectedFiles = [
16
+ 'npm/wrosecode.js',
17
+ 'npm/install.js',
18
+ 'npm/check-publish.js',
19
+ 'LICENSE',
20
+ 'README.md'
21
+ ];
22
+ const requiredAssets = [
23
+ ['linux', 'x64', 'wrosecode-linux-x86_64'],
24
+ ['linux', 'arm64', 'wrosecode-linux-aarch64'],
25
+ ['darwin', 'x64', 'wrosecode-darwin-x86_64'],
26
+ ['darwin', 'arm64', 'wrosecode-darwin-aarch64'],
27
+ ['win32', 'x64', 'wrosecode-windows-x86_64.exe'],
28
+ ['win32', 'arm64', 'wrosecode-windows-aarch64.exe']
29
+ ];
30
+
31
+ function requireCondition(condition, message) {
32
+ if (!condition) errors.push(message);
33
+ }
34
+
35
+ requireCondition(pkg.name === 'wrosecode', 'package name must be "wrosecode".');
36
+ requireCondition(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(pkg.version || ''), 'package version must use semantic versioning.');
37
+ requireCondition(pkg.version === lock.version && lock.packages?.['']?.version === pkg.version, 'package-lock.json version does not match package.json.');
38
+ requireCondition(new RegExp(`^version\\s*=\\s*"${pkg.version.replaceAll('.', '\\.')}"$`, 'm').test(cargoToml), 'Cargo.toml version does not match package.json.');
39
+ requireCondition(typeof pkg.description === 'string' && pkg.description.trim().length > 0, 'package description is required.');
40
+ requireCondition(pkg.license === 'MIT', 'package license must be MIT.');
41
+ requireCondition(fs.existsSync(path.join(root, 'LICENSE')) && fs.readFileSync(path.join(root, 'LICENSE'), 'utf8').startsWith('MIT License'), 'MIT LICENSE file is missing or invalid.');
42
+ requireCondition(Array.isArray(pkg.keywords) && pkg.keywords.length > 0, 'at least one package keyword is required.');
43
+ requireCondition(pkg.engines?.node === '>=18', 'Node.js engine must be >=18.');
44
+ requireCondition(pkg.bin?.wrosecode === 'npm/wrosecode.js', 'wrosecode bin must point to npm/wrosecode.js.');
45
+ requireCondition(pkg.repository?.type === 'git' && pkg.repository?.url === expectedRepo, `repository.url must be ${expectedRepo}.`);
46
+ requireCondition(pkg.homepage === expectedHomepage, `homepage must be ${expectedHomepage}.`);
47
+ requireCondition(pkg.bugs?.url === expectedBugs, `bugs.url must be ${expectedBugs}.`);
48
+ requireCondition(JSON.stringify(pkg.files) === JSON.stringify(expectedFiles), 'package files allowlist must contain only the five approved npm distribution files.');
49
+
50
+ for (const relativePath of expectedFiles) {
51
+ const file = path.join(root, relativePath);
52
+ requireCondition(fs.existsSync(file) && fs.statSync(file).isFile(), `required package file is missing: ${relativePath}`);
53
+ }
54
+
55
+ const launcherPath = path.join(root, 'npm/wrosecode.js');
56
+ if (fs.existsSync(launcherPath)) {
57
+ const launcher = fs.readFileSync(launcherPath, 'utf8');
58
+ requireCondition(launcher.startsWith('#!/usr/bin/env node\n'), 'npm/wrosecode.js must have the Node.js executable shebang.');
59
+ }
60
+
61
+ const installerPath = path.join(root, 'npm/install.js');
62
+ let installerSource = '';
63
+ if (fs.existsSync(installerPath)) {
64
+ installerSource = fs.readFileSync(installerPath, 'utf8');
65
+ for (const [platform, arch, expectedAsset] of requiredAssets) {
66
+ requireCondition(installer.assetName(platform, arch) === expectedAsset, `installer asset mapping is incorrect for ${platform}/${arch}.`);
67
+ }
68
+ const previousOverride = process.env.WROSECODE_RELEASE_BASE;
69
+ delete process.env.WROSECODE_RELEASE_BASE;
70
+ try {
71
+ requireCondition(installer.releaseBase(pkg) === `https://github.com/whiterose717/WROSECODE-CLI/releases/download/v${pkg.version}`, 'installer release URL must resolve from repository metadata and package version.');
72
+ } catch (error) {
73
+ errors.push(`installer cannot derive the release URL: ${error.message}`);
74
+ } finally {
75
+ if (previousOverride === undefined) delete process.env.WROSECODE_RELEASE_BASE;
76
+ else process.env.WROSECODE_RELEASE_BASE = previousOverride;
77
+ }
78
+ requireCondition(installerSource.includes("protocol !== 'https:'") && installerSource.includes("createHash('sha256')") && installerSource.includes('actual !== expected'), 'installer must enforce HTTPS and SHA-256 verification.');
79
+ requireCondition(!/(?:YOUR_GITHUB|YOUR_REPOSITORY|example\.com|placeholder|TODO_RELEASE_URL)/i.test(installerSource), 'installer contains a placeholder release URL or TODO.');
80
+ }
81
+
82
+ const readmePath = path.join(root, 'README.md');
83
+ if (fs.existsSync(readmePath)) {
84
+ const readme = fs.readFileSync(readmePath, 'utf8');
85
+ requireCondition(readme.includes(expectedRepo.replace(/\.git$/, '')), 'README must link to the actual GitHub repository.');
86
+ requireCondition(!/(?:<YOUR_GITHUB_REPOSITORY_URL>|github\.com\/(?:example|your-org|your-user)\/)/i.test(readme), 'README contains a placeholder repository URL.');
87
+ for (const command of [
88
+ 'npm install -g wrosecode',
89
+ 'wrosecode',
90
+ 'npx wrosecode',
91
+ 'npm install -g wrosecode@latest',
92
+ 'npm uninstall -g wrosecode'
93
+ ]) requireCondition(readme.includes(command), `README is missing the npm command: ${command}`);
94
+ }
95
+
96
+ // Scan only files that npm is explicitly permitted to publish. Never emit a
97
+ // matching line or credential value in diagnostics.
98
+ const credentialPatterns = [
99
+ /-----BEGIN (?:RSA |EC |OPENSSH |DSA )?PRIVATE KEY-----/,
100
+ /\b(?:gh[pousr]_[A-Za-z0-9]{30,}|github_pat_[A-Za-z0-9_]{40,}|npm_[A-Za-z0-9]{30,}|AKIA[0-9A-Z]{16})\b/,
101
+ /\bsk-(?:ant|proj|live|svc)?-[A-Za-z0-9_-]{32,}\b/i,
102
+ /\b(?:ANTHROPIC_API_KEY|OPENAI_API_KEY|NPM_TOKEN|GITHUB_TOKEN|CTFD_TOKEN)\s*[:=]\s*["']?([^\s"'#]{24,})/i
103
+ ];
104
+ for (const relativePath of expectedFiles) {
105
+ const file = path.join(root, relativePath);
106
+ if (!fs.existsSync(file) || !fs.statSync(file).isFile()) continue;
107
+ const content = fs.readFileSync(file, 'utf8');
108
+ if (credentialPatterns.some((pattern) => pattern.test(content))) {
109
+ errors.push(`possible hard-coded credential detected in npm package file: ${relativePath}`);
110
+ }
111
+ }
112
+
113
+ async function verifyPublishedRelease() {
114
+ const endpoint = `https://api.github.com/repos/whiterose717/WROSECODE-CLI/releases/tags/v${pkg.version}`;
115
+ let response;
116
+ try {
117
+ response = await fetch(endpoint, {
118
+ headers: {
119
+ accept: 'application/vnd.github+json',
120
+ 'x-github-api-version': '2022-11-28',
121
+ 'user-agent': 'wrosecode-npm-publish-check'
122
+ },
123
+ signal: AbortSignal.timeout(20_000)
124
+ });
125
+ } catch (error) {
126
+ errors.push(`could not verify GitHub Release v${pkg.version}: ${error.message}`);
127
+ return;
128
+ }
129
+ if (!response.ok) {
130
+ errors.push(`GitHub Release v${pkg.version} is not publicly available (HTTP ${response.status}); push the matching tag and wait for the release workflow before publishing.`);
131
+ return;
132
+ }
133
+
134
+ let release;
135
+ try {
136
+ release = await response.json();
137
+ } catch {
138
+ errors.push('GitHub returned invalid release metadata; cannot verify native download assets.');
139
+ return;
140
+ }
141
+ requireCondition(release.tag_name === `v${pkg.version}` && !release.draft && !release.prerelease, `GitHub Release v${pkg.version} must be published (not draft or prerelease).`);
142
+ const availableAssets = new Set((release.assets || []).map((asset) => asset.name));
143
+ const missingAssets = requiredAssets.flatMap(([, , asset]) => [asset, `${asset}.sha256`]).filter((asset) => !availableAssets.has(asset));
144
+ requireCondition(missingAssets.length === 0, `GitHub Release v${pkg.version} is missing assets: ${missingAssets.join(', ')}.`);
145
+ }
146
+
147
+ if (errors.length) {
148
+ console.error('npm publish preflight failed:');
149
+ for (const error of errors) console.error(`- ${error}`);
150
+ process.exit(1);
151
+ }
152
+
153
+ verifyPublishedRelease().then(() => {
154
+ if (errors.length) {
155
+ console.error('npm publish preflight failed:');
156
+ for (const error of errors) console.error(`- ${error}`);
157
+ process.exitCode = 1;
158
+ return;
159
+ }
160
+ console.log(`npm publish preflight passed for ${pkg.name}@${pkg.version}; matching public release assets are present.`);
161
+ }).catch((error) => {
162
+ console.error(`npm publish preflight failed: ${error.message}`);
163
+ process.exitCode = 1;
164
+ });
package/npm/install.js ADDED
@@ -0,0 +1,142 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('node:crypto');
4
+ const fs = require('node:fs/promises');
5
+ const os = require('node:os');
6
+ const path = require('node:path');
7
+
8
+ const MAX_BINARY_BYTES = 300 * 1024 * 1024;
9
+ const PLATFORM_ASSETS = {
10
+ 'linux:x64': 'wrosecode-linux-x86_64',
11
+ 'linux:arm64': 'wrosecode-linux-aarch64',
12
+ 'darwin:x64': 'wrosecode-darwin-x86_64',
13
+ 'darwin:arm64': 'wrosecode-darwin-aarch64',
14
+ 'win32:x64': 'wrosecode-windows-x86_64.exe',
15
+ 'win32:arm64': 'wrosecode-windows-aarch64.exe'
16
+ };
17
+
18
+ function assetName(platform = process.platform, arch = process.arch) {
19
+ const name = PLATFORM_ASSETS[`${platform}:${arch}`];
20
+ if (!name) {
21
+ throw new Error(`Unsupported platform ${platform}/${arch}. Supported targets: Linux, macOS, and Windows on x86_64 or aarch64.`);
22
+ }
23
+ return name;
24
+ }
25
+
26
+ function releaseBase(pkg) {
27
+ if (process.env.WROSECODE_RELEASE_BASE) return process.env.WROSECODE_RELEASE_BASE.replace(/\/+$/, '');
28
+
29
+ const configured = pkg.repository?.url;
30
+ if (typeof configured !== 'string') throw new Error('package.json is missing repository.url; cannot locate the native release.');
31
+ const normalized = configured.replace(/^git\+/, '').replace(/\.git$/, '');
32
+ let repository;
33
+ try {
34
+ repository = new URL(normalized);
35
+ } catch {
36
+ throw new Error('package.json repository.url is not a valid HTTPS GitHub URL.');
37
+ }
38
+ if (repository.protocol !== 'https:' || repository.hostname.toLowerCase() !== 'github.com' || repository.pathname.toLowerCase() !== '/whiterose717/wrosecode-cli') {
39
+ throw new Error('package.json repository.url must identify https://github.com/whiterose717/WROSECODE-CLI.git.');
40
+ }
41
+ if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(pkg.version)) throw new Error(`Invalid package version: ${pkg.version}`);
42
+ return `${repository.origin}${repository.pathname}/releases/download/v${pkg.version}`;
43
+ }
44
+
45
+ function userCacheBinaryPath(version, platform = process.platform) {
46
+ const binaryName = platform === 'win32' ? 'wrosecode.exe' : 'wrosecode';
47
+ if (platform === 'win32') {
48
+ const localAppData = process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local');
49
+ return path.join(localAppData, 'WROSECODE', version, binaryName);
50
+ }
51
+ const cacheHome = process.env.XDG_CACHE_HOME || path.join(os.homedir(), '.cache');
52
+ return path.join(cacheHome, 'wrosecode', version, binaryName);
53
+ }
54
+
55
+ async function fetchHttps(url) {
56
+ const parsed = new URL(url);
57
+ if (parsed.protocol !== 'https:') throw new Error('Release downloads must use HTTPS.');
58
+ const response = await fetch(parsed, { signal: AbortSignal.timeout(120_000), redirect: 'follow' });
59
+ if (!response.ok) throw new Error(`Download failed (${response.status} ${response.statusText}): ${parsed}`);
60
+ if (new URL(response.url).protocol !== 'https:') throw new Error('Release download redirected to a non-HTTPS URL.');
61
+ return response;
62
+ }
63
+
64
+ async function readLimited(response, limit) {
65
+ if (!response.body) throw new Error('Release server returned an empty response body.');
66
+ const reader = response.body.getReader();
67
+ const chunks = [];
68
+ let size = 0;
69
+ while (true) {
70
+ const { done, value } = await reader.read();
71
+ if (done) break;
72
+ size += value.byteLength;
73
+ if (size > limit) {
74
+ await reader.cancel();
75
+ throw new Error('Downloaded release asset exceeds the allowed size.');
76
+ }
77
+ chunks.push(Buffer.from(value));
78
+ }
79
+ return Buffer.concat(chunks, size);
80
+ }
81
+
82
+ async function installBinary() {
83
+ // Explicit override is intended for local builds and pack/install smoke tests.
84
+ if (process.env.WROSECODE_BINARY) return;
85
+
86
+ const pkg = require('../package.json');
87
+ const base = releaseBase(pkg);
88
+ const name = assetName();
89
+ const assetUrl = `${base}/${name}`;
90
+
91
+ const binary = await readLimited(await fetchHttps(assetUrl), MAX_BINARY_BYTES);
92
+ if (binary.length === 0) throw new Error(`Release asset is empty: ${name}`);
93
+
94
+ const checksumBytes = await readLimited(await fetchHttps(`${assetUrl}.sha256`), 1024);
95
+ const checksumText = checksumBytes.toString('utf8').trim();
96
+ const checksumMatch = /^([a-fA-F0-9]{64})(?:\s+\*?([^\s]+))?$/.exec(checksumText);
97
+ if (!checksumMatch || (checksumMatch[2] && path.basename(checksumMatch[2]) !== name)) {
98
+ throw new Error(`Invalid SHA-256 sidecar for ${name}.`);
99
+ }
100
+ const expected = checksumMatch[1].toLowerCase();
101
+ const actual = crypto.createHash('sha256').update(binary).digest('hex');
102
+ if (actual !== expected) throw new Error(`SHA-256 verification failed for ${name}.`);
103
+
104
+ const binDir = path.join(__dirname, 'bin');
105
+ const destination = path.join(binDir, process.platform === 'win32' ? 'wrosecode.exe' : 'wrosecode');
106
+ try {
107
+ await writeBinary(destination, binary);
108
+ } catch (error) {
109
+ // Global installs may be root-owned while npm lifecycle scripts are
110
+ // disabled. Keep the executable in the user's cache in that case.
111
+ if (!['EACCES', 'EPERM', 'EROFS'].includes(error.code)) throw error;
112
+ await writeBinary(userCacheBinaryPath(pkg.version), binary);
113
+ }
114
+ }
115
+
116
+ async function writeBinary(destination, binary) {
117
+ const destinationDir = path.dirname(destination);
118
+ const temporary = `${destination}.tmp-${process.pid}`;
119
+ await fs.mkdir(destinationDir, { recursive: true, mode: 0o700 });
120
+ try {
121
+ await fs.writeFile(temporary, binary, { mode: 0o755, flag: 'wx' });
122
+ if (process.platform !== 'win32') await fs.chmod(temporary, 0o755);
123
+ try {
124
+ await fs.rename(temporary, destination);
125
+ } catch (error) {
126
+ if (process.platform !== 'win32' || !['EEXIST', 'EPERM', 'ENOTEMPTY'].includes(error.code)) throw error;
127
+ await fs.rm(destination, { force: true });
128
+ await fs.rename(temporary, destination);
129
+ }
130
+ } finally {
131
+ await fs.rm(temporary, { force: true });
132
+ }
133
+ }
134
+
135
+ if (require.main === module) {
136
+ installBinary().catch((error) => {
137
+ console.error(`wrosecode: native binary installation failed: ${error.message}`);
138
+ process.exitCode = 1;
139
+ });
140
+ }
141
+
142
+ module.exports = { assetName, releaseBase, userCacheBinaryPath };
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { spawn, spawnSync } = require('node:child_process');
5
+ const fs = require('node:fs');
6
+ const os = require('node:os');
7
+ const path = require('node:path');
8
+
9
+ const pkg = require('../package.json');
10
+ const { userCacheBinaryPath } = require('./install.js');
11
+ const packagedBinary = path.join(__dirname, 'bin', process.platform === 'win32' ? 'wrosecode.exe' : 'wrosecode');
12
+ const cachedBinary = userCacheBinaryPath(pkg.version);
13
+ let binary = process.env.WROSECODE_BINARY || [packagedBinary, cachedBinary].find((candidate) => fs.existsSync(candidate)) || null;
14
+
15
+ if (!binary) {
16
+ // npm can be configured to skip lifecycle scripts. Install lazily on first run
17
+ // in that case, but fail instead of launching without a native executable.
18
+ const installer = spawnSync(process.execPath, [path.join(__dirname, 'install.js')], { stdio: 'inherit' });
19
+ if (installer.error) {
20
+ console.error(`wrosecode: could not run native installer: ${installer.error.message}`);
21
+ process.exit(1);
22
+ }
23
+ if (installer.status !== 0) process.exit(installer.status ?? 1);
24
+ binary = [packagedBinary, cachedBinary].find((candidate) => fs.existsSync(candidate)) || null;
25
+ }
26
+
27
+ if (!binary) {
28
+ console.error('wrosecode: native executable is missing after installation. Reinstall the package or set WROSECODE_BINARY to an executable path.');
29
+ process.exit(1);
30
+ }
31
+
32
+ const child = spawn(binary, process.argv.slice(2), {
33
+ stdio: 'inherit',
34
+ windowsHide: true
35
+ });
36
+
37
+ let signalForwarded = false;
38
+ const signalsToForward = process.stdin.isTTY && process.stdout.isTTY ? ['SIGTERM'] : ['SIGINT', 'SIGTERM'];
39
+ for (const signal of signalsToForward) {
40
+ process.on(signal, () => {
41
+ if (signalForwarded || child.exitCode !== null || child.signalCode !== null || child.pid === undefined) return;
42
+ signalForwarded = true;
43
+ try {
44
+ child.kill(signal);
45
+ } catch (error) {
46
+ if (error.code !== 'ESRCH') {
47
+ console.error(`wrosecode: could not forward ${signal} to native process: ${error.message}`);
48
+ }
49
+ }
50
+ });
51
+ }
52
+
53
+ let spawnFailed = false;
54
+ child.once('error', (error) => {
55
+ spawnFailed = true;
56
+ console.error(`wrosecode: could not start native executable: ${error.message}`);
57
+ process.exitCode = 1;
58
+ });
59
+
60
+ child.once('close', (code, signal) => {
61
+ if (spawnFailed) return;
62
+ if (code !== null) {
63
+ process.exitCode = code;
64
+ } else if (signal) {
65
+ process.exitCode = 128 + (os.constants.signals[signal] || 1);
66
+ } else if (process.exitCode === undefined) {
67
+ process.exitCode = 1;
68
+ }
69
+ });
package/package.json CHANGED
@@ -1,6 +1,41 @@
1
1
  {
2
2
  "name": "wrosecode",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.1",
4
+ "description": "A terminal coding agent written in Rust",
5
+ "license": "MIT",
6
+ "keywords": [
7
+ "cli",
8
+ "coding-agent",
9
+ "developer-tools",
10
+ "terminal",
11
+ "rust"
12
+ ],
13
+ "engines": {
14
+ "node": ">=18"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/whiterose717/WROSECODE-CLI.git"
19
+ },
20
+ "homepage": "https://github.com/whiterose717/WROSECODE-CLI#readme",
21
+ "bugs": {
22
+ "url": "https://github.com/whiterose717/WROSECODE-CLI/issues"
23
+ },
24
+ "bin": {
25
+ "wrosecode": "npm/wrosecode.js"
26
+ },
27
+ "files": [
28
+ "npm/wrosecode.js",
29
+ "npm/install.js",
30
+ "npm/check-publish.js",
31
+ "LICENSE",
32
+ "README.md"
33
+ ],
34
+ "scripts": {
35
+ "build": "cargo build --release --locked",
36
+ "check": "node --check npm/wrosecode.js && node --check npm/install.js && node --check npm/check-publish.js",
37
+ "postinstall": "node npm/install.js",
38
+ "prepack": "npm run check",
39
+ "prepublishOnly": "npm run check && node npm/check-publish.js"
40
+ }
41
+ }