tools: group scripts by what runs them

tools/windows/   .ps1   (pwsh, so usable from Linux and macOS too)
  tools/posix/     .sh
  tools/python/    .py
  tools/           .c and .pl

The .c and .pl files stay at the top level because they are not
host-specific: the build compiles or invokes them on every platform.

Call sites updated in the Makefile, ports/mk/port.mk, docs and the
project memory. The one thing that does not survive a move on its own is
a script deriving the repo root from its own location -- all nine
PowerShell tools used Split-Path $PSScriptRoot -Parent, and memory-sync.sh
used dirname/.., both of which quietly become tools/ one level deeper.
Two levels now.

Two pre-existing Windows failures surfaced while verifying, both real and
neither caused by the move:

  - schfs_fsck.c did not compile under mingw at all: --extract uses
    POSIX mkdir(path,mode), symlink() and link(), none of which mingw
    has. That took the whole tool with it, and `make schfs-check` with
    it. mkdir maps to _mkdir; symlink and link fail loudly rather than
    writing a regular file in their place, because an extracted tree
    that differs from the image while reporting success defeats the
    point of --extract.
  - the round-trip test then failed at `ln -s`, since Git Bash cannot
    create symlinks without developer mode. It skips with a message now.
    Not a fudge: mkschfs's mingw build cannot see a symlink either, so
    the test would have compared a tree with none against an image with
    none and called it a pass -- coverage reporting itself as present
    while being absent.

Verified on Windows: build clean, all seven bootcheck suites green,
make schfs-check passes.
This commit is contained in:
Nexoniarz 2026-08-09 14:38:02 +02:00
commit 754d96ebc5
26 changed files with 127 additions and 39 deletions

View file

@ -1,111 +0,0 @@
#!/bin/sh
# Move Claude Code's project memory between this repo and the local machine.
#
# tools/memory-sync.sh export memory on this machine -> .claude/memory/
# tools/memory-sync.sh import .claude/memory/ -> this machine
# tools/memory-sync.sh status show both sides, change nothing
#
# Why this exists
# ---------------
# Claude Code keeps per-project memory outside the repo, under
#
# <home>/.claude/projects/<key>/memory/
#
# where <key> is the project's absolute path with the separators replaced by
# dashes: D:\DEV\SchOS becomes D--DEV-SchOS, /home/me/dev/SchOS becomes
# -home-me-dev-SchOS. Two consequences follow, and both have already bitten
# this project once:
#
# * Renaming the directory orphans the memory. D:\DEV\Schunix -> D:\DEV\SchOS
# changed the key, and everything written under the old one became
# invisible until it was moved across by hand.
# * The key is machine-specific, so memory written on Windows is not where
# Linux looks for it, even for the same checkout.
#
# Committing the memory to the repo fixes both: git carries it between hosts
# and across renames, and `import` puts it wherever this particular machine
# expects to find it. Run `export` after a session that learned something and
# `import` after cloning or pulling on another machine.
set -eu
usage() {
echo "usage: $0 {export|import|status}" >&2
exit 2
}
[ $# -eq 1 ] || usage
# Repo root: this script lives in tools/, so the parent of its directory.
script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
repo=$(CDPATH= cd -- "$script_dir/.." && pwd)
repo_mem="$repo/.claude/memory"
# The absolute path Claude Code itself sees. Under Git Bash `pwd` gives
# /d/DEV/SchOS, but Claude Code is a Windows program and uses D:\DEV\SchOS, so
# the key must be derived from the Windows form or it will not match.
native_path="$repo"
case "$(uname -s)" in
MINGW* | MSYS* | CYGWIN*)
if command -v cygpath >/dev/null 2>&1; then
native_path=$(cygpath -w "$repo")
fi
;;
esac
# Encode: every separator becomes a dash, and so does the drive colon.
#
# D:\DEV\SchOS -> D--DEV-SchOS
# /home/me/dev/SchOS -> -home-me-dev-SchOS
#
# The colon maps to a dash rather than being deleted -- that is where the
# doubled dash in the Windows form comes from, and dropping it instead yields
# D-DEV-SchOS, which matches nothing.
key=$(printf '%s' "$native_path" | tr '/\\:' '---')
home_dir=${HOME:-$USERPROFILE}
host_mem="$home_dir/.claude/projects/$key/memory"
count() { [ -d "$1" ] && find "$1" -name '*.md' 2>/dev/null | wc -l | tr -d ' ' || echo 0; }
case "$1" in
status)
echo "repo: $repo"
echo "as Claude sees it: $native_path"
echo "project key: $key"
echo
echo "in repo: $repo_mem"
echo " $(count "$repo_mem") memories"
echo "on this host: $host_mem"
echo " $(count "$host_mem") memories"
;;
export)
if [ ! -d "$host_mem" ]; then
echo "memory-sync: nothing to export -- no memory at $host_mem" >&2
echo " (is the project key right? run: $0 status)" >&2
exit 1
fi
mkdir -p "$repo_mem"
# Copy rather than mirror: deleting from the repo is a git operation and
# should be visible in a diff, not a side effect of running a sync script.
cp "$host_mem"/*.md "$repo_mem"/ 2>/dev/null || true
echo "exported $(count "$repo_mem") memories to .claude/memory/"
echo "commit them to carry them to your other machines."
;;
import)
if [ ! -d "$repo_mem" ]; then
echo "memory-sync: nothing to import -- no .claude/memory/ in this repo" >&2
exit 1
fi
mkdir -p "$host_mem"
cp "$repo_mem"/*.md "$host_mem"/ 2>/dev/null || true
echo "imported $(count "$host_mem") memories to:"
echo " $host_mem"
;;
*)
usage
;;
esac