@askexenow/exe-os 0.9.155 → 0.9.157

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.
@@ -0,0 +1,34 @@
1
+ # Protected Files — NEVER overwritten by stack-update
2
+
3
+ These files contain customer configuration. `exe-os stack-update` MUST NOT
4
+ touch them. If a file needs to change, the update should add a NEW file
5
+ and log a migration notice, not replace the existing one.
6
+
7
+ ## Config files (bind-mounted, customer-owned after first setup)
8
+ - `.env` — all secrets, tokens, passwords (PATCHED, never replaced)
9
+ - `gateway.json` — WhatsApp adapter config, account names
10
+ - `branding.json` — customer brand colors, fonts, logo
11
+ - `cloudflared/config.yml` — tunnel ID, credentials, ingress routes
12
+ - `cloudflared/*.json` — tunnel credential files
13
+
14
+ ## Data volumes (Docker managed, persist across updates)
15
+ - `postgres_data` — all database data (CRM, wiki, graph, raw, gateway)
16
+ - `gateway_data` — Baileys WhatsApp auth state (creds.json, sessions)
17
+ - `wiki_data` — uploaded documents, workspace storage
18
+ - `crm_data` — CRM local file storage
19
+ - `monitor_hub_data` — PocketBase data, alert history
20
+ - `monitor_agent_data` — agent metrics cache
21
+ - `redis_data` — CRM job queue, session cache
22
+ - `clickhouse_data` — CRM analytics
23
+ - `exe_os_data` — daemon state, SQLCipher memory DB
24
+
25
+ ## What CAN be updated safely
26
+ - Docker images (pulled, not built locally)
27
+ - `init-db.sql` (only runs on FIRST postgres boot, not on restarts)
28
+ - `docker-compose.yml` (can be replaced — it references configs by path)
29
+ - Deploy scripts (setup.sh, backup.sh, status.sh)
30
+
31
+ ## Golden rule
32
+ If `docker compose down && docker compose up -d` loses customer data
33
+ or config, the compose is WRONG. Volumes and bind mounts must survive
34
+ any container lifecycle operation EXCEPT `docker compose down -v`.
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env bash
2
+ # exe-os stack backup — full data + config, portable to any destination.
3
+ #
4
+ # Usage:
5
+ # ./backup.sh # Backup to /opt/exe-backups/
6
+ # ./backup.sh --output /tmp/backup # Backup to custom dir
7
+ # ./backup.sh --download # Create backup + print download command
8
+ # ./backup.sh --upload-r2 # Backup + upload to Cloudflare R2
9
+ # ./backup.sh --upload-s3 s3://bucket # Backup + upload to S3
10
+ #
11
+ set -euo pipefail
12
+
13
+ BACKUP_DIR="${BACKUP_DIR:-/opt/exe-backups}"
14
+ RETENTION_DAYS="${BACKUP_RETENTION_DAYS:-7}"
15
+ DATE=$(date +%Y%m%d-%H%M%S)
16
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
17
+ DOWNLOAD_MODE=false
18
+ UPLOAD_R2=false
19
+ UPLOAD_S3=""
20
+
21
+ while [[ $# -gt 0 ]]; do
22
+ case $1 in
23
+ --output) BACKUP_DIR="$2"; shift 2;;
24
+ --download) DOWNLOAD_MODE=true; shift;;
25
+ --upload-r2) UPLOAD_R2=true; shift;;
26
+ --upload-s3) UPLOAD_S3="$2"; shift 2;;
27
+ *) shift;;
28
+ esac
29
+ done
30
+
31
+ mkdir -p "$BACKUP_DIR"
32
+ ARCHIVE="$BACKUP_DIR/exe-backup-$DATE"
33
+ mkdir -p "$ARCHIVE"
34
+
35
+ echo "[backup] Starting exe-os full stack backup ($DATE)"
36
+
37
+ # 1. Postgres dump (all databases)
38
+ echo "[backup] Dumping postgres..."
39
+ docker exec exe-db pg_dumpall -U exe > "$ARCHIVE/postgres.sql" 2>/dev/null || echo "[backup] Postgres dump failed"
40
+ gzip "$ARCHIVE/postgres.sql" 2>/dev/null || true
41
+
42
+ # 2. Customer config files (.env, gateway.json, branding.json, cloudflared)
43
+ echo "[backup] Backing up config files..."
44
+ cp "$SCRIPT_DIR/.env" "$ARCHIVE/env.bak" 2>/dev/null || true
45
+ cp "$SCRIPT_DIR/gateway.json" "$ARCHIVE/gateway.json" 2>/dev/null || true
46
+ cp "$SCRIPT_DIR/branding.json" "$ARCHIVE/branding.json" 2>/dev/null || true
47
+ cp -r "$SCRIPT_DIR/cloudflared" "$ARCHIVE/cloudflared" 2>/dev/null || true
48
+
49
+ # 3. Gateway auth state (Baileys creds — critical for WhatsApp connection)
50
+ echo "[backup] Backing up gateway WhatsApp auth state..."
51
+ docker cp exe-gateway:/data/. "$ARCHIVE/gateway-data/" 2>/dev/null || echo "[backup] Gateway data skipped"
52
+
53
+ # 4. Wiki storage (uploaded documents)
54
+ echo "[backup] Backing up wiki storage..."
55
+ docker cp exe-wiki:/app/server/storage/. "$ARCHIVE/wiki-storage/" 2>/dev/null || echo "[backup] Wiki storage skipped"
56
+
57
+ # 5. exe-os daemon state (optional — SQLCipher DB is local-first, not critical for VPS)
58
+ echo "[backup] Backing up exe-os state..."
59
+ docker cp exe-os:/home/exed/.exe-os/. "$ARCHIVE/exe-os-data/" 2>/dev/null || echo "[backup] exe-os data skipped"
60
+
61
+ # 6. Create single archive
62
+ echo "[backup] Creating archive..."
63
+ TARFILE="$BACKUP_DIR/exe-backup-$DATE.tar.gz"
64
+ tar -czf "$TARFILE" -C "$BACKUP_DIR" "exe-backup-$DATE" 2>/dev/null
65
+ rm -rf "$ARCHIVE"
66
+ echo "[backup] Archive: $TARFILE ($(du -h "$TARFILE" | cut -f1))"
67
+
68
+ # 7. Retention — delete old backups
69
+ echo "[backup] Cleaning backups older than $RETENTION_DAYS days..."
70
+ find "$BACKUP_DIR" -name "exe-backup-*.tar.gz" -mtime "+$RETENTION_DAYS" -delete 2>/dev/null
71
+
72
+ # 8. Download instructions
73
+ if $DOWNLOAD_MODE; then
74
+ echo ""
75
+ echo "=== Download to your local machine ==="
76
+ echo "Run on your local machine:"
77
+ echo ""
78
+ HOSTNAME=$(hostname)
79
+ IP=$(curl -s ifconfig.me 2>/dev/null || echo "<VPS_IP>")
80
+ echo " scp root@$IP:$TARFILE ./exe-backup-$DATE.tar.gz"
81
+ echo ""
82
+ echo "Or via Tailscale:"
83
+ TS_IP=$(tailscale ip -4 2>/dev/null || echo "<TAILSCALE_IP>")
84
+ echo " scp root@$TS_IP:$TARFILE ./exe-backup-$DATE.tar.gz"
85
+ echo ""
86
+ echo "To restore on a new VPS:"
87
+ echo " tar -xzf exe-backup-$DATE.tar.gz"
88
+ echo " cp env.bak /opt/exe-stack/.env"
89
+ echo " cp gateway.json /opt/exe-stack/"
90
+ echo " cp branding.json /opt/exe-stack/"
91
+ echo " cp -r cloudflared/ /opt/exe-stack/"
92
+ echo " cat postgres.sql.gz | gunzip | docker exec -i exe-db psql -U exe"
93
+ echo " docker compose up -d"
94
+ fi
95
+
96
+ # 9. Upload to R2 (Cloudflare)
97
+ if $UPLOAD_R2; then
98
+ echo "[backup] Uploading to Cloudflare R2..."
99
+ if command -v rclone >/dev/null 2>&1; then
100
+ rclone copy "$TARFILE" r2:exe-backups/ 2>&1 && echo "[backup] R2 upload complete" || echo "[backup] R2 upload failed"
101
+ elif command -v aws >/dev/null 2>&1; then
102
+ aws s3 cp "$TARFILE" "s3://exe-backups/$(basename "$TARFILE")" --endpoint-url "${R2_ENDPOINT:-}" 2>&1 || echo "[backup] R2 upload failed — configure R2_ENDPOINT"
103
+ else
104
+ echo "[backup] Install rclone or aws-cli for R2 upload"
105
+ fi
106
+ fi
107
+
108
+ # 10. Upload to S3
109
+ if [[ -n "$UPLOAD_S3" ]]; then
110
+ echo "[backup] Uploading to S3..."
111
+ aws s3 cp "$TARFILE" "$UPLOAD_S3/$(basename "$TARFILE")" 2>&1 && echo "[backup] S3 upload complete" || echo "[backup] S3 upload failed"
112
+ fi
113
+
114
+ echo "[backup] Done."
115
+ echo ""
116
+ echo "Backups:"
117
+ ls -lh "$BACKUP_DIR"/exe-backup-*.tar.gz 2>/dev/null | tail -5
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "Exe OS",
3
+ "logo": null,
4
+ "colors": {
5
+ "primary": "#F5D76E",
6
+ "background": "#0F0E1A",
7
+ "surface": "rgba(245, 215, 110, 0.08)",
8
+ "text": "#f8f5ea",
9
+ "muted": "rgba(248, 245, 234, 0.72)"
10
+ },
11
+ "fonts": {
12
+ "heading": "Epilogue",
13
+ "body": "Manrope",
14
+ "mono": "Space Grotesk"
15
+ },
16
+ "support": {
17
+ "email": "support@askexe.com",
18
+ "url": "https://askexe.com"
19
+ }
20
+ }
@@ -126,6 +126,11 @@ services:
126
126
  API_EXTERNAL_URL: ${GOTRUE_EXTERNAL_URL:-https://auth.askexe.com}
127
127
  GOTRUE_DISABLE_SIGNUP: ${GOTRUE_DISABLE_SIGNUP:-false}
128
128
  GOTRUE_MAILER_AUTOCONFIRM: ${GOTRUE_MAILER_AUTOCONFIRM:-true}
129
+ GOTRUE_SMTP_HOST: ${SMTP_HOST:-}
130
+ GOTRUE_SMTP_PORT: ${SMTP_PORT:-587}
131
+ GOTRUE_SMTP_USER: ${SMTP_USER:-}
132
+ GOTRUE_SMTP_PASS: ${SMTP_PASS:-}
133
+ GOTRUE_SMTP_ADMIN_EMAIL: ${SMTP_FROM:-noreply@askexe.com}
129
134
  ports:
130
135
  - "127.0.0.1:${GOTRUE_HOST_PORT:-9999}:9999"
131
136
  networks:
@@ -173,9 +178,14 @@ services:
173
178
  image: ${CRM_IMAGE_TAG:-ghcr.io/askexe/exe-crm:v0.9.2}
174
179
  container_name: exe-crm
175
180
  restart: unless-stopped
181
+ # Auto-migrate on boot: run database init before starting the app.
182
+ # Twenty CRM won't create tables automatically — this ensures they exist.
183
+ command: ["sh", "-c", "yarn database:init:prod 2>/dev/null || true && node dist/src/main"]
176
184
  depends_on:
177
185
  exe-db:
178
186
  condition: service_healthy
187
+ gotrue:
188
+ condition: service_healthy
179
189
  clickhouse:
180
190
  condition: service_healthy
181
191
  redis:
@@ -261,9 +271,13 @@ services:
261
271
  image: ${WIKI_IMAGE_TAG:-ghcr.io/askexe/exe-wiki:v0.9.2}
262
272
  container_name: exe-wiki
263
273
  restart: unless-stopped
274
+ # Wiki uses Prisma — runs migrate on boot via built-in entrypoint.
275
+ # If tables don't exist, Prisma creates them automatically.
264
276
  depends_on:
265
277
  exe-db:
266
278
  condition: service_healthy
279
+ gotrue:
280
+ condition: service_healthy
267
281
  env_file:
268
282
  - path: .env
269
283
  required: false
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env bash
2
+ # exe-os stack restore — restore from a backup archive.
3
+ #
4
+ # Usage:
5
+ # ./restore.sh /path/to/exe-backup-YYYYMMDD-HHMMSS.tar.gz
6
+ #
7
+ # WARNING: This overwrites current config and database. Make a backup first.
8
+ set -euo pipefail
9
+
10
+ RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
11
+ info() { echo -e "${GREEN}[restore]${NC} $1"; }
12
+ warn() { echo -e "${YELLOW}[restore]${NC} $1"; }
13
+ err() { echo -e "${RED}[restore]${NC} $1" >&2; }
14
+
15
+ ARCHIVE="${1:-}"
16
+ [[ -z "$ARCHIVE" ]] && { err "Usage: ./restore.sh <backup-archive.tar.gz>"; exit 1; }
17
+ [[ ! -f "$ARCHIVE" ]] && { err "File not found: $ARCHIVE"; exit 1; }
18
+
19
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
20
+ TEMP_DIR=$(mktemp -d)
21
+ trap "rm -rf $TEMP_DIR" EXIT
22
+
23
+ info "Extracting backup..."
24
+ tar -xzf "$ARCHIVE" -C "$TEMP_DIR"
25
+ BACKUP_DIR=$(ls -d "$TEMP_DIR"/exe-backup-* 2>/dev/null | head -1)
26
+ [[ -z "$BACKUP_DIR" ]] && { err "Invalid backup archive — no exe-backup-* directory found"; exit 1; }
27
+
28
+ echo ""
29
+ warn "This will OVERWRITE current config and restore the database."
30
+ warn "Current data will be LOST. Make sure you have a backup of the current state."
31
+ read -p "Type 'RESTORE' to confirm: " CONFIRM
32
+ [[ "$CONFIRM" != "RESTORE" ]] && { err "Aborted."; exit 1; }
33
+
34
+ # 1. Restore config files
35
+ info "Restoring config files..."
36
+ [[ -f "$BACKUP_DIR/env.bak" ]] && cp "$BACKUP_DIR/env.bak" "$SCRIPT_DIR/.env" && info ".env restored"
37
+ [[ -f "$BACKUP_DIR/gateway.json" ]] && cp "$BACKUP_DIR/gateway.json" "$SCRIPT_DIR/gateway.json" && info "gateway.json restored"
38
+ [[ -f "$BACKUP_DIR/branding.json" ]] && cp "$BACKUP_DIR/branding.json" "$SCRIPT_DIR/branding.json" && info "branding.json restored"
39
+ [[ -d "$BACKUP_DIR/cloudflared" ]] && cp -r "$BACKUP_DIR/cloudflared" "$SCRIPT_DIR/" && info "cloudflared config restored"
40
+
41
+ # 2. Restore postgres
42
+ if [[ -f "$BACKUP_DIR/postgres.sql.gz" ]]; then
43
+ info "Restoring postgres database..."
44
+ docker compose up -d exe-db 2>/dev/null
45
+ sleep 5 # wait for postgres to be ready
46
+ gunzip -c "$BACKUP_DIR/postgres.sql.gz" | docker exec -i exe-db psql -U exe 2>/dev/null
47
+ info "Postgres restored"
48
+ fi
49
+
50
+ # 3. Restore gateway auth state
51
+ if [[ -d "$BACKUP_DIR/gateway-data" ]]; then
52
+ info "Restoring gateway WhatsApp auth state..."
53
+ docker compose up -d exe-gateway 2>/dev/null
54
+ sleep 3
55
+ docker cp "$BACKUP_DIR/gateway-data/." exe-gateway:/data/ 2>/dev/null
56
+ docker restart exe-gateway 2>/dev/null
57
+ info "Gateway auth state restored (WhatsApp should reconnect)"
58
+ fi
59
+
60
+ # 4. Restore wiki storage
61
+ if [[ -d "$BACKUP_DIR/wiki-storage" ]]; then
62
+ info "Restoring wiki storage..."
63
+ docker compose up -d exe-wiki 2>/dev/null
64
+ sleep 3
65
+ docker cp "$BACKUP_DIR/wiki-storage/." exe-wiki:/app/server/storage/ 2>/dev/null
66
+ info "Wiki storage restored"
67
+ fi
68
+
69
+ # 5. Start full stack
70
+ info "Starting full stack..."
71
+ docker compose up -d 2>&1
72
+
73
+ info "Restore complete. Run ./status.sh to verify."
@@ -0,0 +1,166 @@
1
+ #!/usr/bin/env bash
2
+ # exe-os stack first-time setup — run once on a fresh VPS.
3
+ # Usage: ./setup.sh --client <name> --domain <domain> [--license <key>]
4
+ set -euo pipefail
5
+
6
+ RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
7
+ info() { echo -e "${GREEN}[setup]${NC} $1"; }
8
+ warn() { echo -e "${YELLOW}[setup]${NC} $1"; }
9
+ err() { echo -e "${RED}[setup]${NC} $1" >&2; }
10
+
11
+ # Parse args
12
+ CLIENT="" DOMAIN="" LICENSE=""
13
+ while [[ $# -gt 0 ]]; do
14
+ case $1 in
15
+ --client) CLIENT="$2"; shift 2;;
16
+ --domain) DOMAIN="$2"; shift 2;;
17
+ --license) LICENSE="$2"; shift 2;;
18
+ *) err "Unknown arg: $1"; exit 1;;
19
+ esac
20
+ done
21
+ [[ -z "$CLIENT" || -z "$DOMAIN" ]] && { err "Usage: ./setup.sh --client <name> --domain <domain>"; exit 1; }
22
+
23
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
24
+ cd "$SCRIPT_DIR"
25
+
26
+ # Step 1: Docker + GHCR auth
27
+ info "Step 1: Docker registry authentication"
28
+ if ! docker info >/dev/null 2>&1; then
29
+ err "Docker is not running. Install Docker first: https://docs.docker.com/engine/install/"
30
+ exit 1
31
+ fi
32
+
33
+ if [[ -f .ghcr-token ]]; then
34
+ info "Logging into GHCR with stored token..."
35
+ cat .ghcr-token | docker login ghcr.io -u exe-os-pull --password-stdin 2>/dev/null || true
36
+ elif [[ -n "${GHCR_TOKEN:-}" ]]; then
37
+ info "Logging into GHCR with GHCR_TOKEN env var..."
38
+ echo "$GHCR_TOKEN" | docker login ghcr.io -u exe-os-pull --password-stdin 2>/dev/null || true
39
+ else
40
+ warn "No GHCR token found. Set GHCR_TOKEN env var or create .ghcr-token file."
41
+ warn "Images must be pullable — public or pre-authed."
42
+ fi
43
+
44
+ # Step 2: Generate .env
45
+ info "Step 2: Generating .env file"
46
+ if [[ -f .env ]]; then
47
+ warn ".env already exists — skipping generation. Delete .env to regenerate."
48
+ else
49
+ if command -v node >/dev/null 2>&1; then
50
+ node -e "
51
+ const { generateEnv } = require('../../dist/deploy/compose/generate-env.js');
52
+ console.log(generateEnv({ clientName: '$CLIENT', domain: '$DOMAIN', licenseKey: '${LICENSE:-}' || undefined }));
53
+ " > .env 2>/dev/null || {
54
+ # Fallback: generate inline
55
+ info "Generating secrets inline..."
56
+ gen() { openssl rand -hex "$1"; }
57
+ cat > .env << ENVEOF
58
+ POSTGRES_USER=exe
59
+ POSTGRES_PASSWORD=$(gen 32)
60
+ POSTGRES_DB=exedb
61
+ CLICKHOUSE_DB=default
62
+ CLICKHOUSE_USER=exe
63
+ CLICKHOUSE_PASSWORD=$(gen 32)
64
+ REDIS_PASSWORD=$(gen 32)
65
+ GOTRUE_JWT_SECRET=$(gen 48)
66
+ GOTRUE_SITE_URL=https://crm.${DOMAIN}
67
+ GOTRUE_EXTERNAL_URL=https://auth.${DOMAIN}
68
+ GOTRUE_DISABLE_SIGNUP=false
69
+ GOTRUE_MAILER_AUTOCONFIRM=true
70
+ CRM_IMAGE_TAG=ghcr.io/askexe/exe-crm:v0.9.3
71
+ CRM_SERVER_URL=https://crm.${DOMAIN}
72
+ CRM_APP_SECRET=$(gen 48)
73
+ EXE_CRM_ADMIN_TOKEN=$(gen 48)
74
+ CRM_HOST_PORT=3000
75
+ WIKI_IMAGE_TAG=ghcr.io/askexe/exe-wiki:v0.9.4
76
+ WIKI_DB_SCHEMA=wiki
77
+ WIKI_VECTOR_DB=postgres
78
+ WIKI_AUTH_TOKEN=$(gen 48)
79
+ EXE_WIKI_ADMIN_TOKEN=$(gen 48)
80
+ WIKI_JWT_SECRET=$(gen 48)
81
+ WIKI_SIG_KEY=$(gen 48)
82
+ WIKI_SIG_SALT=$(gen 16)
83
+ WIKI_HOST_PORT=3001
84
+ EXE_OS_IMAGE_TAG=ghcr.io/askexe/exe-os:v0.9.155
85
+ EXED_MCP_TOKEN=$(gen 48)
86
+ EXED_DEVICE_ID=vps-${CLIENT}
87
+ EXE_CLOUD_SYNC_TO_POSTGRES=true
88
+ EXE_LICENSE_KEY=${LICENSE:-CHANGEME_EXE_LICENSE_KEY}
89
+ GATEWAY_IMAGE_TAG=ghcr.io/askexe/exe-gateway:v0.9.3
90
+ EXE_GATEWAY_AUTH_TOKEN=$(gen 48)
91
+ EXE_GATEWAY_WS_RELAY_AUTH_TOKEN=$(gen 48)
92
+ EXE_GATEWAY_WHATSAPP_VERIFY_TOKEN=$(gen 32)
93
+ API_ROUTER_URL=https://gateway.${DOMAIN}
94
+ GATEWAY_HTTP_HOST_PORT=3100
95
+ GATEWAY_WS_HOST_PORT=3101
96
+ MONITOR_HUB_IMAGE_TAG=ghcr.io/askexe/exe-monitor-hub:v0.9.4
97
+ MONITOR_AGENT_IMAGE_TAG=ghcr.io/askexe/exe-monitor-agent:v0.9.4
98
+ EXE_MONITOR_ADMIN_TOKEN=$(gen 48)
99
+ MONITOR_HUB_URL=https://monitor.${DOMAIN}
100
+ MONITOR_AGENT_TOKEN=CHANGEME_MONITOR_AGENT_TOKEN
101
+ MONITOR_AGENT_KEY=CHANGEME_MONITOR_AGENT_KEY
102
+ MONITOR_AGENT_LISTEN=:45876
103
+ MONITOR_HUB_PORT=8090
104
+ ENVEOF
105
+ }
106
+ fi
107
+ info ".env generated with auto-generated secrets"
108
+ fi
109
+
110
+ # Step 3: Cloudflared tunnel config
111
+ info "Step 3: Cloudflare Tunnel setup"
112
+ if [[ ! -f cloudflared/config.yml ]]; then
113
+ if [[ -f cloudflared/config.yml.example ]]; then
114
+ warn "Copy cloudflared/config.yml.example → cloudflared/config.yml"
115
+ warn "Then set TUNNEL_ID and DOMAIN in the config."
116
+ warn "Create tunnel: cloudflared tunnel create exe-${CLIENT}"
117
+ fi
118
+ else
119
+ info "Cloudflared config exists."
120
+ fi
121
+
122
+ # Step 4: Pull images
123
+ info "Step 4: Pulling Docker images..."
124
+ docker compose pull 2>&1 || { err "Image pull failed — check GHCR authentication"; exit 1; }
125
+
126
+ # Step 5: Start stack
127
+ info "Step 5: Starting stack..."
128
+ docker compose up -d 2>&1
129
+
130
+ # Step 6: Wait for health
131
+ info "Step 6: Waiting for services to be healthy..."
132
+ sleep 10
133
+ HEALTHY=0
134
+ for i in $(seq 1 30); do
135
+ COUNT=$(docker ps --filter "health=healthy" --format '{{.Names}}' | wc -l | tr -d ' ')
136
+ TOTAL=$(docker ps --format '{{.Names}}' | wc -l | tr -d ' ')
137
+ echo -ne "\r $COUNT/$TOTAL healthy (attempt $i/30)..."
138
+ if [[ "$COUNT" -ge "$TOTAL" ]]; then HEALTHY=1; break; fi
139
+ sleep 5
140
+ done
141
+ echo ""
142
+ [[ "$HEALTHY" -eq 1 ]] && info "All services healthy!" || warn "Some services not healthy yet — check docker ps"
143
+
144
+ # Step 7: Verify
145
+ info "Step 7: Verification"
146
+ docker ps --format 'table {{.Names}}\t{{.Status}}'
147
+ echo ""
148
+ info "Stack deployed! Next steps:"
149
+ echo " 1. Configure Cloudflare tunnel (if not done)"
150
+ echo " 2. Open https://crm.${DOMAIN} to create admin account"
151
+ echo " 3. Open https://wiki.${DOMAIN} to set up wiki"
152
+ echo " 4. Configure WhatsApp: edit gateway.json, restart gateway, pair at https://gateway.${DOMAIN}/pair/<name>"
153
+ echo " 5. Verify: curl https://crm.${DOMAIN}/healthz && curl https://wiki.${DOMAIN}/api/ping"
154
+
155
+ # Step 8: Firewall — ensure outbound HTTPS is open
156
+ info "Step 8: Checking network connectivity..."
157
+ if curl -s --max-time 5 https://ghcr.io >/dev/null 2>&1; then
158
+ info "Outbound HTTPS working (GHCR reachable)"
159
+ else
160
+ warn "Cannot reach ghcr.io — check firewall/network. Docker pulls will fail."
161
+ fi
162
+ if curl -s --max-time 5 https://api.cloudflare.com >/dev/null 2>&1; then
163
+ info "Cloudflare reachable"
164
+ else
165
+ warn "Cannot reach Cloudflare — tunnel won't work."
166
+ fi
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env bash
2
+ # exe-os stack health check — run anytime to verify all services.
3
+ set -euo pipefail
4
+
5
+ RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
6
+
7
+ echo "=== exe-os Stack Health ==="
8
+ echo ""
9
+
10
+ # Container status
11
+ echo "Containers:"
12
+ docker ps --format 'table {{.Names}}\t{{.Status}}' 2>/dev/null
13
+ echo ""
14
+
15
+ # Service health endpoints
16
+ echo "Service Endpoints:"
17
+ DOMAIN="${1:-localhost}"
18
+ check() {
19
+ local name=$1 url=$2
20
+ CODE=$(curl -sk -o /dev/null -w "%{http_code}" --max-time 5 "$url" 2>/dev/null || echo "000")
21
+ if [[ "$CODE" == "200" ]]; then
22
+ echo -e " ${GREEN}✅${NC} $name ($CODE)"
23
+ elif [[ "$CODE" == "401" ]]; then
24
+ echo -e " ${YELLOW}🔒${NC} $name ($CODE — auth required, service is up)"
25
+ else
26
+ echo -e " ${RED}❌${NC} $name ($CODE)"
27
+ fi
28
+ }
29
+
30
+ check "CRM" "http://127.0.0.1:3000/healthz"
31
+ check "Wiki" "http://127.0.0.1:3001/api/ping"
32
+ check "Gateway" "http://127.0.0.1:3100/health"
33
+ check "Monitor" "http://127.0.0.1:8090/api/health"
34
+ check "GoTrue" "http://127.0.0.1:9999/health"
35
+ check "exe-os" "http://127.0.0.1:8765/health"
36
+
37
+ echo ""
38
+
39
+ # Database
40
+ echo "Database:"
41
+ docker exec exe-db psql -U exe -d exedb -c "SELECT schemaname, COUNT(*) as tables FROM pg_tables WHERE schemaname NOT IN ('pg_catalog','information_schema') GROUP BY schemaname ORDER BY schemaname;" 2>/dev/null || echo " ❌ Cannot connect to database"
42
+
43
+ echo ""
44
+
45
+ # Disk/Memory
46
+ echo "Resources:"
47
+ echo " RAM: $(free -h 2>/dev/null | awk '/^Mem:/ {print $3 "/" $2}' || echo 'N/A')"
48
+ echo " Disk: $(df -h / 2>/dev/null | awk 'NR==2 {print $3 "/" $2 " (" $5 " used)"}' || echo 'N/A')"
@@ -508,11 +508,36 @@ async function runStackUpdate(options) {
508
508
  return { status: "planned", targetVersion: plan.targetVersion, changes: plan.changes, lockFile };
509
509
  }
