mercury-agent 0.4.22 → 0.4.24
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/docs/ARCHITECTURE.md +30 -0
- package/docs/DESIGN.md +42 -0
- package/docs/ROADMAP.md +41 -0
- package/docs/VISION.md +32 -0
- package/docs/archive/.gitkeep +0 -0
- package/docs/backlog/.gitkeep +0 -0
- package/docs/bugs/.gitkeep +0 -0
- package/docs/bugs/bwrap-privileged-linux-docker.md +140 -0
- package/docs/bugs/registry-pull-no-local-fallback.md +168 -0
- package/docs/debug/major/.gitkeep +0 -0
- package/docs/debug/minor/.gitkeep +0 -0
- package/docs/debug/moderate/.gitkeep +0 -0
- package/docs/html-slides/.gitkeep +0 -0
- package/docs/ideas/.gitkeep +0 -0
- package/docs/in-progress/.gitkeep +0 -0
- package/docs/notes/.gitkeep +0 -0
- package/docs/pending-updates/.gitkeep +0 -0
- package/docs/runbooks/publish-checklist.md +8 -0
- package/docs/templates/TEMPLATE-AUTOPILOT-CONFIG.yaml +35 -0
- package/docs/templates/TEMPLATE-BUG.md +71 -0
- package/docs/templates/TEMPLATE-CI.yml +25 -0
- package/docs/templates/TEMPLATE-DECISIONS.md +11 -0
- package/docs/templates/TEMPLATE-FEATURE.md +127 -0
- package/docs/templates/TEMPLATE-GOAL.md +31 -0
- package/docs/templates/TEMPLATE-IDEA.md +31 -0
- package/docs/templates/TEMPLATE-NOTE.md +27 -0
- package/docs/templates/TEMPLATE-ROADMAP.md +21 -0
- package/examples/extensions/pinchtab/index.ts +1 -1
- package/package.json +1 -1
- package/src/adapters/whatsapp.ts +635 -635
- package/src/agent/container-entry.ts +66 -12
- package/src/agent/container-runner.ts +18 -12
- package/src/agent/model-capabilities.ts +231 -231
- package/src/bridges/discord.ts +178 -178
- package/src/bridges/slack.ts +179 -179
- package/src/bridges/teams.ts +162 -162
- package/src/bridges/telegram.ts +579 -579
- package/src/cli/mercury.ts +2587 -2585
- package/src/cli/whatsapp-auth.ts +263 -263
- package/src/config.ts +316 -316
- package/src/core/commands.ts +110 -110
- package/src/core/permissions.ts +196 -196
- package/src/core/router.ts +204 -204
- package/src/core/routes/chat.ts +175 -175
- package/src/core/routes/dashboard.ts +2493 -2493
- package/src/core/routes/messages.ts +37 -37
- package/src/core/routes/mutes.ts +95 -95
- package/src/core/routes/roles.ts +135 -135
- package/src/core/runtime.ts +1508 -1508
- package/src/core/task-scheduler.ts +139 -139
- package/src/extensions/catalog.ts +117 -117
- package/src/extensions/hooks.ts +161 -161
- package/src/extensions/installer.ts +306 -306
- package/src/extensions/loader.ts +271 -271
- package/src/extensions/permission-guard.ts +52 -52
- package/src/server.ts +391 -391
- package/src/storage/db.ts +1684 -1687
- package/src/storage/pi-auth.ts +95 -95
- package/src/tts/azure.ts +52 -52
- package/src/tts/synthesize.ts +133 -133
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# {Project Name} — Architecture Reference
|
|
2
|
+
|
|
3
|
+
> On-demand reference. Do not auto-load. Read when a task is cross-cutting or you need to understand inter-package data flow.
|
|
4
|
+
|
|
5
|
+
## Packages
|
|
6
|
+
|
|
7
|
+
| Package | Purpose | Stack | Runs On |
|
|
8
|
+
|---------|---------|-------|---------|
|
|
9
|
+
| `{package}/` | {purpose} | {stack} | {where it runs} |
|
|
10
|
+
|
|
11
|
+
## Deployment Topology
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
{ASCII diagram of your deployment — servers, services, databases, CDNs, etc.}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Data Flow
|
|
18
|
+
|
|
19
|
+
> How data moves between packages, services, and external systems. Include request paths, event flows, and storage interactions.
|
|
20
|
+
|
|
21
|
+
## Key Invariants
|
|
22
|
+
|
|
23
|
+
> Rules that must always hold true across the system. Breaking these causes cascading failures.
|
|
24
|
+
|
|
25
|
+
- {Invariant 1}
|
|
26
|
+
- {Invariant 2}
|
|
27
|
+
|
|
28
|
+
## Extension Points
|
|
29
|
+
|
|
30
|
+
> Where the system is designed to be extended — plugin interfaces, hook points, configuration surfaces.
|
package/docs/DESIGN.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# {Project Name} — Design System
|
|
2
|
+
|
|
3
|
+
> Fill this in if your project has a UI. Skip if it's a backend-only project.
|
|
4
|
+
|
|
5
|
+
## 1. Visual Theme
|
|
6
|
+
|
|
7
|
+
> Design principles — what the UI should feel like.
|
|
8
|
+
|
|
9
|
+
## 2. Color Roles
|
|
10
|
+
|
|
11
|
+
> CSS variable inventory. All colors must be defined as variables — never hardcode hex in component files.
|
|
12
|
+
|
|
13
|
+
| Token | Dark Value | Light Value | Role |
|
|
14
|
+
|-------|-----------|-------------|------|
|
|
15
|
+
| `--bg` | {hex} | {hex} | Page background |
|
|
16
|
+
| `--surface` | {hex} | {hex} | Card/panel background |
|
|
17
|
+
| `--text` | {hex} | {hex} | Primary text |
|
|
18
|
+
| `--muted` | {hex} | {hex} | Secondary text |
|
|
19
|
+
| `--accent` | {hex} | {hex} | Interactive elements |
|
|
20
|
+
| `--border` | {hex} | {hex} | Borders and dividers |
|
|
21
|
+
| `--color-success` | {hex} | {hex} | Success states |
|
|
22
|
+
| `--color-error` | {hex} | {hex} | Error states |
|
|
23
|
+
| `--color-warning` | {hex} | {hex} | Warning states |
|
|
24
|
+
|
|
25
|
+
## 3. Typography
|
|
26
|
+
|
|
27
|
+
> Font families, sizes, weights. Which fonts for which contexts.
|
|
28
|
+
|
|
29
|
+
## 4. Layout & Spacing
|
|
30
|
+
|
|
31
|
+
> Grid system, breakpoints, spacing scale. Include RTL/logical property conventions if applicable.
|
|
32
|
+
|
|
33
|
+
## 5. Components
|
|
34
|
+
|
|
35
|
+
> Component conventions — buttons, inputs, cards, modals, status indicators, etc.
|
|
36
|
+
|
|
37
|
+
## 6. Hard Rules
|
|
38
|
+
|
|
39
|
+
> Violations block merge. Examples:
|
|
40
|
+
> - No hardcoded hex colors in component files — use CSS variables
|
|
41
|
+
> - No physical CSS properties (`left`/`right`) — use logical properties
|
|
42
|
+
> - All interactive elements must have visible focus rings
|
package/docs/ROADMAP.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# {Project Name} — Roadmap
|
|
2
|
+
|
|
3
|
+
Single source of truth for priority. Rule: ≤15 min/week to maintain.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Inbox
|
|
8
|
+
|
|
9
|
+
> Uncategorized ideas. Triage into Now / Next / Later or drop.
|
|
10
|
+
|
|
11
|
+
| Item | Doc | Notes |
|
|
12
|
+
|------|-----|-------|
|
|
13
|
+
| — | — | — |
|
|
14
|
+
|
|
15
|
+
## Now
|
|
16
|
+
|
|
17
|
+
> Max 2 items. What you're actively working on.
|
|
18
|
+
|
|
19
|
+
| Item | Doc | Started | Notes |
|
|
20
|
+
|------|-----|---------|-------|
|
|
21
|
+
| — | — | — | — |
|
|
22
|
+
|
|
23
|
+
## Next
|
|
24
|
+
|
|
25
|
+
| # | Item | Doc | Depends on | Why now |
|
|
26
|
+
|---|------|-----|-----------|---------|
|
|
27
|
+
| 1 | **autonomous-planning-tier** | [doc](backlog/autonomous-planning-tier.md) | — | Let agents decompose ideas, keep human gate |
|
|
28
|
+
|
|
29
|
+
## Later
|
|
30
|
+
|
|
31
|
+
| Item | Doc | Notes |
|
|
32
|
+
|------|-----|-------|
|
|
33
|
+
| — | — | — |
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Shipped
|
|
38
|
+
|
|
39
|
+
| Item | Shipped | What |
|
|
40
|
+
|------|---------|------|
|
|
41
|
+
| — | — | — |
|
package/docs/VISION.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# {Project Name} — Product Vision
|
|
2
|
+
|
|
3
|
+
## What {Project Name} Is
|
|
4
|
+
|
|
5
|
+
> One-sentence pitch.
|
|
6
|
+
|
|
7
|
+
## Target User
|
|
8
|
+
|
|
9
|
+
> Who is this for? Be specific — role, context, what they're trying to accomplish.
|
|
10
|
+
|
|
11
|
+
## What Makes {Project Name} Different
|
|
12
|
+
|
|
13
|
+
| Differentiator | Why it matters |
|
|
14
|
+
|---------------|----------------|
|
|
15
|
+
| {differentiator} | {why} |
|
|
16
|
+
|
|
17
|
+
## Non-Goals
|
|
18
|
+
|
|
19
|
+
> Explicit list of what this project does NOT try to be. Helps filter feature requests.
|
|
20
|
+
|
|
21
|
+
- {Non-goal 1}
|
|
22
|
+
- {Non-goal 2}
|
|
23
|
+
|
|
24
|
+
## Guiding Questions for New Ideas
|
|
25
|
+
|
|
26
|
+
> Use these to evaluate whether a feature idea fits the product:
|
|
27
|
+
|
|
28
|
+
1. Does this serve the target user directly?
|
|
29
|
+
2. Does this align with the differentiators above?
|
|
30
|
+
3. Does this conflict with any non-goal?
|
|
31
|
+
4. Can the user benefit from this without configuration or documentation?
|
|
32
|
+
5. Would removing this make the product worse for the target user?
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Bug: bwrap fails to mount /proc on Linux Docker Engine (non-Desktop)
|
|
2
|
+
|
|
3
|
+
**Severity:** P1 — blocks all agent responses on standard Linux Docker hosts
|
|
4
|
+
**Affected:** Linux servers running Docker Engine (not Docker Desktop, not gVisor)
|
|
5
|
+
**File:** `src/agent/container-runner.ts`, bwrap compat branch (~line 980)
|
|
6
|
+
|
|
7
|
+
## Symptom
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Container error: Container failed (exit code 1): Error: pi CLI failed (1):
|
|
11
|
+
bwrap: Can't mount proc on /newroot/proc: Operation not permitted
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Happens on Linux servers (e.g. Hetzner, AWS EC2, DigitalOcean) running
|
|
15
|
+
Docker Engine with the default kernel config. The existing bwrap Docker compat
|
|
16
|
+
flags (`seccomp=unconfined`, `apparmor=unconfined`, `CAP_SYS_ADMIN`) are not
|
|
17
|
+
sufficient for bwrap to mount `/proc` inside the container.
|
|
18
|
+
|
|
19
|
+
## Root cause
|
|
20
|
+
|
|
21
|
+
On Linux Docker Engine, the default seccomp + AppArmor + capability set does
|
|
22
|
+
not allow `mount(2)` inside a user namespace, even with:
|
|
23
|
+
- `--security-opt seccomp=unconfined`
|
|
24
|
+
- `--security-opt apparmor=unconfined`
|
|
25
|
+
- `--cap-add SYS_ADMIN`
|
|
26
|
+
|
|
27
|
+
This is a known limitation: Docker's default behavior strips many mount-related
|
|
28
|
+
permissions that `--privileged` restores (device cgroup rules, all capabilities,
|
|
29
|
+
full /sys and /proc access).
|
|
30
|
+
|
|
31
|
+
**Verified:** `--privileged` makes bwrap work:
|
|
32
|
+
```bash
|
|
33
|
+
# Fails:
|
|
34
|
+
docker run --rm --entrypoint bwrap \
|
|
35
|
+
--security-opt seccomp=unconfined --security-opt apparmor=unconfined \
|
|
36
|
+
--cap-add SYS_ADMIN mercury-agent:latest \
|
|
37
|
+
--ro-bind /usr /usr --proc /proc --dev /dev --unshare-pid echo hello
|
|
38
|
+
# → bwrap: Can't mount proc on /newroot/proc: Operation not permitted
|
|
39
|
+
|
|
40
|
+
# Works:
|
|
41
|
+
docker run --rm --entrypoint bwrap --privileged mercury-agent:latest \
|
|
42
|
+
--ro-bind /usr /usr --proc /proc --dev /dev --unshare-pid echo hello
|
|
43
|
+
# → execvp echo: No such file or directory (bwrap ran fine, echo just not in /usr)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Fix
|
|
47
|
+
|
|
48
|
+
### Option A: Add `--privileged` flag to bwrap compat (recommended short-term)
|
|
49
|
+
|
|
50
|
+
In `container-runner.ts` (~line 985), replace the current compat flags with
|
|
51
|
+
`--privileged` when `containerBwrapDockerCompat` is explicitly set to `true`:
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
} else if (this.config.containerBwrapDockerCompat || isDockerDesktop()) {
|
|
55
|
+
logger.info("Enabling bwrap Docker compat (seccomp/apparmor/SYS_ADMIN)", {
|
|
56
|
+
configFlag: this.config.containerBwrapDockerCompat,
|
|
57
|
+
dockerDesktop: isDockerDesktop(),
|
|
58
|
+
});
|
|
59
|
+
if (this.config.containerBwrapDockerCompat) {
|
|
60
|
+
// Explicit opt-in: Linux Docker Engine needs --privileged for bwrap
|
|
61
|
+
// to mount /proc inside a user namespace. The finer-grained flags
|
|
62
|
+
// (seccomp=unconfined + apparmor=unconfined + SYS_ADMIN) are not
|
|
63
|
+
// sufficient on standard Linux kernels.
|
|
64
|
+
args.push("--privileged");
|
|
65
|
+
} else {
|
|
66
|
+
// Docker Desktop auto-detection: use the lighter-weight flags
|
|
67
|
+
// (Docker Desktop's VM has a more permissive kernel config)
|
|
68
|
+
args.push(
|
|
69
|
+
"--security-opt",
|
|
70
|
+
"seccomp=unconfined",
|
|
71
|
+
"--security-opt",
|
|
72
|
+
"apparmor=unconfined",
|
|
73
|
+
"--cap-add",
|
|
74
|
+
"SYS_ADMIN",
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
This keeps the lighter flags for Docker Desktop (where they work) and uses
|
|
81
|
+
`--privileged` only when the user explicitly opted in via
|
|
82
|
+
`MERCURY_CONTAINER_BWRAP_DOCKER_COMPAT=true`.
|
|
83
|
+
|
|
84
|
+
### Option B: Add a separate `MERCURY_CONTAINER_PRIVILEGED` config flag
|
|
85
|
+
|
|
86
|
+
If you prefer to keep the compat flag behavior unchanged, add a new flag:
|
|
87
|
+
|
|
88
|
+
In `config.ts`, add:
|
|
89
|
+
```typescript
|
|
90
|
+
containerPrivileged: boolean; // default: false
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
In `config-file.ts`, add the env mapping:
|
|
94
|
+
```typescript
|
|
95
|
+
containerPrivileged: "MERCURY_CONTAINER_PRIVILEGED",
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
In `container-runner.ts`, after the existing compat block:
|
|
99
|
+
```typescript
|
|
100
|
+
if (this.config.containerPrivileged) {
|
|
101
|
+
args.push("--privileged");
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
User sets `MERCURY_CONTAINER_PRIVILEGED=true` in `.env`.
|
|
106
|
+
|
|
107
|
+
### Option C: Auto-detect and use --privileged as fallback
|
|
108
|
+
|
|
109
|
+
Run a probe container on startup to test if bwrap works with the lighter
|
|
110
|
+
flags. If it fails, automatically escalate to `--privileged` and log a
|
|
111
|
+
warning. This is the most user-friendly but adds startup latency.
|
|
112
|
+
|
|
113
|
+
## Workaround (immediate)
|
|
114
|
+
|
|
115
|
+
Until the fix is in place, users can work around this by manually running
|
|
116
|
+
mercury with Docker's `--privileged` flag. However, since `mercury run`
|
|
117
|
+
doesn't expose extra Docker args, the only current workaround is to
|
|
118
|
+
modify `MERCURY_AGENT_IMAGE` to point to a locally-built image and skip
|
|
119
|
+
bwrap entirely by setting `MERCURY_CONTAINER_RUNTIME=runsc` (requires
|
|
120
|
+
gVisor installed), or to apply the code change.
|
|
121
|
+
|
|
122
|
+
## Linux server setup checklist
|
|
123
|
+
|
|
124
|
+
These sysctl settings are needed regardless of the fix above:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
sysctl -w kernel.unprivileged_userns_clone=1
|
|
128
|
+
sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
|
|
129
|
+
cat > /etc/sysctl.d/99-bubblewrap.conf << 'EOF'
|
|
130
|
+
kernel.unprivileged_userns_clone=1
|
|
131
|
+
kernel.apparmor_restrict_unprivileged_userns=0
|
|
132
|
+
EOF
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## How to verify
|
|
136
|
+
|
|
137
|
+
1. Set `MERCURY_CONTAINER_BWRAP_DOCKER_COMPAT=true` in `.env`
|
|
138
|
+
2. Start mercury: `pm2 restart all` or `mercury service install`
|
|
139
|
+
3. Run: `mercury chat 'hello'`
|
|
140
|
+
4. Check logs — should see successful container run, no bwrap errors
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Bug: mercury run fails when registry pull fails but local build exists
|
|
2
|
+
|
|
3
|
+
**Severity:** P1 — blocks users who build locally but have a registry image configured
|
|
4
|
+
**Introduced in:** 0.4.22 (commit 75e8e71)
|
|
5
|
+
**File:** `src/cli/mercury.ts`, `runAction()` (~line 187)
|
|
6
|
+
|
|
7
|
+
## Symptom
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
$ mercury build # succeeds → mercury-agent:latest exists locally
|
|
11
|
+
$ mercury run
|
|
12
|
+
Image 'ghcr.io/avishai-tsabari/mercury-agent:latest' not found locally, pulling...
|
|
13
|
+
Error response from daemon: unauthorized
|
|
14
|
+
|
|
15
|
+
Error: Failed to pull 'ghcr.io/avishai-tsabari/mercury-agent:latest'.
|
|
16
|
+
If this is a private registry, authenticate first:
|
|
17
|
+
docker login ghcr.io
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The user has a working local image (`mercury-agent:latest`) from `mercury build`,
|
|
21
|
+
but `mercury run` exits with an error because the configured registry image
|
|
22
|
+
can't be pulled (private registry, no auth, offline, etc.).
|
|
23
|
+
|
|
24
|
+
## Root cause
|
|
25
|
+
|
|
26
|
+
The 0.4.22 change replaced the local-fallback logic with auto-pull. The old
|
|
27
|
+
code tried `mercury-agent:latest` as a fallback when the configured image
|
|
28
|
+
wasn't found. The new code attempts `docker pull` and hard-exits on failure —
|
|
29
|
+
it never checks whether a locally built image exists.
|
|
30
|
+
|
|
31
|
+
### Before (0.4.21)
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
configured image not found?
|
|
35
|
+
→ try mercury-agent:latest locally
|
|
36
|
+
→ found? use it (with warning)
|
|
37
|
+
→ not found? error: pull or build
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### After (0.4.22)
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
configured image not found?
|
|
44
|
+
→ is registry image? attempt pull
|
|
45
|
+
→ pull fails? hard exit ← BUG: should fall back to local
|
|
46
|
+
→ not registry? error: run mercury build
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Fix
|
|
50
|
+
|
|
51
|
+
After a failed pull of a registry image, check if `mercury-agent:latest`
|
|
52
|
+
exists locally before giving up. If it does, use it with a warning.
|
|
53
|
+
|
|
54
|
+
### Implementation (lines ~187–213 of `src/cli/mercury.ts`)
|
|
55
|
+
|
|
56
|
+
Replace the current block:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
if (imageCheck.status !== 0) {
|
|
60
|
+
const isRegistryImage = imageName.includes("/");
|
|
61
|
+
if (isRegistryImage) {
|
|
62
|
+
console.log(`Image '${imageName}' not found locally, pulling...`);
|
|
63
|
+
const pull = spawnSync("docker", ["pull", imageName], {
|
|
64
|
+
stdio: "inherit",
|
|
65
|
+
});
|
|
66
|
+
if (pull.signal) {
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
if (pull.status !== 0) {
|
|
70
|
+
const firstSegment = imageName.split("/")[0];
|
|
71
|
+
const registry = firstSegment.includes(".")
|
|
72
|
+
? firstSegment
|
|
73
|
+
: "docker.io";
|
|
74
|
+
console.error(`\nError: Failed to pull '${imageName}'.`);
|
|
75
|
+
console.error(
|
|
76
|
+
"If this is a private registry, authenticate first:\n" +
|
|
77
|
+
` docker login ${registry}`,
|
|
78
|
+
);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
console.error(`Error: Container image '${imageName}' not found.`);
|
|
83
|
+
console.error("Run 'mercury build' to build it.");
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
With:
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
if (imageCheck.status !== 0) {
|
|
93
|
+
const isRegistryImage = imageName.includes("/");
|
|
94
|
+
let resolved = false;
|
|
95
|
+
|
|
96
|
+
if (isRegistryImage) {
|
|
97
|
+
console.log(`Image '${imageName}' not found locally, pulling...`);
|
|
98
|
+
const pull = spawnSync("docker", ["pull", imageName], {
|
|
99
|
+
stdio: "inherit",
|
|
100
|
+
});
|
|
101
|
+
if (pull.signal) {
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
if (pull.status === 0) {
|
|
105
|
+
resolved = true;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Fallback: if the configured image isn't available (pull failed, not a
|
|
110
|
+
// registry image, or never pulled), try the local build tag.
|
|
111
|
+
if (!resolved) {
|
|
112
|
+
const localTag = "mercury-agent:latest";
|
|
113
|
+
if (imageName !== localTag) {
|
|
114
|
+
const localCheck = spawnSync("docker", ["image", "inspect", localTag], {
|
|
115
|
+
stdio: "pipe",
|
|
116
|
+
});
|
|
117
|
+
if (localCheck.status === 0) {
|
|
118
|
+
console.log(
|
|
119
|
+
`\nℹ️ Using locally built ${localTag} (configured image unavailable)\n`,
|
|
120
|
+
);
|
|
121
|
+
process.env.MERCURY_AGENT_IMAGE = localTag;
|
|
122
|
+
resolved = true;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!resolved) {
|
|
128
|
+
if (isRegistryImage) {
|
|
129
|
+
const firstSegment = imageName.split("/")[0];
|
|
130
|
+
const registry = firstSegment.includes(".")
|
|
131
|
+
? firstSegment
|
|
132
|
+
: "docker.io";
|
|
133
|
+
console.error(`\nError: Failed to pull '${imageName}'.`);
|
|
134
|
+
console.error(
|
|
135
|
+
"If this is a private registry, authenticate first:\n" +
|
|
136
|
+
` docker login ${registry}\n` +
|
|
137
|
+
"Or build locally:\n" +
|
|
138
|
+
" mercury build",
|
|
139
|
+
);
|
|
140
|
+
} else {
|
|
141
|
+
console.error(`Error: Container image '${imageName}' not found.`);
|
|
142
|
+
console.error("Run 'mercury build' to build it.");
|
|
143
|
+
}
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Behavior after fix
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
configured image not found?
|
|
153
|
+
→ is registry image? attempt pull
|
|
154
|
+
→ pull succeeds? use it ✓
|
|
155
|
+
→ pull fails? continue to fallback
|
|
156
|
+
→ try mercury-agent:latest locally
|
|
157
|
+
→ found? use it (with info message) ✓
|
|
158
|
+
→ not found? error with both suggestions (login + build) ✓
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## How to verify
|
|
162
|
+
|
|
163
|
+
1. Build locally: `mercury build`
|
|
164
|
+
2. Ensure no GHCR auth: `docker logout ghcr.io`
|
|
165
|
+
3. Set `.env` to `MERCURY_AGENT_IMAGE=ghcr.io/avishai-tsabari/mercury-agent:latest`
|
|
166
|
+
4. Run `mercury run` — should fall back to local image with info message
|
|
167
|
+
5. Remove local image: `docker rmi mercury-agent:latest`
|
|
168
|
+
6. Run `mercury run` — should error with both `docker login` and `mercury build` suggestions
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Publish Checklist
|
|
2
|
+
|
|
3
|
+
Before publishing a new version to npm:
|
|
4
|
+
|
|
5
|
+
1. **`bun run check`** — typecheck + lint + tests
|
|
6
|
+
2. **`mercury build`** — if you touched build path, Dockerfiles, or file-copy logic
|
|
7
|
+
3. **`mercury init` + `mercury service install`** in a test project — if you touched CLI flow, config loading, or service management
|
|
8
|
+
4. **Smoke test assistants** — send a message, verify they respond
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Autopilot Configuration
|
|
2
|
+
# Copy this file to docs/autopilot/config.yaml and customize.
|
|
3
|
+
# The orchestrator script reads this file each iteration.
|
|
4
|
+
|
|
5
|
+
gates:
|
|
6
|
+
max_iterations: 10 # stop after N iterations per session
|
|
7
|
+
max_features_without_review: 3 # stop after completing N features/bugs without human review
|
|
8
|
+
max_retries_same_task: 3 # skip a task after N failed attempts
|
|
9
|
+
iteration_timeout_minutes: 30 # kill a single execute phase after this long
|
|
10
|
+
|
|
11
|
+
risk:
|
|
12
|
+
sensitive_paths: # changes to these = immediate stop for review
|
|
13
|
+
- "**/auth/**"
|
|
14
|
+
- "**/migration*"
|
|
15
|
+
- "**/.env*"
|
|
16
|
+
- "**/schema*"
|
|
17
|
+
auto_stop_risk_threshold: 8 # risk_score >= this from assess = stop
|
|
18
|
+
|
|
19
|
+
scope:
|
|
20
|
+
allowed_actions: # which actions the autopilot may take
|
|
21
|
+
- implement_feature
|
|
22
|
+
- continue_feature
|
|
23
|
+
- fix_bug
|
|
24
|
+
- sync_docs
|
|
25
|
+
# - propose_decomposition # uncomment to enable autonomous planning (requires allow_autonomous_planning: true)
|
|
26
|
+
skip_slugs: # slugs to never touch autonomously
|
|
27
|
+
# - my-feature-slug
|
|
28
|
+
|
|
29
|
+
planning:
|
|
30
|
+
allow_autonomous_planning: false # when true, autopilot can decompose ideas into draft plans (requires propose_decomposition in allowed_actions)
|
|
31
|
+
# plans land as Status: Proposed and always stop for human review
|
|
32
|
+
|
|
33
|
+
notifications:
|
|
34
|
+
on_stop: console # "console" | "file" (future: "slack", "email")
|
|
35
|
+
decision_log: docs/autopilot/decision-log.md
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Bug: {Title}
|
|
2
|
+
|
|
3
|
+
**Status**: Open | In-Progress | Fixed
|
|
4
|
+
**Severity**: minor | moderate | major
|
|
5
|
+
**Slug**: {slug}
|
|
6
|
+
**Reported**: {YYYY-MM-DD}
|
|
7
|
+
**Last updated**: {YYYY-MM-DD}
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Summary
|
|
12
|
+
|
|
13
|
+
{One-sentence description of what's broken and where.}
|
|
14
|
+
|
|
15
|
+
## Steps to Reproduce
|
|
16
|
+
|
|
17
|
+
1.
|
|
18
|
+
2.
|
|
19
|
+
3.
|
|
20
|
+
|
|
21
|
+
## Expected Behavior
|
|
22
|
+
|
|
23
|
+
{What should happen.}
|
|
24
|
+
|
|
25
|
+
## Actual Behavior
|
|
26
|
+
|
|
27
|
+
{What actually happens. Include any error messages or observable symptoms.}
|
|
28
|
+
|
|
29
|
+
## Impact
|
|
30
|
+
|
|
31
|
+
- {Who or what is affected, and how severely.}
|
|
32
|
+
|
|
33
|
+
## Suspected Location
|
|
34
|
+
|
|
35
|
+
- {File path(s) or component(s) most likely responsible.}
|
|
36
|
+
|
|
37
|
+
## Notes
|
|
38
|
+
|
|
39
|
+
- {Workarounds, related issues, env var context, etc.}
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Implementation Checklist
|
|
44
|
+
|
|
45
|
+
- [ ] Root cause identified
|
|
46
|
+
- [ ] Fix implemented
|
|
47
|
+
- [ ] `{your check command}` passes
|
|
48
|
+
- [ ] No secrets or `.env` files committed
|
|
49
|
+
- [ ] No unrelated files modified
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Post-Mortem
|
|
54
|
+
|
|
55
|
+
> Fill in after the fix is complete.
|
|
56
|
+
|
|
57
|
+
### Investigation
|
|
58
|
+
|
|
59
|
+
{How you traced the bug — files read, code paths followed, assumptions tested.}
|
|
60
|
+
|
|
61
|
+
### Root Cause
|
|
62
|
+
|
|
63
|
+
{Precise explanation of the defective code and why it caused the symptom.}
|
|
64
|
+
|
|
65
|
+
### Fix
|
|
66
|
+
|
|
67
|
+
{What changed and why. Include file paths and key line references.}
|
|
68
|
+
|
|
69
|
+
### Lessons
|
|
70
|
+
|
|
71
|
+
- {Takeaways applicable to future work — patterns to avoid, checks to add, etc.}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
check:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
# TODO: Add stack setup steps, e.g.:
|
|
16
|
+
# - uses: actions/setup-node@v4
|
|
17
|
+
# with: { node-version: 20 }
|
|
18
|
+
# - run: npm ci
|
|
19
|
+
|
|
20
|
+
- name: Run checks
|
|
21
|
+
run: |
|
|
22
|
+
# TODO: Paste your check command from .claude/project-checks.md
|
|
23
|
+
# Example: npm run typecheck && npm run lint && npm test
|
|
24
|
+
echo "CI not configured — fill in the check command above"
|
|
25
|
+
exit 1
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Decisions: {Goal Title}
|
|
2
|
+
|
|
3
|
+
**Goal**: [{goal-slug}](goal.md)
|
|
4
|
+
|
|
5
|
+
## D-001: {Decision title}
|
|
6
|
+
- **Category:** tech-stack | architecture | scope | pattern | trade-off
|
|
7
|
+
- **Decided:** {what was chosen}
|
|
8
|
+
- **Alternatives considered:** {list}
|
|
9
|
+
- **Reasoning:** {why this choice}
|
|
10
|
+
- **Revisit if:** {condition that would invalidate this decision}
|
|
11
|
+
- **Used by:** {feature-slug-1}, {feature-slug-2}
|