-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathMakefile
More file actions
455 lines (410 loc) · 19.9 KB
/
Copy pathMakefile
File metadata and controls
455 lines (410 loc) · 19.9 KB
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
# agent-ways
# Top-level Makefile — build, install, and release.
#
# Quick start: make setup
# Full install: make install
# Update: make update
.DEFAULT_GOAL := help
.PHONY: setup install relink uninstall update update-binaries sync-to-home sync-to-home-link sync-to-home-test clean help deps ways ways-rebuild ways-audit ways-audit-rebuild attend attend-rebuild attend-chat attend-chat-rebuild hooks-install way-embed-rebuild lint test test-unit test-sim test-lang test-locales test-multilingual release purge-attend-state
ifeq ($(OS),Windows_NT)
SHELL := C:/Program Files/Git/usr/bin/bash.exe
.SHELLFLAGS := -c
LINK := cp -f
EXE := .exe
# Copy hooks/ways contents into ~/.claude/hooks/ways/ (no symlinks without Developer Mode)
INSTALL_HOOKS = mkdir -p "$(HOME)/.claude/hooks/ways" && cp -r "$(CURDIR)/hooks/ways/." "$(HOME)/.claude/hooks/ways/"
else
SHELL := bash
LINK := ln -sf
EXE :=
# Symlink hooks/ways into ~/.claude/hooks/ways
INSTALL_HOOKS = mkdir -p "$(HOME)/.claude/hooks" && ln -sf "$(CURDIR)/hooks/ways" "$(HOME)/.claude/hooks/ways"
endif
WAYS_BIN = bin/ways
WAYS_AUDIT_BIN = bin/ways-audit
ATTEND_BIN = bin/attend
ATTEND_CHAT_BIN = bin/attend-chat
WAY_EMBED_BIN = bin/way-embed
XDG_BIN = $(or $(XDG_BIN_HOME),$(HOME)/.local/bin)
CLAUDE_BIN = $(HOME)/.claude/bin
# --- Primary targets ---
help:
@echo "agent-ways"
@echo ""
@echo " make setup Build ways CLI + attend + fetch embedding model + corpus"
@echo " make install Full first-time setup (hooks + tools + PATH)"
@echo " make deps Install the C++ build toolchain (only if a prebuilt binary"
@echo " won't run on your platform and you must build from source)"
@echo " make update Pull + rebuild + relink in the app dir; then 'ways reconcile' to reproject"
@echo " make sync-to-home [legacy] ADR-140 subdirectory projection — superseded by 'ways reconcile'"
@echo " make sync-to-home-link [legacy] symlink variant of sync-to-home"
@echo " make ways Get ways binary (download or build from source)"
@echo " make ways-rebuild Force rebuild ways from source"
@echo " make ways-audit Get ways-audit compliance binary (download or build)"
@echo " make attend Build attend binary"
@echo " make attend-rebuild Force rebuild attend from source"
@echo " make lint Run clippy on Rust workspace (warnings = errors)"
@echo " make test Run all tests (lint + smoke + unit + sim + lang)"
@echo " make test-unit Run Rust unit tests"
@echo " make test-sim Run session simulator (8 scenarios)"
@echo " make test-lang Validate active language coverage"
@echo " make test-locales Check locale files for gaps and duplicates"
@echo " make test-multilingual Verify multilingual way matching (18 languages)"
@echo " make docs Regenerate docs/cli/attend.md from the clap definition"
@echo " make release Build release binary for current platform"
@echo " make cut-release Open a version-bump PR for a component (COMPONENT=ways LEVEL=patch)"
@echo " make publish-release After the bump PR merges: tag + publish (COMPONENT=ways [PUSH=1])"
@echo " make uninstall Remove ways from PATH"
@echo " make clean Remove build artifacts"
@echo " make purge-attend-state Wipe all attend runtime cache (peers, signals,"
@echo " channels, instance names, heartbeats, sensor"
@echo " checkpoints). Manual recovery only — never"
@echo " invoked by setup/install/update."
@echo ""
# Install the C++ build toolchain (cmake + compiler + git) needed to build
# way-embed from source, for platforms with no pre-built binary (or where the
# prebuilt won't launch). This is the ONLY target that installs system packages;
# it uses sudo where the platform requires it and lets the package manager prompt
# for confirmation. `make setup` never calls this — the user runs it explicitly.
deps:
@echo "Installing build toolchain (cmake, C++ compiler, git)."
@echo "This installs system packages — you'll be prompted to confirm."
@echo ""
@if command -v pacman >/dev/null 2>&1; then \
sudo pacman -S --needed cmake gcc git; \
elif command -v apt-get >/dev/null 2>&1; then \
sudo apt-get update && sudo apt-get install cmake g++ git; \
elif command -v dnf >/dev/null 2>&1; then \
sudo dnf install cmake gcc-c++ git; \
elif command -v zypper >/dev/null 2>&1; then \
sudo zypper install cmake gcc-c++ git; \
elif command -v brew >/dev/null 2>&1; then \
brew install cmake git; \
else \
echo "No supported package manager found (pacman/apt/dnf/zypper/brew)."; \
echo "Install manually: cmake, a C++ compiler (g++ or clang++), and git."; \
exit 1; \
fi
@echo ""
@echo "Toolchain ready. Now run: make setup"
# Build ways CLI + set up embedding engine + generate initial corpus.
setup: ways ways-audit attend attend-chat
@echo "Setting up embedding engine..."
@# Optional accelerator — if its build deps are missing, warn and continue so
@# the rest of install (incl. the PATH symlinks) still completes. Without it,
@# ways fall back to regex/keyword matching.
@$(MAKE) -C tools/way-embed setup || { \
echo ""; \
echo " ⚠ Embedding engine not built — semantic (meaning-based) matching is unavailable."; \
echo " Regex/keyword ways still work. To enable it, install the build toolchain"; \
echo " with 'make deps', then re-run 'make setup' (or use a platform with a prebuilt binary)."; \
}
@echo ""
@echo "Setting up mmaid diagram renderer..."
@bash tools/mmaid/download-mmaid.sh || echo " (mmaid optional — skipping)"
@echo ""
@echo "Generating corpus..."
@$(WAYS_BIN) corpus --quiet
# Idempotent (re)linking of the suite binaries onto PATH. Only links what exists
# in bin/, so it is safe to run before every binary is built and safe to re-run.
# Both `install` and `ways update` call this — that is what lets a binary NEWLY
# ADDED to the suite get its PATH symlink without a fresh `make install`. The
# suite binaries (ways, ways-audit, attend, attend-chat) link into $(XDG_BIN);
# way-embed lives in $(CLAUDE_BIN).
relink:
@mkdir -p "$(XDG_BIN)"
@for b in ways ways-audit attend attend-chat; do \
if [ -e "$(CURDIR)/bin/$$b" ]; then \
$(LINK) "$(CURDIR)/bin/$$b" "$(XDG_BIN)/$$b"; \
fi; \
done
@if [ -e "$(CURDIR)/$(WAY_EMBED_BIN)" ]; then \
mkdir -p "$(CLAUDE_BIN)"; \
if [ "$(CURDIR)/$(WAY_EMBED_BIN)" -ef "$(CLAUDE_BIN)/way-embed" ]; then :; \
else $(LINK) "$(CURDIR)/$(WAY_EMBED_BIN)" "$(CLAUDE_BIN)/way-embed"; fi; \
fi
# Full install: build, setup, symlink to PATH.
install: hooks-executable setup hooks-install
@$(MAKE) -s --no-print-directory relink
@echo ""
@echo "Install complete."
@echo " ways binary: $(XDG_BIN)/ways → $(CURDIR)/$(WAYS_BIN)"
@echo " ways-audit binary: $(XDG_BIN)/ways-audit → $(CURDIR)/$(WAYS_AUDIT_BIN)"
@echo " attend binary: $(XDG_BIN)/attend → $(CURDIR)/$(ATTEND_BIN)"
@echo " attend-chat binary: $(XDG_BIN)/attend-chat → $(CURDIR)/$(ATTEND_CHAT_BIN)"
@echo " way-embed binary: $(CLAUDE_BIN)/way-embed → $(CURDIR)/$(WAY_EMBED_BIN)"
@case ":$$PATH:" in \
*":$(XDG_BIN):"*) ;; \
*) printf '\n %s\n %s\n %s\n' \
"NOTE: $(XDG_BIN) is not on your PATH — ways/attend won't be found yet." \
"Add it to your shell rc (~/.bashrc or ~/.zshrc), then restart your shell:" \
" export PATH=\"$(XDG_BIN):\$$PATH\"" ;; \
esac
@echo " Restart Claude Code for ways to take effect."
hooks-install:
@$(INSTALL_HOOKS)
@echo "Hooks installed at $(HOME)/.claude/hooks/ways"
# Remove symlink from PATH.
uninstall:
@rm -f "$(XDG_BIN)/ways" "$(XDG_BIN)/ways-audit" "$(XDG_BIN)/attend" "$(XDG_BIN)/attend-chat"
@echo "Removed $(XDG_BIN)/ways $(XDG_BIN)/ways-audit $(XDG_BIN)/attend $(XDG_BIN)/attend-chat"
# Pull upstream and re-setup. scripts/update.sh wraps the pull so machine-local
# changes (settings.json, stale build artifacts) and merged branches don't abort
# the fast-forward — it autostashes, prunes, and surfaces conflicts instead of
# clobbering. See the script for recovery behavior.
update:
@bash scripts/update.sh
$(MAKE) update-binaries
$(MAKE) install
# Subdirectory topology (ADR-140): the repo lives in a subdir of ~/.claude and is
# projected up into it. Copy is the default (robust everywhere); the -link variant
# symlinks instead (git pull then becomes the whole update — no re-sync). Both
# delegate to the same deterministic script and run a smoke test of the merge.
sync-to-home:
@bash scripts/sync-to-home.sh
sync-to-home-link:
@SYNC_MODE=symlink bash scripts/sync-to-home.sh
sync-to-home-test:
@bash scripts/sync-to-home-test.sh
# Rebuild every binary `update` is responsible for refreshing.
# Indirected from `update:` so adding a new rebuild here takes effect
# on the same `make update` run that pulls the change — sub-makes
# re-read the Makefile, but the in-memory `update:` recipe is fixed at
# make-process startup.
update-binaries: ways-rebuild ways-audit-rebuild attend-rebuild attend-chat-rebuild way-embed-rebuild
# --- Build ---
# Get the ways binary: try existing → download → build from source.
ways:
@if [ -x $(WAYS_BIN) ] && $(WAYS_BIN) --version >/dev/null 2>&1; then \
echo "ways already installed: $$($(WAYS_BIN) --version)"; \
elif bash tools/ways-cli/download-ways.sh; then \
echo "Pre-built binary installed."; \
elif command -v cargo >/dev/null 2>&1; then \
echo "Pre-built unavailable (see above) — building from source..."; \
bash scripts/check-rust.sh || exit 1; \
cargo build --release --manifest-path tools/Cargo.toml -p ways; \
mkdir -p bin; \
$(LINK) "$(CURDIR)/tools/target/release/ways$(EXE)" $(WAYS_BIN); \
echo "Built: $(WAYS_BIN) ($$(ls -lh $(WAYS_BIN) | awk '{print $$5}'))"; \
else \
echo "error: No pre-built binary and cargo not found."; \
echo "Install Rust: https://rustup.rs/"; \
exit 1; \
fi
# Force rebuild from source (ignores existing binary and download).
ways-rebuild:
@if ! command -v cargo >/dev/null 2>&1; then \
echo "error: cargo not found. Install Rust: https://rustup.rs/"; \
exit 1; \
fi
@bash scripts/check-rust.sh
cargo build --release --manifest-path tools/Cargo.toml -p ways
@mkdir -p bin
@$(LINK) "$(CURDIR)/tools/target/release/ways$(EXE)" $(WAYS_BIN)
@echo "Built: $(WAYS_BIN) ($$(ls -lh $(WAYS_BIN) | awk '{print $$5}'))"
# Get the ways-audit compliance binary: try existing → download → build. A
# first-class member of the suite (installed and updated like the others); it is
# *deliberately-invoked* in the sense that you run `ways-audit` when you want it,
# not that it's optional to install.
ways-audit:
@if [ -x $(WAYS_AUDIT_BIN) ] && $(WAYS_AUDIT_BIN) --version >/dev/null 2>&1; then \
echo "ways-audit already installed: $$($(WAYS_AUDIT_BIN) --version)"; \
elif bash tools/ways-audit/download-ways-audit.sh; then \
echo "Pre-built ways-audit binary installed."; \
elif command -v cargo >/dev/null 2>&1; then \
echo "Pre-built unavailable (see above) — building ways-audit from source..."; \
bash scripts/check-rust.sh || exit 1; \
cargo build --release --manifest-path tools/Cargo.toml -p ways-audit; \
mkdir -p bin; \
$(LINK) "$(CURDIR)/tools/target/release/ways-audit$(EXE)" $(WAYS_AUDIT_BIN); \
echo "Built: $(WAYS_AUDIT_BIN) ($$(ls -lh $(WAYS_AUDIT_BIN) | awk '{print $$5}'))"; \
else \
echo "error: No pre-built binary and cargo not found."; \
echo "Install Rust: https://rustup.rs/"; \
exit 1; \
fi
# Force rebuild ways-audit from source (ignores existing binary and download).
ways-audit-rebuild:
@if ! command -v cargo >/dev/null 2>&1; then \
echo "error: cargo not found. Install Rust: https://rustup.rs/"; \
exit 1; \
fi
@bash scripts/check-rust.sh
cargo build --release --manifest-path tools/Cargo.toml -p ways-audit
@mkdir -p bin
@$(LINK) "$(CURDIR)/tools/target/release/ways-audit$(EXE)" $(WAYS_AUDIT_BIN)
@echo "Built: $(WAYS_AUDIT_BIN) ($$(ls -lh $(WAYS_AUDIT_BIN) | awk '{print $$5}'))"
# Build attend binary from workspace.
attend:
@if [ -x $(ATTEND_BIN) ] && $(ATTEND_BIN) --version >/dev/null 2>&1; then \
echo "attend already built."; \
elif bash tools/attend/download-attend.sh; then \
echo "Pre-built attend binary installed."; \
$(MAKE) -s --no-print-directory _attend_state_hint; \
elif command -v cargo >/dev/null 2>&1; then \
echo "Pre-built unavailable (see above) — building attend from source..."; \
cargo build --release --manifest-path tools/Cargo.toml -p attend; \
mkdir -p bin; \
$(LINK) "$(CURDIR)/tools/target/release/attend$(EXE)" $(ATTEND_BIN); \
echo "Built: $(ATTEND_BIN) ($$(ls -lh $(ATTEND_BIN) | awk '{print $$5}'))"; \
$(MAKE) -s --no-print-directory _attend_state_hint; \
else \
echo "error: No pre-built binary and cargo not found. Install Rust: https://rustup.rs/"; \
exit 1; \
fi
# Generate the attend CLI markdown reference from the same clap-derive
# `Cli` definition that drives runtime --help (ADR-111 extension). Output
# lives in docs/cli/ alongside other end-user reference material.
docs: attend
@mkdir -p docs/cli
@cargo build --release --manifest-path tools/Cargo.toml -p attend --bin gen-docs --quiet
@./tools/target/release/gen-docs > docs/cli/attend.md
@echo "Wrote docs/cli/attend.md ($$(wc -l < docs/cli/attend.md) lines)"
# Force rebuild attend from source.
attend-rebuild:
@if ! command -v cargo >/dev/null 2>&1; then \
echo "error: cargo not found. Install Rust: https://rustup.rs/"; \
exit 1; \
fi
cargo build --release --manifest-path tools/Cargo.toml -p attend
@mkdir -p bin
@$(LINK) "$(CURDIR)/tools/target/release/attend$(EXE)" $(ATTEND_BIN)
@echo "Built: $(ATTEND_BIN) ($$(ls -lh $(ATTEND_BIN) | awk '{print $$5}'))"
@$(MAKE) -s --no-print-directory _attend_state_hint
# Build attend-chat binary from workspace.
attend-chat:
@if [ -x $(ATTEND_CHAT_BIN) ] && $(ATTEND_CHAT_BIN) --version >/dev/null 2>&1; then \
echo "attend-chat already built."; \
elif bash tools/attend-chat/download-attend-chat.sh; then \
echo "Pre-built attend-chat binary installed."; \
$(MAKE) -s --no-print-directory _attend_state_hint; \
elif command -v cargo >/dev/null 2>&1; then \
echo "Pre-built unavailable (see above) — building attend-chat from source..."; \
cargo build --release --manifest-path tools/Cargo.toml -p attend-chat; \
mkdir -p bin; \
$(LINK) "$(CURDIR)/tools/target/release/attend-chat$(EXE)" $(ATTEND_CHAT_BIN); \
echo "Built: $(ATTEND_CHAT_BIN) ($$(ls -lh $(ATTEND_CHAT_BIN) | awk '{print $$5}'))"; \
$(MAKE) -s --no-print-directory _attend_state_hint; \
else \
echo "error: No pre-built binary and cargo not found. Install Rust: https://rustup.rs/"; \
exit 1; \
fi
# Force rebuild attend-chat from source.
attend-chat-rebuild:
@if ! command -v cargo >/dev/null 2>&1; then \
echo "error: cargo not found. Install Rust: https://rustup.rs/"; \
exit 1; \
fi
cargo build --release --manifest-path tools/Cargo.toml -p attend-chat
@mkdir -p bin
@$(LINK) "$(CURDIR)/tools/target/release/attend-chat$(EXE)" $(ATTEND_CHAT_BIN)
@echo "Built: $(ATTEND_CHAT_BIN) ($$(ls -lh $(ATTEND_CHAT_BIN) | awk '{print $$5}'))"
@$(MAKE) -s --no-print-directory _attend_state_hint
# Internal: post-build advisory printed after every attend / attend-
# chat (re)build. Suggests `make purge-attend-state` for operators
# updating from older attends whose on-disk state schema may have
# drifted (signals format, instance registry, heartbeat layout).
# Phony so it always runs; not a dependency of any user target.
.PHONY: _attend_state_hint
_attend_state_hint:
@echo ""
@echo " Note: if you are updating from an older attend, consider"
@echo " \`make purge-attend-state\` to reset cached runtime"
@echo " state for consistency. Skip it on a fresh install."
# Force re-fetch (or rebuild) of the way-embed binary. Delegates to the
# way-embed sub-Makefile's rebuild-binary target, which clears the
# cached install before download-binary.sh would short-circuit.
way-embed-rebuild:
$(MAKE) -C tools/way-embed rebuild-binary
# --- Test ---
test: lint test-smoke test-unit test-sim
@echo "All tests passed."
lint:
@echo "Linting Rust workspace..."
@cargo clippy --manifest-path tools/Cargo.toml -- -D warnings
@echo "Lint passed."
test-smoke: ways
@echo "Smoke testing ways binary..."
@$(WAYS_BIN) --version
@$(WAYS_BIN) lint --check --global && echo " lint: PASS"
@$(WAYS_BIN) match "write a unit test" >/dev/null && echo " match: PASS"
@$(WAYS_BIN) graph --output /dev/null && echo " graph: PASS"
@echo "Smoke tests passed."
test-unit:
@echo "Running Rust unit tests..."
@cargo test --manifest-path tools/ways-cli/Cargo.toml --bin ways --quiet
@echo "Unit tests passed."
test-sim: ways
@echo "Running session simulator (8 scenarios)..."
@cargo test --manifest-path tools/ways-cli/Cargo.toml --test session_sim -- --test-threads=1
@echo "Simulation tests passed."
test-lang: ways
@echo "Validating active language coverage..."
@$(WAYS_BIN) language --json | python3 -c "\
import json,sys; d=json.load(sys.stdin); \
active=d['locales_found']; \
print(f' Active locales in corpus: {len(active)}'); \
print(' Language coverage: SKIP (no locale data -- dormant per ADR-139)' if len(active)==0 else ' Language coverage: PASS')"
test-locales:
@echo "Checking locale files for gaps and duplicates..."
@python3 scripts/test-locales.py
test-multilingual: ways
@bash tests/test-multilingual.sh
# --- Release ---
# Build release binary for current platform with checksum.
# To publish: git tag ways-vX.Y.Z && git push --tags
# CI builds all 4 platforms and creates a GitHub Release.
release: ways-rebuild
@mkdir -p dist
@PLATFORM=$$(uname -s | tr '[:upper:]' '[:lower:]')-$$(uname -m | sed 's/arm64/aarch64/'); \
cp $(WAYS_BIN) dist/ways-$$PLATFORM; \
cd dist && sha256sum ways-$$PLATFORM > ways-$$PLATFORM.sha256; \
echo "dist/ways-$$PLATFORM ($$(ls -lh ways-$$PLATFORM | awk '{print $$5}'))"; \
cat ways-$$PLATFORM.sha256
# Release a Cargo-versioned component (ADR-150). Two steps, because main is
# branch-protected and PR-first:
# make cut-release COMPONENT=ways LEVEL=patch # 1) open a version-bump PR
# (merge that PR, then: git checkout main && git pull)
# make publish-release COMPONENT=ways [PUSH=1] # 2) tag the merged bump + publish
# publish-release without PUSH=1 creates the tag locally and prints the push
# command; PUSH=1 pushes it (CI then builds all platforms + creates the Release).
cut-release:
@bash scripts/release.sh bump "$(COMPONENT)" "$(LEVEL)"
publish-release:
@bash scripts/release.sh tag "$(COMPONENT)" $(if $(PUSH),--push,)
# --- Supporting ---
hooks-executable:
@find hooks -name '*.sh' -exec chmod +x {} + 2>/dev/null || true
@echo "Hooks marked executable."
clean:
$(MAKE) -C tools/way-embed clean
cargo clean --manifest-path tools/ways-cli/Cargo.toml 2>/dev/null || true
cargo clean --manifest-path tools/Cargo.toml 2>/dev/null || true
rm -rf dist/
# Wipe all attend / attend-chat runtime cache state under
# ~/.cache/attend/. Recovery target only — NEVER a dependency of
# setup, install, update, update-binaries, or any rebuild target.
# An advisory hint is printed at the end of attend / attend-chat
# build targets pointing operators here when they update.
#
# Removes: signals (peer messages), _groups.yaml (channel
# membership), state/ (sensor checkpoints), instances/ (per-cwd
# session naming, ADR-129), heartbeat/ (liveness sidecars,
# ADR-129), last_inbound (reply targeting).
#
# Does NOT touch ~/.claude/sessions/*.json or ~/.claude/projects/ —
# those are Claude Code's own session state, owned outside attend.
purge-attend-state:
@echo "Wiping ~/.cache/attend/ (peers, signals, channels, instances, heartbeats, sensor state)"
@if pgrep -f 'attend run' >/dev/null 2>&1; then \
echo ""; \
echo "WARNING: at least one 'attend run' is currently running."; \
echo " Purging cached state under a live attend leaves it"; \
echo " operating on stale in-memory views. Stop your"; \
echo " attend processes first, then re-run this target."; \
echo ""; \
echo " Aborting."; \
exit 1; \
fi
@rm -rf "$(HOME)/.cache/attend"
@echo "Done. Next attend launch starts from a clean slate."