510
510
  await postDeployAudit(options, "started", plan.targetVersion, previousVersion);
511
- const backupDir = path.join(path.dirname(options.envFile), ".exe-stack-backups");
511
+ const stackDir = path.dirname(options.envFile);
512
+ const backupDir = path.join(stackDir, ".exe-stack-backups");
512
513
  mkdirSync(backupDir, { recursive: true });
513
514
  const stamp = now().toISOString().replace(/[:.]/g, "-");
514
- const backupEnvFile = path.join(backupDir, `env-${stamp}.bak`);
515
+ const updateBackupDir = path.join(backupDir, `pre-update-${stamp}`);
516
+ mkdirSync(updateBackupDir, { recursive: true });
517
+ const backupEnvFile = path.join(updateBackupDir, "env.bak");
515
518
  writeFileSync(backupEnvFile, envRaw, { mode: 384 });
519
+ const protectedFiles = ["gateway.json", "branding.json"];
520
+ for (const f of protectedFiles) {
521
+ const src = path.join(stackDir, f);
522
+ try {
523
+ if (existsSync(src)) {
524
+ copyFileSync(src, path.join(updateBackupDir, f));
525
+ }
526
+ } catch {
527
+ }
528
+ }
529
+ const cfDir = path.join(stackDir, "cloudflared");
530
+ try {
531
+ if (existsSync(cfDir)) {
532
+ const cfBackup = path.join(updateBackupDir, "cloudflared");
533
+ mkdirSync(cfBackup, { recursive: true });
534
+ for (const f of readdirSync(cfDir)) {
535
+ copyFileSync(path.join(cfDir, f), path.join(cfBackup, f));
536
+ }
537
+ }
538
+ } catch {
539
+ }
540
+ console.log(`[stack-update] Config backed up to ${updateBackupDir}`);
516
541
  const updates = Object.fromEntries(plan.changes.map((c) => [c.key, c.after]));
