mini-coder 0.1.0 โ 0.1.2
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/.claude/settings.local.json +43 -30
- package/README.md +38 -157
- package/dist/mc-edit.js +29 -5
- package/dist/mc.js +2758 -3282
- package/docs/mini-coder.1.md +206 -102
- package/lefthook.yml +15 -0
- package/package.json +3 -2
- package/docs/configs.md +0 -118
- package/docs/custom-agents.md +0 -69
- package/docs/custom-commands.md +0 -141
- package/docs/skills.md +0 -83
- package/research.md +0 -38
|
@@ -1,32 +1,45 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"WebSearch",
|
|
5
|
+
"WebFetch(domain:github.com)",
|
|
6
|
+
"WebFetch(domain:dev.to)",
|
|
7
|
+
"WebFetch(domain:mariozechner.at)",
|
|
8
|
+
"WebFetch(domain:lobste.rs)",
|
|
9
|
+
"WebFetch(domain:reading.sh)",
|
|
10
|
+
"WebFetch(domain:daveswift.com)",
|
|
11
|
+
"Bash(grep:*)",
|
|
12
|
+
"Bash(ls:*)",
|
|
13
|
+
"Bash(bun run:*)",
|
|
14
|
+
"Bash(git stash:*)",
|
|
15
|
+
"Bash(gh pr:*)",
|
|
16
|
+
"Bash(git status:*)",
|
|
17
|
+
"Bash(git add:*)",
|
|
18
|
+
"Bash(git commit:*)",
|
|
19
|
+
"Bash(sqlite3:*)",
|
|
20
|
+
"Bash(git branch:*)",
|
|
21
|
+
"Bash(git checkout:*)",
|
|
22
|
+
"Bash(npm info:*)",
|
|
23
|
+
"Bash(npm install:*)",
|
|
24
|
+
"Bash(find:*)",
|
|
25
|
+
"Bash(git log:*)",
|
|
26
|
+
"Bash(npm ls:*)",
|
|
27
|
+
"Bash(gh api:*)",
|
|
28
|
+
"Bash(bun:*)",
|
|
29
|
+
"Bash(npx tsc:*)",
|
|
30
|
+
"WebFetch(domain:docs.anthropic.com)",
|
|
31
|
+
"WebFetch(domain:sdk.vercel.ai)",
|
|
32
|
+
"WebFetch(domain:ai-sdk.dev)",
|
|
33
|
+
"WebFetch(domain:www.npmjs.com)",
|
|
34
|
+
"Bash(curl -sL https://registry.npmjs.org/opencode-anthropic-auth/-/opencode-anthropic-auth-0.0.13.tgz)",
|
|
35
|
+
"Bash(tar xz:*)",
|
|
36
|
+
"Bash(tmux new-session:*)",
|
|
37
|
+
"Bash(tmux capture-pane:*)",
|
|
38
|
+
"Bash(tmux list-sessions:*)",
|
|
39
|
+
"Bash(tmux kill-session:*)",
|
|
40
|
+
"Bash(python3:*)",
|
|
41
|
+
"Bash(echo \"EXIT: $?\")",
|
|
42
|
+
"Bash(xargs cat:*)"
|
|
43
|
+
]
|
|
44
|
+
}
|
|
32
45
|
}
|
package/README.md
CHANGED
|
@@ -6,194 +6,75 @@
|
|
|
6
6
|
|
|
7
7
|
> _Small. Fast. Gets out of your way._
|
|
8
8
|
|
|
9
|
-
[๐ Read the Full Manual](
|
|
9
|
+
[๐ Read the Full Manual](docs/mini-coder.1.md)
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## ๐ค Who Am I?
|
|
16
|
-
|
|
17
|
-
I'm `mc` โ your new terminal companion. I live in your shell, speak to large language models, and help you explore, understand, and modify code at the speed of thought.
|
|
18
|
-
|
|
19
|
-
I was built with a simple philosophy: **dev flow first**. No slow startup. No clunky GUI. No vendor lock-in. Just you, your terminal, and an AI that keeps up.
|
|
11
|
+
A terminal coding agent for developers who want a sharp tool, not a bloated IDE plugin. Shell-first, multi-provider, minimal tool surface. Just you, your terminal, and an AI that keeps up.
|
|
20
12
|
|
|
21
13
|

|
|
22
14
|
|
|
23
15
|
---
|
|
24
16
|
|
|
25
|
-
##
|
|
26
|
-
|
|
27
|
-
My toolkit is lean on purpose โ every tool earns its spot, no passengers:
|
|
28
|
-
|
|
29
|
-
| Tool | What it does |
|
|
30
|
-
| --------------- | -------------------------------------------------------------------------- |
|
|
31
|
-
| ๐ `shell` | Run shell commands, inspect the repo, and use `mc-edit` for targeted edits |
|
|
32
|
-
| ๐ค `subagent` | Spawn a focused mini-me for parallel subtasks |
|
|
33
|
-
| ๐งฐ `listSkills` | List discovered skills without loading full skill bodies |
|
|
34
|
-
| ๐ `readSkill` | Load one `SKILL.md` on demand |
|
|
35
|
-
| ๐ `webSearch` | Search the web when `EXA_API_KEY` is set |
|
|
36
|
-
| ๐ `webContent` | Fetch full page content from URLs when `EXA_API_KEY` is set |
|
|
37
|
-
|
|
38
|
-
mini-coder is intentionally **shell-first**: inspect with shell, edit with `mc-edit`, verify with shell.
|
|
39
|
-
|
|
40
|
-
Need more firepower? I also connect to **MCP servers** over HTTP or stdio โ attached MCP tools show up dynamically whenever the job calls for them.
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## โก Key Features
|
|
45
|
-
|
|
46
|
-
- **Multi-provider** โ set `OPENCODE_API_KEY` for Zen, `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GOOGLE_API_KEY` or `GEMINI_API_KEY`, or just run Ollama locally (`OLLAMA_BASE_URL` optional). I auto-discover whatever's available.
|
|
47
|
-
- **Built-in web search** โ set `EXA_API_KEY` and I expose `webSearch` + `webContent` tools.
|
|
48
|
-
- **Session memory** โ conversations are saved in a local SQLite database. Resume where you left off with `-c` or pick a specific session with `-r <id>`.
|
|
49
|
-
- **Shell integration** โ prefix with `!` to run shell commands inline. Use `@` to reference files in your prompt (with Tab completion).
|
|
50
|
-
- **Slash commands** โ `/model` or `/models` to list/switch models, `/model effort <low|medium|high|xhigh|off>` for reasoning effort, `/reasoning [on|off]` to toggle reasoning display, `/context` to inspect or tune pruning/tool-result caps, `/cache` to configure prompt caching, `/review` for a code review (global custom command, auto-created at `~/.agents/commands/review.md`), `/agent [name]` to set or clear an active primary agent, `/undo` to remove the last conversation turn (it does not revert filesystem changes), `/new` for a clean session, `/mcp list|add|remove` to manage MCP servers, and `/exit` (`/quit`, `/q`) to leave. See all with `/help`.
|
|
51
|
-
|
|
52
|
-
- **Custom commands** โ drop a `.md` file in `.agents/commands/` and it becomes a `/command`. Claude-compatible `.claude/commands/` works too. Supports argument placeholders (`$ARGUMENTS`, `$1`โฆ`$9`) and shell interpolation (`` !`cmd` ``). Global commands live in `~/.agents/commands/` and `~/.claude/commands/`. Custom commands take precedence over built-ins. โ [docs/custom-commands.md](docs/custom-commands.md)
|
|
53
|
-
- **Custom agents** โ drop a `.md` file in `.agents/agents/` or `.claude/agents/` (or `~/.agents/agents/` / `~/.claude/agents/` globally) and activate it with `/agent [name]`. Agent definitions are also exposed to subagent delegation unless `mode: primary`. โ [docs/custom-agents.md](docs/custom-agents.md)
|
|
54
|
-
- **Skills** โ place a `SKILL.md` in `.agents/skills/<name>/` and inject it into any prompt with `@skill-name`. Claude-compatible `.claude/skills/<name>/SKILL.md` works too. Skills are _never_ auto-loaded โ always explicit. โ [docs/skills.md](docs/skills.md)
|
|
55
|
-
- **Beautiful, minimal output** โ compact tool output, formatted trees for file searches, a live status bar with model, git branch, and token counts.
|
|
56
|
-
- **16 ANSI colors only** โ my output inherits _your_ terminal theme. Dark mode, light mode, Solarized, Gruvbox โ I fit right in.
|
|
57
|
-
|
|
58
|
-
---
|
|
59
|
-
|
|
60
|
-
## ๐ง Interesting Things About Me
|
|
61
|
-
|
|
62
|
-
- **I eat my own dog food.** I was built _by_ a mini-coder agent. It's agents all the way down. ๐ข
|
|
63
|
-
- **I'm tiny but mighty.** The whole runtime is [Bun.js](https://bun.com) โ fast startup, native TypeScript, and a built-in SQLite driver.
|
|
64
|
-
- **I respect existing conventions.** Context lives in `AGENTS.md` or `CLAUDE.md`, commands in `.agents/commands/`, agents in `.agents/agents/`, skills in `.agents/skills/` โ I follow the ecosystem instead of inventing new standards.
|
|
65
|
-
- **I spin while I think.** โ โ โ นโ ธโ ผโ ดโ ฆโ งโ โ (It's the little things.)
|
|
66
|
-
- **I can clone myself.** The `subagent` tool lets me spin up parallel instances of myself to tackle independent subtasks simultaneously. Divide and conquer! (Up to 10 levels deep.)
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
## ๐ Config folders
|
|
71
|
-
|
|
72
|
-
I follow the [`.agents` convention](https://github.com/agentsmd/agents) โ the shared standard across AI coding tools โ and I also understand `.claude` layouts for **commands**, **skills**, and **agents**.
|
|
73
|
-
|
|
74
|
-
| Path | What it does |
|
|
75
|
-
| -------------------------------- | ----------------------------------------------------- |
|
|
76
|
-
| `.agents/commands/*.md` | Custom slash commands (`/name`) |
|
|
77
|
-
| `.claude/commands/*.md` | Claude-compatible custom commands |
|
|
78
|
-
| `.agents/agents/*.md` | Custom agents |
|
|
79
|
-
| `.claude/agents/*.md` | Alternate `.claude` path for custom agents |
|
|
80
|
-
| `.agents/skills/<name>/SKILL.md` | Reusable skill instructions (`@name`) |
|
|
81
|
-
| `.claude/skills/<name>/SKILL.md` | Claude-compatible skills |
|
|
82
|
-
| `.agents/AGENTS.md` | Preferred local project context |
|
|
83
|
-
| `CLAUDE.md` | Local fallback context if `.agents/AGENTS.md` is absent |
|
|
84
|
-
| `AGENTS.md` | Local fallback context if `.agents/AGENTS.md` and `CLAUDE.md` are absent |
|
|
85
|
-
| `~/.agents/AGENTS.md` | Preferred global context, prepended before local context |
|
|
86
|
-
| `~/.agents/CLAUDE.md` | Global fallback context if `~/.agents/AGENTS.md` is absent |
|
|
87
|
-
|
|
88
|
-
Global commands, agents, and skills also work from `~/.agents/...` and `~/.claude/...`.
|
|
89
|
-
|
|
90
|
-
For commands, skills, and agents: local overrides global, and `.agents` overrides `.claude` at the same scope. Context files are combined differently: global context is injected first, then local context. โ [docs/configs.md](docs/configs.md)
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
|
|
94
|
-
## ๐ Getting Started
|
|
17
|
+
## โก Quick Start
|
|
95
18
|
|
|
96
|
-
|
|
19
|
+
I run on [Bun](https://bun.com) โ install me via bun or npm, but Bun needs to be on your machine.
|
|
97
20
|
|
|
98
21
|
```bash
|
|
99
|
-
# Install
|
|
100
|
-
bun add -g mini-coder
|
|
101
|
-
# or: npm install -g mini-coder
|
|
102
|
-
|
|
103
|
-
# Set a provider key (pick one โ or run Ollama locally)
|
|
104
|
-
export OPENCODE_API_KEY=your-zen-key # recommended
|
|
105
|
-
export ANTHROPIC_API_KEY=your-key # direct Anthropic
|
|
106
|
-
export OPENAI_API_KEY=your-key # direct OpenAI
|
|
107
|
-
export GOOGLE_API_KEY=your-key # direct Gemini
|
|
108
|
-
# or: export GEMINI_API_KEY=your-key
|
|
109
|
-
|
|
110
|
-
# Optional extras
|
|
111
|
-
export OLLAMA_BASE_URL=http://localhost:11434
|
|
112
|
-
export EXA_API_KEY=your-exa-key # enables webSearch/webContent
|
|
113
|
-
|
|
114
|
-
# Launch
|
|
115
|
-
mc
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
Or drop me a prompt straight away for one-shot mode (runs once, then exits):
|
|
22
|
+
# Install
|
|
23
|
+
bun add -g mini-coder # or: npm install -g mini-coder
|
|
119
24
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
25
|
+
# Set one API key (pick any)
|
|
26
|
+
export OPENCODE_API_KEY=your-key # recommended
|
|
27
|
+
export ANTHROPIC_API_KEY=your-key # direct Anthropic
|
|
28
|
+
export OPENAI_API_KEY=your-key # direct OpenAI
|
|
29
|
+
export GOOGLE_API_KEY=your-key # direct Gemini (or GEMINI_API_KEY)
|
|
123
30
|
|
|
124
|
-
|
|
31
|
+
# Optional
|
|
32
|
+
export OLLAMA_BASE_URL=http://localhost:11434 # local models
|
|
33
|
+
export EXA_API_KEY=your-key # web search tools
|
|
125
34
|
|
|
126
|
-
|
|
127
|
-
mc
|
|
128
|
-
mc -r <id> # resume a specific session
|
|
129
|
-
mc -l # list recent sessions
|
|
130
|
-
mc -m zen/claude-sonnet-4-6 # pick a model
|
|
131
|
-
mc --cwd ~/src/other-project # set working directory
|
|
132
|
-
mc -h # show help
|
|
35
|
+
# Go
|
|
36
|
+
mc
|
|
133
37
|
```
|
|
134
38
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
## ๐๏ธ App data
|
|
138
|
-
|
|
139
|
-
Everything I remember lives in `~/.config/mini-coder/` โ here's what I'm holding onto:
|
|
39
|
+
One-shot mode: `mc "refactor auth to use async/await"` โ runs once, then exits.
|
|
140
40
|
|
|
141
|
-
|
|
142
|
-
- `api.log` โ a request/response log for every provider call this run, if you want to peek under the hood
|
|
143
|
-
- `errors.log` โ anything that went sideways, caught and written down so you can actually debug it
|
|
41
|
+
Useful flags: `-c` continue last session, `-r <id>` resume, `-l` list sessions, `-m <model>` pick a model, `-h` help.
|
|
144
42
|
|
|
145
43
|
---
|
|
146
44
|
|
|
147
|
-
##
|
|
45
|
+
## ๐ OAuth Login
|
|
148
46
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
- [docs/custom-commands.md](docs/custom-commands.md)
|
|
152
|
-
- [docs/custom-agents.md](docs/custom-agents.md)
|
|
153
|
-
- [docs/skills.md](docs/skills.md)
|
|
154
|
-
- [docs/configs.md](docs/configs.md)
|
|
155
|
-
|
|
156
|
-
## ๐๏ธ Project Structure
|
|
157
|
-
|
|
158
|
-
```
|
|
159
|
-
src/
|
|
160
|
-
index.ts # Entry point + CLI arg parsing
|
|
161
|
-
agent/ # Main REPL loop + tool registry
|
|
162
|
-
cli/ # Input, output, slash commands, markdown rendering
|
|
163
|
-
llm-api/ # Provider factory + streaming turn logic
|
|
164
|
-
tools/ # shell, subagent, skill tools
|
|
165
|
-
# + webSearch, webContent
|
|
166
|
-
internal/ # shared internals, including the mc-edit helper implementation
|
|
167
|
-
mcp/ # MCP server connections
|
|
168
|
-
session/ # SQLite-backed session & history management
|
|
169
|
-
```
|
|
47
|
+
Use `/login` inside the REPL to authenticate via browser-based OAuth (currently Anthropic). No need to manage API keys manually.
|
|
170
48
|
|
|
171
49
|
---
|
|
172
50
|
|
|
173
|
-
##
|
|
51
|
+
## ๐ ๏ธ Features
|
|
174
52
|
|
|
175
|
-
- **
|
|
176
|
-
- **
|
|
177
|
-
- **
|
|
178
|
-
- **
|
|
179
|
-
- **
|
|
180
|
-
- **
|
|
53
|
+
- **Multi-provider** โ auto-discovers Anthropic, OpenAI, Gemini, Ollama, or any OpenAI-compatible endpoint
|
|
54
|
+
- **Session memory** โ SQLite-backed. Resume with `-c` or `-r <id>`
|
|
55
|
+
- **Shell integration** โ `!` prefix for inline commands, `@` to reference files with tab completion
|
|
56
|
+
- **Web search** โ `webSearch` + `webContent` tools when `EXA_API_KEY` is set
|
|
57
|
+
- **MCP support** โ connect external tool servers over HTTP or stdio
|
|
58
|
+
- **Custom commands** โ drop `.md` files in `.agents/commands/` โ instant `/slash` commands
|
|
59
|
+
- **Custom agents** โ `.agents/agents/*.md` for specialized personas you can activate with `/agent`
|
|
60
|
+
- **Skills** โ `.agents/skills/<name>/SKILL.md`, inject with `@name`
|
|
61
|
+
- **`mc-edit`** โ safe, exact-text file editing (no full-file rewrites)
|
|
62
|
+
- **16 ANSI colors** โ inherits your terminal theme. Always looks right.
|
|
181
63
|
|
|
182
64
|
---
|
|
183
65
|
|
|
184
|
-
##
|
|
66
|
+
## ๐ Getting Deeper
|
|
185
67
|
|
|
186
|
-
|
|
68
|
+
The README is the highlight reel. For the full story โ slash commands, config folders, context files, app data, and everything else:
|
|
187
69
|
|
|
188
|
-
|
|
70
|
+
**[๐ Read the Full Manual](docs/mini-coder.1.md)**
|
|
189
71
|
|
|
190
72
|
---
|
|
191
73
|
|
|
192
|
-
##
|
|
74
|
+
## ๐ฎ Tech Stack
|
|
193
75
|
|
|
194
|
-
|
|
195
|
-
> โ [vpr99](https://github.com/vpr99)
|
|
76
|
+
[Bun.js](https://bun.com) ยท [AI SDK](https://ai-sdk.dev) ยท [yoctocolors](https://github.com/sindresorhus/yoctocolors)
|
|
196
77
|
|
|
197
|
-
|
|
78
|
+
## ๐ License
|
|
198
79
|
|
|
199
|
-
|
|
80
|
+
MIT โ [github.com/sacenox/mini-coder](https://github.com/sacenox/mini-coder)
|
package/dist/mc-edit.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
// src/cli/structured-output.ts
|
|
5
5
|
import { createTwoFilesPatch } from "diff";
|
|
6
|
+
import * as c from "yoctocolors";
|
|
6
7
|
function normalizePatchLines(patchText) {
|
|
7
8
|
const patchLines = patchText.split(`
|
|
8
9
|
`);
|
|
@@ -17,14 +18,30 @@ function normalizePatchLines(patchText) {
|
|
|
17
18
|
return line;
|
|
18
19
|
});
|
|
19
20
|
}
|
|
20
|
-
function
|
|
21
|
+
function colorizeDiffLine(line) {
|
|
22
|
+
if (line.startsWith("---") || line.startsWith("+++"))
|
|
23
|
+
return c.dim(line);
|
|
24
|
+
if (line.startsWith("@@"))
|
|
25
|
+
return c.cyan(line);
|
|
26
|
+
if (line.startsWith("+"))
|
|
27
|
+
return c.green(line);
|
|
28
|
+
if (line.startsWith("-"))
|
|
29
|
+
return c.red(line);
|
|
30
|
+
return line;
|
|
31
|
+
}
|
|
32
|
+
function renderUnifiedDiff(filePath, before, after, options) {
|
|
21
33
|
if (before === after) {
|
|
22
34
|
return "(no changes)";
|
|
23
35
|
}
|
|
24
36
|
const patchText = createTwoFilesPatch(filePath, filePath, before, after, "", "", {
|
|
25
37
|
context: 3
|
|
26
38
|
});
|
|
27
|
-
|
|
39
|
+
const lines = normalizePatchLines(patchText);
|
|
40
|
+
if (options?.colorize) {
|
|
41
|
+
return lines.map(colorizeDiffLine).join(`
|
|
42
|
+
`);
|
|
43
|
+
}
|
|
44
|
+
return lines.join(`
|
|
28
45
|
`);
|
|
29
46
|
}
|
|
30
47
|
function renderMetadataBlock(result) {
|
|
@@ -43,8 +60,11 @@ function renderMetadataBlock(result) {
|
|
|
43
60
|
}
|
|
44
61
|
function writeFileEditResult(io, result) {
|
|
45
62
|
if (result.ok) {
|
|
63
|
+
const colorize = process.env.FORCE_COLOR === "1" || process.env.FORCE_COLOR === "true";
|
|
46
64
|
const sections = [
|
|
47
|
-
renderUnifiedDiff(result.path, result.before, result.after
|
|
65
|
+
renderUnifiedDiff(result.path, result.before, result.after, {
|
|
66
|
+
colorize
|
|
67
|
+
}),
|
|
48
68
|
renderMetadataBlock(result)
|
|
49
69
|
];
|
|
50
70
|
io.stdout(`${sections.join(`
|
|
@@ -64,7 +84,7 @@ function stripMatchingQuotes(value) {
|
|
|
64
84
|
if (value.length < 2)
|
|
65
85
|
return value;
|
|
66
86
|
const first = value[0];
|
|
67
|
-
const last = value
|
|
87
|
+
const last = value.at(-1);
|
|
68
88
|
if ((first === '"' || first === "'") && first === last) {
|
|
69
89
|
return value.slice(1, -1);
|
|
70
90
|
}
|
|
@@ -76,7 +96,11 @@ function normalizePathInput(pathInput) {
|
|
|
76
96
|
function resolvePath(cwdInput, pathInput) {
|
|
77
97
|
const cwd = cwdInput ?? process.cwd();
|
|
78
98
|
const normalizedInput = normalizePathInput(pathInput);
|
|
79
|
-
|
|
99
|
+
let expanded = normalizedInput;
|
|
100
|
+
if (normalizedInput.startsWith("~/"))
|
|
101
|
+
expanded = join(homedir(), normalizedInput.slice(2));
|
|
102
|
+
else if (normalizedInput === "~")
|
|
103
|
+
expanded = homedir();
|
|
80
104
|
const filePath = expanded.startsWith("/") ? expanded : join(cwd, expanded);
|
|
81
105
|
const relPath = relative(cwd, filePath);
|
|
82
106
|
return { cwd, filePath, relPath };
|