merakcode 0.0.0-stage → 0.1.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/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tong Tong
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.
22
+
23
+ ---
24
+
25
+ Parts of this software are derived from other open-source projects, most notably
26
+ opencode (https://github.com/anomalyco/opencode), Copyright (c) 2025 opencode, MIT License.
27
+ See THIRD_PARTY_NOTICES.md for their copyright notices and licenses.
package/README.md CHANGED
@@ -1,3 +1,323 @@
1
- # Temporary Holding Version
1
+ <p align="center">
2
+ <img src="apps/desktop/renderer/public/logo.svg" width="72" alt="MerakCode" />
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">MerakCode</h1>
6
+
7
+ <p align="center">Aiming to be the best AI coding tool to work with</p>
8
+
9
+ <p align="center">
10
+ <a href="https://github.com/TongTong313/merakcode/actions/workflows/ci.yml"><img src="https://github.com/TongTong313/merakcode/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
11
+ <a href="https://github.com/TongTong313/merakcode/releases"><img src="https://img.shields.io/github/v/release/TongTong313/merakcode?include_prereleases" alt="Release" /></a>
12
+ <a href="https://www.npmjs.com/package/merakcode"><img src="https://img.shields.io/npm/v/merakcode" alt="npm" /></a>
13
+ <a href="LICENSE"><img src="https://img.shields.io/github/license/TongTong313/merakcode" alt="License" /></a>
14
+ </p>
15
+
16
+ <p align="center"><a href="README.md">简体中文</a> · English</p>
17
+
18
+ ---
19
+
20
+ MerakCode is an open-source AI coding tool. Beyond strong coding skills, it can help with anything you need AI for. AI now writes far faster than people can read, so MerakCode puts a lot of care into how people and the agent work together: a better way to review what the agent produces and a smoother experience overall, so that its output is what you expect.
21
+
22
+ We open-sourced this project to make up for a regret we have carried, and in the hope that the community can keep it going. The name comes from Merak, the star in the Big Dipper that, together with Dubhe, points to Polaris. We hope MerakCode does the same and points each of your ideas in the right direction.
23
+
24
+ ## What it does
25
+
26
+ - **AI coding**: strong project-level coding across many languages, frameworks, paradigms and styles. Honestly, this part is no different from other AI coding products. You be the judge, and if you like it, a Star is the best way to support us.
27
+ - **Collaboration across products**: MerakCode is designed around people and the agent working together. It has a review interface built specifically for checking what the agent produces (desktop app only) and a complete permission system for what the agent may do. It can also work alongside other AI coding products that ship a CLI, so the collaboration reaches across products.
28
+ - **Model setup**: connect all kinds of model providers (only 8 for now, more to come) as well as local models. MerakCode can also use models through API relay services.
29
+ - **Secure and reliable**: commands the agent runs go into our own OS sandbox. They cannot read your key folders, cannot write outside the workspace, and need your approval to reach unfamiliar websites. This is a small product built by a few people, with no server side (no time to build one...). We don't collect, and couldn't collect, any usage data, so there is nothing of yours to leak.
30
+ - **Extensible**: MCP, skills, plugins, custom agents and slash commands.
31
+ - **Beyond coding**: AI coding is one of the hardest kinds of task there is, so using MerakCode for other things works just fine.
32
+ - **Build your own**: MerakCode ships an agent SDK, and every MerakCode product is built on it. You can build your own AI coding tool on the same engine.
33
+
34
+ ## How to install
35
+
36
+ ### Desktop app
37
+
38
+ Download from the [Releases](https://github.com/TongTong313/merakcode/releases) page:
39
+
40
+ | System | File |
41
+ | ------- | --------------------------------------------------------------------------------- |
42
+ | Windows | `MerakCode-<version>-windows-x64.exe` |
43
+ | macOS | `MerakCode-<version>-darwin-arm64.dmg` (Apple silicon), `-darwin-x64.dmg` (Intel) |
44
+ | Linux | `MerakCode-<version>-linux-x64.AppImage` or `.deb` |
45
+
46
+ The desktop app ships with its own engine; you do not need the command-line version as well.
47
+
48
+ The installers are not code-signed yet, so the system stops them the first time:
49
+
50
+ - **Windows**: when you see "Windows protected your PC", click "More info", then "Run anyway".
51
+ - **macOS**: if the app "cannot be opened", go to System Settings → Privacy & Security and click "Open Anyway" near the bottom. Unsigned macOS builds cannot update themselves; the app tells you when a new version is out and opens the download page.
52
+
53
+ ### Command line
54
+
55
+ The command-line version has no UI. It is for one-off tasks in a terminal, scripts, and editors (through ACP). It shares its config and keys with the desktop app.
56
+
57
+ macOS / Linux:
58
+
59
+ ```sh
60
+ curl -fsSL https://github.com/TongTong313/merakcode/releases/latest/download/install.sh | sh
61
+ ```
62
+
63
+ Windows (PowerShell):
64
+
65
+ ```powershell
66
+ irm https://github.com/TongTong313/merakcode/releases/latest/download/install.ps1 | iex
67
+ ```
68
+
69
+ Or with npm (the package brings its own runtime; any Node.js 18 or newer can install it):
70
+
71
+ ```sh
72
+ npm install -g merakcode
73
+ ```
74
+
75
+ The command is `merak`. Upgrade later with `merak upgrade` (or `merak update`).
76
+
77
+ To check a download yourself, put the release's `SHA256SUMS` in the same folder as the file and run:
78
+
79
+ ```sh
80
+ sha256sum -c SHA256SUMS --ignore-missing # Linux
81
+ shasum -a 256 -c SHA256SUMS --ignore-missing # macOS
82
+ ```
83
+
84
+ ```powershell
85
+ # Windows: the output must equal the value on this file's line in SHA256SUMS
86
+ (Get-FileHash .\merakcode-<version>-windows-x64.zip).Hash.ToLower()
87
+ ```
88
+
89
+ ### Uninstall
90
+
91
+ On Windows, if you set up the sandbox, first click "Reset" under Settings → Permissions & security in the desktop app (or run `merak sandbox reset`). It removes the sandbox account and firewall rule and takes back the folder permissions it was given.
92
+
93
+ - Desktop app: uninstall it from the system's app list.
94
+ - Installed with the script: on macOS / Linux delete `~/.local/bin/merak`; on Windows remove `~\.merakcode\bin` from your user PATH.
95
+ - Installed with npm: `npm uninstall -g merakcode`.
96
+ - Config, sessions, logs and caches all live in one folder, `~/.merakcode` (on Windows `~` is `C:\Users\<you>`; the `MERAKCODE_HOME` environment variable moves it). Delete it if you no longer need it.
97
+
98
+ ## Quick start
99
+
100
+ Open the desktop app and click "Open folder" to pick your project.
101
+
102
+ The first time, connect a model provider: on the onboarding screen, pick a provider and enter its API key (change it later under Settings → Models & providers). The built-in catalog is OpenAI, Anthropic, Google, Alibaba Cloud Model Studio, Zhipu AI, DeepSeek, Moonshot AI and OpenRouter. Any other service is an OpenAI-compatible provider in your config, with its URL, model ids and API key.
103
+
104
+ Then just say what you want:
105
+
106
+ ```text
107
+ Add unit tests for formatDate in utils/date.ts
108
+ ```
109
+
110
+ Handy actions (`⌘` on macOS, `Ctrl` on Windows and Linux):
111
+
112
+ | Action | What it does |
113
+ | --------------------- | ----------------------------------------------------------------------------- |
114
+ | `⌘/Ctrl+K` | Command palette: search conversation titles, conversation content or commands |
115
+ | `⌘/Ctrl+N` | New conversation |
116
+ | `⌘/Ctrl+,` | Open settings |
117
+ | `⌘/Ctrl+J` | Open or close the terminal |
118
+ | `⌘/Ctrl+B` | Show or hide the side panel |
119
+ | `Shift+Tab` | Switch permission mode |
120
+ | Type `/` in the input | Pick a slash command, such as `/compact` to shrink a long conversation |
121
+ | Type `@` in the input | Reference a file in the project |
122
+
123
+ ## Commands
124
+
125
+ The command-line version runs in a terminal. If you have not connected a model provider in the desktop app, run `merak provider login` first. Then run a task in your project folder and get the result printed:
126
+
127
+ ```sh
128
+ cd your-project
129
+ merak run "Explain how src/index.ts starts up"
130
+ ```
131
+
132
+ | Command | What it does |
133
+ | ----------------------------- | --------------------------------------------------------------------------------- |
134
+ | `merak run "<task>"` | Run one task and print the result |
135
+ | `merak provider login` | Connect a model provider; `list` shows the connected ones, `logout` removes one |
136
+ | `merak serve --port 4096` | Start only the engine, for the SDK or other programs |
137
+ | `merak upgrade` (or `update`) | Upgrade. `--check` only looks for a new version, `--yes` skips the question |
138
+ | `merak models` | List the models you can use |
139
+ | `merak mcp list` | Show MCP server status |
140
+ | `merak sandbox status` | Is the sandbox on? `setup` turns it on, `reset` removes it |
141
+ | `merak doctor` | Check the install, config, models and sandbox, and say what is wrong |
142
+ | `merak logs` | Where the logs are and recent runs; `--tail` follows the newest log |
143
+ | `merak bug-report` | Zip the checks, config and logs for an issue; keys and conversations are left out |
144
+ | `merak acp` | Run as an [ACP](https://agentclientprotocol.com) agent for editors such as Zed |
145
+
146
+ Add `--help` to any command for the full details.
147
+
148
+ ### In your editor (ACP)
149
+
150
+ Editors that speak [ACP](https://agentclientprotocol.com) can use MerakCode as their agent. For Zed, add this to `~/.config/zed/settings.json`:
151
+
152
+ ```json
153
+ {
154
+ "agent_servers": {
155
+ "MerakCode": { "command": "merak", "args": ["acp"] }
156
+ }
157
+ }
158
+ ```
159
+
160
+ ## Permissions and the sandbox
161
+
162
+ MerakCode edits files and runs commands on your computer, so every action goes through the permission mode first: do it, ask you, or refuse.
163
+
164
+ | Mode | Good for | What happens |
165
+ | ------------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
166
+ | Read-only | Designs and plans | Only reads files and runs read-only commands (such as `git status` or `ls`). No edits, no other commands |
167
+ | Ask (default) | Everyday work | Reads files and edits inside the workspace right away; asks before running commands, editing outside the workspace, reading sensitive files or going online |
168
+ | Auto | Large projects, when you trust the AI | Does most things right away; still asks before risky commands (such as `git push` or `sudo`), edits outside the workspace, sensitive files and unknown websites |
169
+
170
+ Switch modes next to the input in the desktop app, or press `Shift+Tab`. When it asks, you can allow once, allow for this session, always allow (saved to the project config) or deny. By default, commands such as `rm -rf /` or formatting a disk never run, in any mode.
171
+
172
+ Commands the agent runs also go into an **OS sandbox**: they can only write the workspace, temp folders and package manager caches; they cannot read key folders such as `~/.ssh` or `~/.aws`; they cannot change `.git/hooks` or `.git/config`; and network traffic goes through a local proxy that asks you about sites it has not seen. The sandbox is our own code on top of what each OS provides:
173
+
174
+ | System | Built on | What you need to do |
175
+ | ------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
176
+ | Windows | A separate low-rights account, NTFS permissions, the firewall | Click "Set up" under Settings → Permissions & security in the desktop app (or run `merak sandbox setup` once) and approve one administrator prompt |
177
+ | Linux | Landlock (kernel 5.13 or newer) | Nothing. Network rules need kernel 6.7 or newer |
178
+ | macOS | The built-in Seatbelt (sandbox-exec) | Nothing |
179
+
180
+ While the sandbox is not ready (for example before setup on Windows), commands that may change things ask first, even in auto mode. For what the sandbox does and does not protect against, see [SECURITY.md](SECURITY.md).
181
+
182
+ ## Configuration
183
+
184
+ | Location | Purpose |
185
+ | ------------------------------------------------------ | -------------------------------------------------------------- |
186
+ | `~/.merakcode/merakcode.json` | Global config (model, language, permission rules...) |
187
+ | `<project>/.merakcode/merakcode.json` | Project config, overrides the global one |
188
+ | `<project>/AGENTS.md` | Notes about your project for MerakCode (`CLAUDE.md` works too) |
189
+ | `<project>/.merakcode/agents/`, `skills/`, `commands/` | Custom agents, skills and slash commands |
190
+
191
+ Config files can be plain JSON or JSONC with comments. Add `"$schema"` at the top and your editor will autocomplete and check it:
192
+
193
+ ```jsonc
194
+ {
195
+ "$schema": "https://raw.githubusercontent.com/TongTong313/merakcode/main/schema/config.json",
196
+ "model": "anthropic/claude-sonnet-4-5",
197
+ "locale": "en-US",
198
+ "permission": {
199
+ "bash": { "git status": "allow", "rm -rf *": "deny" },
200
+ },
201
+ "sandbox": { "mode": "preferred" },
202
+ }
203
+ ```
204
+
205
+ To switch to English: in the desktop app, use Settings → General → Language; for the command line, set `"locale": "en-US"` in the config or the environment variable `MERAKCODE_LOCALE=en-US`.
206
+
207
+ ## SDK
208
+
209
+ To use MerakCode from your own program, use the TypeScript SDK:
210
+
211
+ ```sh
212
+ npm install @merakcode/sdk
213
+ ```
214
+
215
+ ```ts
216
+ import { createMerakCode } from "@merakcode/sdk"
217
+
218
+ const merak = await createMerakCode({ cwd: process.cwd() })
219
+ const session = await merak.session()
220
+ for await (const event of session.run("What does this project do?")) {
221
+ if (event.type === "text") process.stdout.write(event.delta)
222
+ }
223
+ await merak.close()
224
+ ```
225
+
226
+ See the [SDK guide](docs/sdk/README.en.md) for everything else.
227
+
228
+ ## Develop from source
229
+
230
+ You need Node.js 26.12 or newer and pnpm 12.
231
+
232
+ ```sh
233
+ git clone https://github.com/TongTong313/merakcode.git
234
+ cd merakcode
235
+ pnpm install
236
+ pnpm hooks:install # check formatting before each commit
237
+ ```
238
+
239
+ ### Run from source
240
+
241
+ | To | Run |
242
+ | -------------------------- | -------------------------------------------------------------------------------- |
243
+ | Work on the desktop app | `pnpm --dir apps/desktop/main dev` |
244
+ | Run a command-line command | `pnpm dev run "Explain this project"` |
245
+ | Start only the engine | `pnpm dev serve --port 4096` |
246
+ | Debug the engine | `node --inspect --import ./script/node/register.mjs apps/cli/src/index.ts serve` |
247
+ | Print detailed logs | `pnpm dev serve --print-logs --log-level DEBUG` |
248
+
249
+ **Note**: desktop development reloads the UI as you save and restarts the main process and the engine when their code changes, which makes debugging much easier.
250
+
251
+ `pnpm dev` runs the source directly; there is nothing to build first. Change the code and run it again.
252
+
253
+ ### Tests and checks
254
+
255
+ ```sh
256
+ pnpm check # formatting, types, dependency boundaries, generated files... run before you commit
257
+ cd packages/engine && pnpm test # each package runs its own tests
258
+ cd apps/cli && pnpm test test/cli/doctor-command.test.ts # a single file
259
+ ```
260
+
261
+ ### Packaging
262
+
263
+ ```sh
264
+ pnpm --dir apps/cli build --single # CLI release bundle for this machine, in apps/cli/dist/
265
+ pnpm --dir apps/desktop/main package # desktop installer for this machine, in apps/desktop/main/release/
266
+ ```
267
+
268
+ The CLI ends up at `apps/cli/dist/merakcode-<version>-<platform>/bin/merak` (`merak.cmd` on Windows). Packaging downloads Node and Electron; if that is slow, set `MERAKCODE_NODE_MIRROR` and `ELECTRON_MIRROR` to a closer mirror.
269
+
270
+ ### Generated files
271
+
272
+ | If you changed | Run |
273
+ | ------------------ | ------------------------------------------------------- |
274
+ | A server route | `pnpm generate:sdk`, then `pnpm generate:sdk-reference` |
275
+ | A config option | `pnpm generate:schema` |
276
+ | An error code | `pnpm generate:errors` |
277
+ | The SDK public API | `pnpm check:api --write` |
278
+
279
+ ### Point the SDK at the engine source
280
+
281
+ ```ts
282
+ const merak = await createMerakCode({
283
+ executablePath: [process.execPath, "--import", "<repo>/script/node/register.mjs", "<repo>/apps/cli/src/index.ts"],
284
+ })
285
+ ```
286
+
287
+ ### Layout
288
+
289
+ ```text
290
+ apps/cli the merak command; merak serve is the engine, and the desktop app ships the same one
291
+ apps/desktop/main desktop app main process (Electron)
292
+ apps/desktop/renderer desktop app UI (SolidJS)
293
+ packages/engine the engine: sessions, models, tools, permissions, HTTP server
294
+ packages/sandbox the OS sandbox (Windows / Linux / macOS)
295
+ packages/sdk/js TypeScript SDK
296
+ packages/util, log shared helpers and logging
297
+ packages/client-core approval options for the desktop app
298
+ ```
299
+
300
+ Neither the desktop app nor the command-line commands import engine code. They start a `merak serve` process through the SDK and talk to it over HTTP and an event stream. `pnpm check` enforces this. See [CONTRIBUTING.md](CONTRIBUTING.md) for the rest of the conventions.
301
+
302
+ ## When something goes wrong
303
+
304
+ 1. If the error has a code (such as `[MRK-2002]`), look it up in the [error code list](docs/errors.md).
305
+ 2. Run `merak doctor`; it tells you which part is broken.
306
+ 3. Still stuck? Run `merak bug-report` and attach the zip to an [issue](https://github.com/TongTong313/merakcode/issues/new/choose).
307
+ 4. To read the logs yourself: `merak logs` shows where they are, `merak logs --tail` follows the newest one.
308
+
309
+ ## Security
310
+
311
+ Please do not report security problems in public issues. See [SECURITY.md](SECURITY.md) for how to report them privately.
312
+
313
+ ## Contributing
314
+
315
+ Issues and pull requests are welcome; let's make MerakCode better together. See [CONTRIBUTING.md](CONTRIBUTING.md) for the guidelines.
316
+
317
+ ## License
318
+
319
+ [MIT](LICENSE)
320
+
321
+ ## Thanks
322
+
323
+ Parts of this project are based on code from [opencode](https://github.com/anomalyco/opencode), and we thank them for it. Their license notices are in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
@@ -0,0 +1,67 @@
1
+ # Third-party notices
2
+
3
+ MerakCode contains code taken from or based on the open-source projects below. Their licenses ask us to keep
4
+ their copyright notices, so they are reproduced here in full.
5
+
6
+ Release packages also contain `THIRD_PARTY_LICENSES.txt`, which lists every npm package bundled into that
7
+ release together with its license text.
8
+
9
+ ## opencode
10
+
11
+ - Project: https://github.com/anomalyco/opencode
12
+ - Used in: the engine (sessions, tools, providers, server)
13
+ - License: MIT
14
+
15
+ ```
16
+ MIT License
17
+
18
+ Copyright (c) 2025 opencode
19
+
20
+ Permission is hereby granted, free of charge, to any person obtaining a copy
21
+ of this software and associated documentation files (the "Software"), to deal
22
+ in the Software without restriction, including without limitation the rights
23
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24
+ copies of the Software, and to permit persons to whom the Software is
25
+ furnished to do so, subject to the following conditions:
26
+
27
+ The above copyright notice and this permission notice shall be included in all
28
+ copies or substantial portions of the Software.
29
+
30
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36
+ SOFTWARE.
37
+ ```
38
+
39
+ ## pi-mono
40
+
41
+ - Project: https://github.com/badlogic/pi-mono
42
+ - Used in: the patterns that detect "context window exceeded" errors in `packages/engine/src/provider/error.ts`
43
+ - License: MIT
44
+
45
+ ```
46
+ MIT License
47
+
48
+ Copyright (c) 2025 Mario Zechner
49
+
50
+ Permission is hereby granted, free of charge, to any person obtaining a copy
51
+ of this software and associated documentation files (the "Software"), to deal
52
+ in the Software without restriction, including without limitation the rights
53
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
54
+ copies of the Software, and to permit persons to whom the Software is
55
+ furnished to do so, subject to the following conditions:
56
+
57
+ The above copyright notice and this permission notice shall be included in all
58
+ copies or substantial portions of the Software.
59
+
60
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
61
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
62
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
63
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
64
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
65
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
66
+ SOFTWARE.
67
+ ```
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Command name and npm package names. Lives in bin/ because the npm launcher requires it at startup.
3
+ */
4
+
5
+ const commandName = "merak"
6
+
7
+ /** npm package id: the main package and the platform package prefix */
8
+ const packageName = "merakcode"
9
+
10
+ function binMap() {
11
+ return { [commandName]: `./bin/${commandName}` }
12
+ }
13
+
14
+ /** Platform package: merakcode-<os>-<arch>. Windows is spelled "windows"; npm reserves "win32" for its os field. */
15
+ function platformPackage(platform, arch) {
16
+ return `${packageName}-${platform === "win32" ? "windows" : platform}-${arch}`
17
+ }
18
+
19
+ module.exports = {
20
+ commandName,
21
+ packageName,
22
+ binMap,
23
+ platformPackage,
24
+ }
@@ -0,0 +1,98 @@
1
+ // Deliberately standalone: copied beside the npm launcher, and bundled into desktop.
2
+ const fs = require("node:fs")
3
+ const path = require("node:path")
4
+ const os = require("node:os")
5
+
6
+ function safe(value) {
7
+ return (
8
+ String(value)
9
+ .replace(/[^a-zA-Z0-9_-]/g, "-")
10
+ .slice(0, 80) || "unknown"
11
+ )
12
+ }
13
+
14
+ function root() {
15
+ if (process.env.MERAKCODE_LOG_ROOT) return process.env.MERAKCODE_LOG_ROOT.replaceAll("\0", "")
16
+ return path.join(process.env.MERAKCODE_HOME?.replaceAll("\0", "") || path.join(os.homedir(), ".merakcode"), "logs")
17
+ }
18
+
19
+ // Only extracted, bounded identifiers reach disk. Never persist arbitrary stderr, argv, URLs or report payloads.
20
+ function nativeEvidence(text) {
21
+ // Node/V8 fatal errors: heap exhaustion, failed V8 checks, and the native stack trace printed with them
22
+ const runtime = /FATAL ERROR:|# Fatal error in|Native stack trace/.test(text)
23
+ const native = /segmentation fault|access violation/i.test(text)
24
+ return {
25
+ runtime_crash_signature: runtime,
26
+ native_fault_signature: native,
27
+ runtime_version: text.match(/Node\.js v(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)/)?.[1],
28
+ fault_address: text.match(/(?:fault at address|access violation at)\s+(0x[0-9a-f]+)/i)?.[1],
29
+ modules_observed:
30
+ runtime || native ? [...new Set(text.match(/[A-Za-z0-9_.-]{1,120}\.(?:dll|node)\b/gi) || [])].slice(0, 30) : [],
31
+ }
32
+ }
33
+
34
+ class CrashEvidence {
35
+ constructor(options) {
36
+ const dir = path.join(options.root || root(), ".state", "crash-evidence")
37
+ fs.mkdirSync(dir, { recursive: true, mode: 0o700 })
38
+ this.file = path.join(dir, `${safe(options.component)}-${safe(options.runId)}.json`)
39
+ this.tail = ""
40
+ this.closed = false
41
+ this.data = {
42
+ schema: "merakcode.crash-evidence.v3",
43
+ owner_pid: process.pid,
44
+ component: safe(options.component),
45
+ run_id: safe(options.runId),
46
+ started_at: new Date().toISOString(),
47
+ evidence: nativeEvidence(""),
48
+ }
49
+ this.save()
50
+ }
51
+
52
+ save() {
53
+ fs.writeFileSync(this.file, JSON.stringify(this.data), { mode: 0o600 })
54
+ }
55
+
56
+ write(chunk) {
57
+ if (this.closed) return 0
58
+ try {
59
+ // Process bounded windows even if a caller hands us a very large chunk.
60
+ const value = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8")
61
+ for (let offset = 0; offset < value.length; offset += 8192) {
62
+ this.tail = (this.tail + value.slice(offset, offset + 8192)).slice(-32768)
63
+ const next = nativeEvidence(this.tail)
64
+ const previous = this.data.evidence
65
+ this.data.evidence = {
66
+ ...previous,
67
+ runtime_crash_signature: previous.runtime_crash_signature || next.runtime_crash_signature,
68
+ native_fault_signature: previous.native_fault_signature || next.native_fault_signature,
69
+ runtime_version: next.runtime_version || previous.runtime_version,
70
+ fault_address: next.fault_address || previous.fault_address,
71
+ modules_observed: [...new Set([...previous.modules_observed, ...next.modules_observed])].slice(0, 30),
72
+ }
73
+ }
74
+ if (this.data.evidence.runtime_crash_signature || this.data.evidence.native_fault_signature) this.save()
75
+ return value.length
76
+ } catch {
77
+ return 0
78
+ }
79
+ }
80
+
81
+ close(options = {}) {
82
+ if (this.closed) return
83
+ this.closed = true
84
+ this.tail = ""
85
+ try {
86
+ if (!options.keep) {
87
+ fs.rmSync(this.file, { force: true })
88
+ return
89
+ }
90
+ this.data.owner_pid = 0
91
+ this.data.exit_code = options.code ?? null
92
+ this.data.signal = options.signal ?? null
93
+ this.save()
94
+ } catch {}
95
+ }
96
+ }
97
+
98
+ module.exports = { CrashEvidence, nativeEvidence }
package/bin/merak ADDED
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env node
2
+
3
+ // npm entry point. npm installs only the platform package for this machine (merakcode-<os>-<arch>, see
4
+ // optionalDependencies); find it and run its lib/index.js with its bundled Node.
5
+ // MERAKCODE_BIN_PATH overrides the executable (for debugging).
6
+
7
+ const childProcess = require("child_process")
8
+ const fs = require("fs")
9
+ const path = require("path")
10
+ const os = require("os")
11
+ const crypto = require("crypto")
12
+ const { platformPackage } = require("./cli-name.cjs")
13
+
14
+ function logRoot(env) {
15
+ if (env.MERAKCODE_LOG_ROOT) return env.MERAKCODE_LOG_ROOT.replaceAll("\0", "")
16
+ return path.join(env.MERAKCODE_HOME?.replaceAll("\0", "") || path.join(os.homedir(), ".merakcode"), "logs")
17
+ }
18
+
19
+ function runDirect(command, args, env) {
20
+ const result = childProcess.spawnSync(command, args, { stdio: "inherit", env })
21
+ if (result.error) {
22
+ console.error(result.error.message)
23
+ process.exit(1)
24
+ }
25
+ process.exit(typeof result.status === "number" ? result.status : 0)
26
+ }
27
+
28
+ function run(command, args, env) {
29
+ if (process.platform !== "win32") return runDirect(command, args, env)
30
+ // Windows: keep stderr as crash evidence when the process exits abnormally
31
+ const runId = crypto.randomUUID()
32
+ const childEnv = { ...env, MERAKCODE_RUN_ID: runId }
33
+ const evidence = (() => {
34
+ try {
35
+ const helper = fs.existsSync(path.join(__dirname, "crash-evidence.cjs"))
36
+ ? path.join(__dirname, "crash-evidence.cjs")
37
+ : path.join(__dirname, "../node_modules/@merakcode/log/src/crash-evidence.cjs")
38
+ const { CrashEvidence } = require(helper)
39
+ return new CrashEvidence({ root: logRoot(childEnv), component: "cli", runId })
40
+ } catch {
41
+ return undefined
42
+ }
43
+ })()
44
+ // Evidence failure never prevents launching the product.
45
+ let controlled = false
46
+ const child = childProcess.spawn(command, args, {
47
+ stdio: ["inherit", "inherit", "pipe"],
48
+ env: childEnv,
49
+ })
50
+ child.stderr.on("data", (chunk) => {
51
+ process.stderr.write(chunk)
52
+ evidence?.write(chunk)
53
+ })
54
+ child.on("error", (error) => {
55
+ evidence?.close()
56
+ console.error(error.message)
57
+ process.exit(1)
58
+ })
59
+ // close, unlike exit, waits for stderr to drain.
60
+ child.on("close", (code, signal) => {
61
+ evidence?.close({ keep: !controlled && (code !== 0 || !!signal), code, signal })
62
+ process.exit(typeof code === "number" ? code : signal ? 1 : 0)
63
+ })
64
+ for (const signal of ["SIGINT", "SIGTERM"]) {
65
+ process.once(signal, () => {
66
+ controlled = true
67
+ child.kill(signal)
68
+ })
69
+ }
70
+ }
71
+
72
+ /** Walks up from this script looking for node_modules/<platform package> */
73
+ function findPlatformPackage(name) {
74
+ for (let dir = path.dirname(fs.realpathSync(__filename)); ; dir = path.dirname(dir)) {
75
+ const candidate = path.join(dir, "node_modules", name)
76
+ if (fs.existsSync(path.join(candidate, "lib", "index.js"))) return candidate
77
+ if (path.dirname(dir) === dir) return
78
+ }
79
+ }
80
+
81
+ const env = { ...process.env }
82
+ const args = process.argv.slice(2)
83
+
84
+ if (process.env.MERAKCODE_BIN_PATH) {
85
+ run(process.env.MERAKCODE_BIN_PATH, args, env)
86
+ } else {
87
+ const name = platformPackage(process.platform, process.arch)
88
+ const pkg = findPlatformPackage(name)
89
+ if (!pkg) {
90
+ console.error(
91
+ `The package for this platform (${name}) is not installed. npm may have skipped optional dependencies; ` +
92
+ `reinstall with: npm install -g merakcode\n` +
93
+ `You can also use the install script or download a release from GitHub.`,
94
+ )
95
+ process.exit(1)
96
+ }
97
+ const node = path.join(pkg, "node", process.platform === "win32" ? "node.exe" : "bin/node")
98
+ // node:ffi (used by the engine) prints an ExperimentalWarning on every start
99
+ run(node, ["--disable-warning=ExperimentalWarning", path.join(pkg, "lib", "index.js"), ...args], env)
100
+ }
package/package.json CHANGED
@@ -1,6 +1,29 @@
1
1
  {
2
2
  "name": "merakcode",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "MerakCode command line: run tasks, start the engine, ACP for editors",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/TongTong313/merakcode.git",
9
+ "directory": "apps/cli"
10
+ },
11
+ "bin": {
12
+ "merak": "./bin/merak"
13
+ },
14
+ "files": [
15
+ "bin",
16
+ "THIRD_PARTY_NOTICES.md"
17
+ ],
18
+ "engines": {
19
+ "node": ">=18"
20
+ },
21
+ "optionalDependencies": {
22
+ "merakcode-darwin-arm64": "0.1.0",
23
+ "merakcode-darwin-x64": "0.1.0",
24
+ "merakcode-linux-arm64": "0.1.0",
25
+ "merakcode-linux-x64": "0.1.0",
26
+ "merakcode-windows-arm64": "0.1.0",
27
+ "merakcode-windows-x64": "0.1.0"
28
+ }
29
+ }