517
542
  const patched = patchEnv(envRaw, updates);
518
543
  const tmp = `${options.envFile}.tmp-${process.pid}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askexenow/exe-os",
3
- "version": "0.9.155",
3
+ "version": "0.9.157",
4
4
  "description": "AI employee operating system — persistent memory, task management, and multi-agent coordination for Claude Code.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",
@@ -1,10 +1,12 @@
1
1
  {
2
- "current": "0.9.155",
2
+ "current": "0.9.157",
3
3
  "notes": {
4
- "0.9.155": {
5
- "version": "0.9.155",
4
+ "0.9.157": {
5
+ "version": "0.9.157",
6
6
  "date": "2026-05-28",
7
7
  "features": [
8
+ "update safety + portable backups + restore",
9
+ "complete deployment readiness — all 14 second-pass blind spots fixed",
8
10
  "production-ready stack — all 15 blind spots fixed",
9
11
  "blocked task notification — ping dispatcher immediately on status change",
10
12
  "self-improving skills — usage tracking, success counting, and refinement daemon",
@@ -27,9 +29,7 @@
27
29
  "device-scoped behaviors — add device_id column + filter on load",
28
30
  "gateway prompt injection defense — 3-tier security hardening",
29
31
  "add diagnostics(action=\"merge_agent_memories\") for reassigning memories across agent IDs",
30
- "add task dependency tree visualization (action=dependency_tree)",
31
- "graceful COO auto-relaunch after context-full exit",
32
- "desktop push notifications on task completion (macOS/Linux)"
32
+ "add task dependency tree visualization (action=dependency_tree)"
33
33
  ],
34
34
  "fixes": [
35
35
  "add scope import to prompt-submit — gate pass",
@@ -104,10 +104,13 @@
104
104
  "exe-daemon.ts kills old embed.pid process and cleans up"
105
105
  ]
106
106
  },
107
- "0.9.154": {
108
- "version": "0.9.154",
107
+ "0.9.156": {
108
+ "version": "0.9.156",
109
109
  "date": "2026-05-28",
110
110
  "features": [
111
+ "complete deployment readiness — all 14 second-pass blind spots fixed",
112
+ "production-ready stack — all 15 blind spots fixed",
113
+ "blocked task notification — ping dispatcher immediately on status change",
111
114
  "self-improving skills — usage tracking, success counting, and refinement daemon",
112
115
  "4 retrieval improvements — query expansion, stop words, contradiction resolution, abstention",
113
116
  "competitive roadmap — serverless tier, identity depth, self-improving skills, user modeling",
@@ -129,12 +132,13 @@
129
132
  "gateway prompt injection defense — 3-tier security hardening",
130
133
  "add diagnostics(action=\"merge_agent_memories\") for reassigning memories across agent IDs",
131
134
  "add task dependency tree visualization (action=dependency_tree)",
132
- "graceful COO auto-relaunch after context-full exit",
133
- "desktop push notifications on task completion (macOS/Linux)",
134
- "rename GHCR image exed → exe-os across all deploy/stack references",
135
- "passive daemon-restart detection — agents get one-time /mcp notice"
135
+ "graceful COO auto-relaunch after context-full exit"
136
136
  ],
137
137
  "fixes": [
138
+ "add scope import to prompt-submit — gate pass",
139
+ "add writeFileSync import to config.ts",
140
+ "persist cloud endpoint migration to config.json — stop logging on every boot",
141
+ "include memory_type in pushToPostgres metadata — was stripped on sync",
138
142
  "add scope import to daemon-orchestration — satisfies customer-readiness gate",
139
143
  "skill-refinement.ts — correct writeMemory field names + updateIdentity 3rd arg",
140
144
  "make skill lifecycle fields optional on Behavior interface — unblocks publish",
@@ -155,11 +159,7 @@
155
159
  "close remaining session-scoping findings from Bob's audit",
156
160
  "close 3 more session-scoping leaks from Bob's audit (LEAK-4, LEAK-7, LEAK-8)",
157
161
  "diagnostics check_update ENOENT + healthcheck timeout",
158
- "close 8 session-scoping leaks — daemon ALS trust + review cleanup + close-task + inbox",
159
- "correct graph column names in federated recall query",
160
- "review notifications never reached reviewer — signal file gate was dead code",
161
- "remove osascript fallback — desktop notifications use OSC 9 only on macOS",
162
- "generate valid UUIDs in projection worker stableId + add wiki.* projection"
162
+ "close 8 session-scoping leaks — daemon ALS trust + review cleanup + close-task + inbox"
163
163
  ],
164
164
  "security": [
165
165
  "fix shell injection, SSRF, socket leaks, backup validation",
@@ -176,6 +176,8 @@
176
176
  "fix 4 pricing tier bypass vulnerabilities (audit F1-F4)"
177
177
  ],
178
178
  "other": [
179
+ "rename memory schema → graph across codebase",
180
+ "unified access control — admin token + GoTrue across all services",
179
181
  "capture data pipeline spec — raw → filter → wiki + CRM projection",
180
182
  "bump to v0.9.149 — task lifecycle simplification + review notification fix",
181
183
  "capture gateway connection observability requirements (2026-05-28)",
@@ -198,19 +200,20 @@
198
200
  "v0.9.140 publish + heap cap 4GB (was 33% unbounded)",
199
201
  "PG-1 cross-repo entity federation design document",
200
202
  "add lint step + automated npm publish workflow",
201
- "audit: scoped SQL + package budget + TUI vendored + TODO classification",
202
- "add full readiness audit evidence",
203
- "roadmap: Cross-Repo Ontology — Palantir-level graph (PG-1 through PG-10)"
203
+ "audit: scoped SQL + package budget + TUI vendored + TODO classification"
204
204
  ],
205
205
  "migration_notes": [
206
206
  "If daemon goes down, agents will now fail instead of silently",
207
207
  "exe-daemon.ts kills old embed.pid process and cleans up"
208
208
  ]
209
209
  },
210
- "0.9.153": {
211
- "version": "0.9.153",
210
+ "0.9.155": {
211
+ "version": "0.9.155",
212
212
  "date": "2026-05-28",
213
213
  "features": [
214
+ "production-ready stack — all 15 blind spots fixed",
215
+ "blocked task notification — ping dispatcher immediately on status change",
216
+ "self-improving skills — usage tracking, success counting, and refinement daemon",
214
217
  "4 retrieval improvements — query expansion, stop words, contradiction resolution, abstention",
215
218
  "competitive roadmap — serverless tier, identity depth, self-improving skills, user modeling",
216
219
  "run database migrations before container swap in stack-update",
@@ -232,12 +235,18 @@
232
235
  "add diagnostics(action=\"merge_agent_memories\") for reassigning memories across agent IDs",
233
236
  "add task dependency tree visualization (action=dependency_tree)",
234
237
  "graceful COO auto-relaunch after context-full exit",
235
- "desktop push notifications on task completion (macOS/Linux)",
236
- "rename GHCR image exed → exe-os across all deploy/stack references",
237
- "passive daemon-restart detection — agents get one-time /mcp notice",
238
- "daemon restart orchestrator — single authority for all restart decisions"
238
+ "desktop push notifications on task completion (macOS/Linux)"
239
239
  ],
240
240
  "fixes": [
241
+ "add scope import to prompt-submit — gate pass",
242
+ "add writeFileSync import to config.ts",
243
+ "persist cloud endpoint migration to config.json — stop logging on every boot",
244
+ "include memory_type in pushToPostgres metadata — was stripped on sync",
245
+ "add scope import to daemon-orchestration — satisfies customer-readiness gate",
246
+ "skill-refinement.ts — correct writeMemory field names + updateIdentity 3rd arg",
247
+ "make skill lifecycle fields optional on Behavior interface — unblocks publish",
248
+ "session isolation for tmux kill — block cross-scope session kills",
249
+ "session-scope daemon, push, capacity, and cleanup (P0 #7-#13)",
241
250
  "add memory_type to crdt-sync MemoryRecord interface — unblocks publish",
242
251
  "session-scope daemon, push, capacity, cleanup (P0 #7-#9, #13)",
243
252
  "include memory_type in cloud sync push/pull + fix backfill re-sync",
@@ -252,17 +261,8 @@
252
261
  "add shipped_version to support triage + clean platform procedures",
253
262
  "close remaining session-scoping findings from Bob's audit",
254
263
  "close 3 more session-scoping leaks from Bob's audit (LEAK-4, LEAK-7, LEAK-8)",
255
- "close 8 session-scoping leaks — daemon ALS trust + review cleanup + close-task + inbox",
256
- "correct graph column names in federated recall query",
257
264
  "diagnostics check_update ENOENT + healthcheck timeout",
258
- "review notifications never reached reviewer signal file gate was dead code",
259
- "remove osascript fallback — desktop notifications use OSC 9 only on macOS",
260
- "generate valid UUIDs in projection worker stableId + add wiki.* projection",
261
- "RSS backpressure + safe Metal shutdown for embedding daemon OOM",
262
- "multi-Tom dispatch — per-task signal files + atomic claim + herd prevention",
263
- "restrict project_name='all' to coordinators only in list_tasks",
264
- "CRM Dockerfile multi-arch — BUILDPLATFORM for build stages, rebuild bcrypt",
265
- "enhance intercom log with caller/task/trigger metadata for tracing"
265
+ "close 8 session-scoping leaksdaemon ALS trust + review cleanup + close-task + inbox"
266
266
  ],
267
267
  "security": [
268
268
  "fix shell injection, SSRF, socket leaks, backup validation",
@@ -279,6 +279,8 @@
279
279
  "fix 4 pricing tier bypass vulnerabilities (audit F1-F4)"
280
280
  ],
281
281
  "other": [
282
+ "rename memory schema → graph across codebase",
283
+ "unified access control — admin token + GoTrue across all services",
282
284
  "capture data pipeline spec — raw → filter → wiki + CRM projection",
283
285
  "bump to v0.9.149 — task lifecycle simplification + review notification fix",
284
286
  "capture gateway connection observability requirements (2026-05-28)",
@@ -301,19 +303,20 @@
301
303
  "v0.9.140 publish + heap cap 4GB (was 33% unbounded)",
302
304
  "PG-1 cross-repo entity federation design document",
303
305
  "add lint step + automated npm publish workflow",
304
- "audit: scoped SQL + package budget + TUI vendored + TODO classification",
305
- "add full readiness audit evidence",
306
- "roadmap: Cross-Repo Ontology — Palantir-level graph (PG-1 through PG-10)"
306
+ "audit: scoped SQL + package budget + TUI vendored + TODO classification"
307
307
  ],
308
308
  "migration_notes": [
309
309
  "If daemon goes down, agents will now fail instead of silently",
310
310
  "exe-daemon.ts kills old embed.pid process and cleans up"
311
311
  ]
312
312
  },
313
- "0.9.150": {
314
- "version": "0.9.150",
313
+ "0.9.154": {
314
+ "version": "0.9.154",
315
315
  "date": "2026-05-28",
316
316
  "features": [
317
+ "self-improving skills — usage tracking, success counting, and refinement daemon",
318
+ "4 retrieval improvements — query expansion, stop words, contradiction resolution, abstention",
319
+ "competitive roadmap — serverless tier, identity depth, self-improving skills, user modeling",
317
320
  "run database migrations before container swap in stack-update",
318
321
  "graph auto-extract from ARCHITECTURE.md — regex-based entity/relationship extraction",
319
322
  "migrate cloud.askexe.com → api.askexe.com as canonical endpoint",
@@ -335,12 +338,21 @@
335
338
  "graceful COO auto-relaunch after context-full exit",
336
339
  "desktop push notifications on task completion (macOS/Linux)",
337
340
  "rename GHCR image exed → exe-os across all deploy/stack references",
338
- "passive daemon-restart detection — agents get one-time /mcp notice",
339
- "daemon restart orchestrator — single authority for all restart decisions",
340
- "query router cache tuning + cross-session tasks + shared skills",
341
- "socket health probe + tmux env guard + reviewer queue fallback (features 1, 2)"
341
+ "passive daemon-restart detection — agents get one-time /mcp notice"
342
342
  ],
343
343
  "fixes": [
344
+ "add scope import to daemon-orchestration — satisfies customer-readiness gate",
345
+ "skill-refinement.ts — correct writeMemory field names + updateIdentity 3rd arg",
346
+ "make skill lifecycle fields optional on Behavior interface — unblocks publish",
347
+ "session isolation for tmux kill — block cross-scope session kills",
348
+ "session-scope daemon, push, capacity, and cleanup (P0 #7-#13)",
349
+ "add memory_type to crdt-sync MemoryRecord interface — unblocks publish",
350
+ "session-scope daemon, push, capacity, cleanup (P0 #7-#9, #13)",
351
+ "include memory_type in cloud sync push/pull + fix backfill re-sync",
352
+ "session-scope signal file system — prevent cross-session task/review bleed",
353
+ "session-scope notification routing — use row.session_scope over ambient",
354
+ "daemon NEVER guesses session from tmux — header-only routing",
355
+ "3 daemon bugs — context-full TTL override, API watchdog kill-after-3, idle-kill verify",
344
356
  "federated recall always searches code_context + graph — count threshold was useless",
345
357
  "make cross-repo guardrail task-aware — allow multi-repo work when task scope permits",
346
358
  "ONE postgres — replace crm-postgres with exe-db across entire stack",
@@ -348,24 +360,12 @@
348
360
  "add shipped_version to support triage + clean platform procedures",
349
361
  "close remaining session-scoping findings from Bob's audit",
350
362
  "close 3 more session-scoping leaks from Bob's audit (LEAK-4, LEAK-7, LEAK-8)",
363
+ "diagnostics check_update ENOENT + healthcheck timeout",
351
364
  "close 8 session-scoping leaks — daemon ALS trust + review cleanup + close-task + inbox",
352
365
  "correct graph column names in federated recall query",
353
- "diagnostics check_update ENOENT + healthcheck timeout",
354
366
  "review notifications never reached reviewer — signal file gate was dead code",
355
367
  "remove osascript fallback — desktop notifications use OSC 9 only on macOS",
356
- "generate valid UUIDs in projection worker stableId + add wiki.* projection",
357
- "RSS backpressure + safe Metal shutdown for embedding daemon OOM",
358
- "multi-Tom dispatch — per-task signal files + atomic claim + herd prevention",
359
- "restrict project_name='all' to coordinators only in list_tasks",
360
- "CRM Dockerfile multi-arch — BUILDPLATFORM for build stages, rebuild bcrypt",
361
- "enhance intercom log with caller/task/trigger metadata for tracing",
362
- "project-scope review queries — no more cross-project review pollution",
363
- "remove unused getActiveAgent import in list-tasks",
364
- "project-scope ALL task queries — prevents cross-project pollution",
365
- "hash-based cloud pull conflict detection + indentation-aware Python/Rust chunker",
366
- "add sessionScopeFilter to worker-gate + create-task queries",
367
- "replace require() with ESM import in shouldAutoInstance",
368
- "intercom-check passes project_name to scanFromDb — prevents cross-project task pollution"
368
+ "generate valid UUIDs in projection worker stableId + add wiki.* projection"
369
369
  ],
370
370
  "security": [
371
371
  "fix shell injection, SSRF, socket leaks, backup validation",
@@ -382,6 +382,7 @@
382
382
  "fix 4 pricing tier bypass vulnerabilities (audit F1-F4)"
383
383
  ],
384
384
  "other": [
385
+ "capture data pipeline spec — raw → filter → wiki + CRM projection",
385
386
  "bump to v0.9.149 — task lifecycle simplification + review notification fix",
386
387
  "capture gateway connection observability requirements (2026-05-28)",
387
388
  "bump to v0.9.146 for publish",
@@ -405,70 +406,69 @@
405
406
  "add lint step + automated npm publish workflow",
406
407
  "audit: scoped SQL + package budget + TUI vendored + TODO classification",
407
408
  "add full readiness audit evidence",
408
- "roadmap: Cross-Repo Ontology — Palantir-level graph (PG-1 through PG-10)",
409
- "capture mcp restart self-healing roadmap"
409
+ "roadmap: Cross-Repo Ontology — Palantir-level graph (PG-1 through PG-10)"
410
410
  ],
411
411
  "migration_notes": [
412
412
  "If daemon goes down, agents will now fail instead of silently",
413
413
  "exe-daemon.ts kills old embed.pid process and cleans up"
414
414
  ]
415
415
  },
416
- "0.9.144": {
417
- "version": "0.9.144",
418
- "date": "2026-05-26",
416
+ "0.9.153": {
417
+ "version": "0.9.153",
418
+ "date": "2026-05-28",
419
419
  "features": [
420
- "close_task auto-merges PR + pulls main + builds + prunes + respawns",
421
- "auto-respawn Tom after close_task if more tasks queued",
422
- "message WAL fallback messages survive daemon downtime",
423
- "entity type hierarchysubtypes with rollup queries (PG-2)",
424
- "temporal validity windows for graph queries (PG-3)",
425
- "backup restore CLI + restoreBackup function",
426
- "ESLint setup + dependency hygiene + any type reduction",
427
- "config(action=\"hire\") MCP toolCOO can hire employees directly",
428
- "GM (General Manager) role template + hiring guidance",
429
- "merge gate warning in close_task catches unmerged PRs",
430
- "behavior hygieneplatform procedure + COO identity + company procedure",
431
- "MCP auto-reconnect to daemon survives deploy restarts transparently",
432
- "event-driven notifications stop polling managers, let task state drive everything",
433
- "MCP disconnect tracker + daemon observability",
434
- "MCP lifecycle logging to file FULL transparency on every disconnect",
435
- "automatic P0 bug fixing daemon auto-dispatch + GitHub Actions fallback",
436
- "enforce worktrees for engineer sessions prevent direct main commits",
437
- "multi-device coordinationrouting, handoff, device status",
438
- "hook tamper protection SHA-256 manifest + verification before spawn",
439
- "governed collaborative memory visibility tags + write governance",
440
- "cache-sharing protocol pub/sub memory bus for inter-agent sharing",
441
- "multi-modal memory media attachments on memories",
442
- "comprehensive \"last 20%\" integration tests + audit_trail read path",
443
- "wire memory poisoning defense into writeMemory() pipeline",
444
- "memory poisoning defensetrust levels, anomaly detection, quarantine"
420
+ "4 retrieval improvements query expansion, stop words, contradiction resolution, abstention",
421
+ "competitive roadmap serverless tier, identity depth, self-improving skills, user modeling",
422
+ "run database migrations before container swap in stack-update",
423
+ "graph auto-extract from ARCHITECTURE.md regex-based entity/relationship extraction",
424
+ "migrate cloud.askexe.com api.askexe.com as canonical endpoint",
425
+ "federated recall code_context + graph fallback when memory results weak",
426
+ "migrate cloud.askexe.com api.askexe.com across all src/ defaults",
427
+ "rolling restart in stack-update one service at a time with health verification",
428
+ "DMR benchmark harness + LoCoMo improvements for v0.9.145 evaluation",
429
+ "Windows/WSL support WezTerm config + WSL detection in setup wizard",
430
+ "queryTaskRows() consolidationsingle scoped query path for all task list operations",
431
+ "review signal filesreliable reviewer notification on update_task(done)",
432
+ "Ghostty-native notifications via OSC 9 no more Script Editor popup",
433
+ "device-scoped behaviors device_id column + filter in loading",
434
+ "dispatch reliability 45s boot timeout, dispatch ack signals, agent heartbeat",
435
+ "setup wizard headless mode + daemon health check after restart",
436
+ "device-scoped behaviors add device_id column + filter on load",
437
+ "gateway prompt injection defense 3-tier security hardening",
438
+ "add diagnostics(action=\"merge_agent_memories\") for reassigning memories across agent IDs",
439
+ "add task dependency tree visualization (action=dependency_tree)",
440
+ "graceful COO auto-relaunch after context-full exit",
441
+ "desktop push notifications on task completion (macOS/Linux)",
442
+ "rename GHCR image exed exe-os across all deploy/stack references",
443
+ "passive daemon-restart detection agents get one-time /mcp notice",
444
+ "daemon restart orchestratorsingle authority for all restart decisions"
445
445
  ],
446
446
  "fixes": [
447
- "remove unused test imports blocking publish",
448
- "resolve all typecheck errors await-in-sync + type mismatches",
449
- "remaining require() ESM imports in daemon (db-backup, intercom, shutdown)",
450
- "eliminate CJS require() from ESM daemon + reliable task signal delivery",
451
- "migrate critical writeFileSync to atomicWrite prevent corruption on crash (Track C)",
452
- "security hardening SQL injection lint + TUI input sanitize + MCP rate limiter (Track D)",
453
- "clear public launch readiness blockers",
454
- "prune old worktree on close_task before respawning fresh",
455
- "exe-launch-agent resolves multi-instance names tom2/tom3 no longer rejected",
456
- "worktree isolation for all runtimes + token budget enforcement + atomic memory versioning",
457
- "cross-device sync dedup cooldown key prevents duplicate pushes",
458
- "merge gate checks branch name not git author — was silently passing",
459
- "resume_employee uses autoInstance spawns tom2/tom3 for parallel",
460
- "security hardening fail-closed behavior auth gates",
461
- "send_message intercom uses force:truebypass 5-min debounce",
462
- "global session cap 10→50 match MCP session cap",
463
- "/exe-call ALWAYS fires + tmux send-keys blocked for ALL agents",
464
- "SIGTERM graceful shutdownremove process.exit(0) from initMetrics",
465
- "stale task escalationsurface alive-but-stalled agents to COO",
466
- "cloud sync upsert + entity type hierarchy + temporal validity + file_copy security",
467
- "daemon memory leak + duplicate watchdog + HTTP body limit + WAL flush",
468
- "heap pressure alarm was false positive compared heapUsed/heapTotal instead of heapUsed/heapLimit",
469
- "strengthen scoped SQL audit cover UPDATE/INSERT, expand exemptions",
470
- "hard block tmux send-keys for non-coordinator agents",
471
- "MCP disconnect procedure explicitly block tmux send-keys workaround"
447
+ "add memory_type to crdt-sync MemoryRecord interface — unblocks publish",
448
+ "session-scope daemon, push, capacity, cleanup (P0 #7-#9, #13)",
449
+ "include memory_type in cloud sync push/pull + fix backfill re-sync",
450
+ "session-scope signal file system prevent cross-session task/review bleed",
451
+ "session-scope notification routinguse row.session_scope over ambient",
452
+ "daemon NEVER guesses session from tmux header-only routing",
453
+ "3 daemon bugs context-full TTL override, API watchdog kill-after-3, idle-kill verify",
454
+ "federated recall always searches code_context + graph — count threshold was useless",
455
+ "make cross-repo guardrail task-aware allow multi-repo work when task scope permits",
456
+ "ONE postgres replace crm-postgres with exe-db across entire stack",
457
+ "smart session-scoping gate + last boot cleanup leak + triage_bug docs",
458
+ "add shipped_version to support triage + clean platform procedures",
459
+ "close remaining session-scoping findings from Bob's audit",
460
+ "close 3 more session-scoping leaks from Bob's audit (LEAK-4, LEAK-7, LEAK-8)",
461
+ "close 8 session-scoping leaksdaemon ALS trust + review cleanup + close-task + inbox",
462
+ "correct graph column names in federated recall query",
463
+ "diagnostics check_update ENOENT + healthcheck timeout",
464
+ "review notifications never reached reviewer signal file gate was dead code",
465
+ "remove osascript fallbackdesktop notifications use OSC 9 only on macOS",
466
+ "generate valid UUIDs in projection worker stableId + add wiki.* projection",
467
+ "RSS backpressure + safe Metal shutdown for embedding daemon OOM",
468
+ "multi-Tom dispatch per-task signal files + atomic claim + herd prevention",
469
+ "restrict project_name='all' to coordinators only in list_tasks",
470
+ "CRM Dockerfile multi-arch — BUILDPLATFORM for build stages, rebuild bcrypt",
471
+ "enhance intercom log with caller/task/trigger metadata for tracing"
472
472
  ],
473
473
  "security": [
474
474
  "fix shell injection, SSRF, socket leaks, backup validation",
@@ -485,7 +485,18 @@
485
485
  "fix 4 pricing tier bypass vulnerabilities (audit F1-F4)"
486
486
  ],
487
487
  "other": [
488
+ "capture data pipeline spec — raw → filter → wiki + CRM projection",
489
+ "bump to v0.9.149 — task lifecycle simplification + review notification fix",
490
+ "capture gateway connection observability requirements (2026-05-28)",
491
+ "bump to v0.9.146 for publish",
492
+ "Windows support architecture — WezTerm + WSL decision (2026-05-27)",
493
+ "Merge branch 'tom4-work' — device-scoped behaviors + push-notification fix",
494
+ "bump to v0.9.145 for publish",
495
+ "revert: keep workflow files unchanged — GitHub OAuth blocks workflow scope",
496
+ "stage remaining Yoshi fixes — features + bug cleanup",
497
+ "add tests for daemon restart orchestrator module",
488
498
  "publish v0.9.144 — ESM require() fix + reliable task signals + OAuth 2.1",
499
+ "add MCP tool tests for message, cloud-sync, and file-copy",
489
500
  "add coverage for send_message, cloud_sync, file_copy MCP tools (Track A)",
490
501
  "Recover MCP sessions after daemon restart",
491
502
  "publish v0.9.143 — all fixes live",
@@ -498,18 +509,7 @@
498
509
  "add lint step + automated npm publish workflow",
499
510
  "audit: scoped SQL + package budget + TUI vendored + TODO classification",
500
511
  "add full readiness audit evidence",
501
- "roadmap: Cross-Repo Ontology — Palantir-level graph (PG-1 through PG-10)",
502
- "capture mcp restart self-healing roadmap",
503
- "Enforce chain of command task review parity",
504
- "document raw SQL fallback in orchestrator auto-approve path",
505
- "Finalize orchestration rollout fixes",
506
- "Scope device governance task queries",
507
- "bump v0.9.138 — 7 critical bug fixes, 10 features, 16 commits",
508
- "bump v0.9.137 — Memanto typed schema, push notifications, lazy consolidation",
509
- "bump v0.9.136 — daemon OOM fix, process monitor, auto-notify reviewer",
510
- "bump v0.9.135 — code debt cleanup, 28 new tests, full observability",
511
- "Codex MCP regression tests (18) + DB singleton integration tests (10)",
512
- "release notes for v0.9.134"
512
+ "roadmap: Cross-Repo Ontology — Palantir-level graph (PG-1 through PG-10)"
513
513
  ],
514
514
  "migration_notes": [
515
515
  "If daemon goes down, agents will now fail instead of silently",