@plot-pm/board 0.16.1 → 0.16.3

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,127 @@
1
+ #!/usr/bin/env bash
2
+ # The ONE answer to "where do desks and action records go?" — sourced, not run.
3
+ #
4
+ # Every script that resolved this privately asks here instead. Nine sites
5
+ # computed the rule on 2026-10-01 and two of them already answered `.worktrees`
6
+ # while seven answered the checkout's parent, so one of the two populations was
7
+ # always writing somewhere the other did not read.
8
+ #
9
+ # The rule itself is `deskRoot` in the domain, asked through
10
+ # `board/plot-desk-root.mjs`, per *A Shell Script Asks The Domain*: every caller
11
+ # runs once per operator command, which is the cost rule's permitted case.
12
+ #
13
+ # NO CALLER KEEPS A FALLBACK DEFAULT. When the bundle cannot answer — no `node`,
14
+ # a missing file — the caller stops with the reason. A silent fallback is a
15
+ # second default, and two defaults are the defect this removes.
16
+ #
17
+ # plot_repo_root → the MAIN checkout, from anywhere
18
+ # plot_desk_root [repo [configured]] → the desk root; exit 3 when unaskable
19
+ # plot_exclude_desk_root [repo] → keep it out of `git status`; never fails
20
+ #
21
+ # shellcheck shell=bash
22
+
23
+ # The MAIN checkout, from a desk as readily as from the checkout itself.
24
+ #
25
+ # `--show-toplevel` answers the DESK inside a linked worktree, so with
26
+ # `.worktrees` as the default it would resolve `<desk>/.worktrees` and place
27
+ # every tree under a root nothing else reads. `plot-reap.sh:440-447` recorded
28
+ # that failure on 2026-09-10, when every tree read as unplaceable.
29
+ #
30
+ # The parent of `--git-common-dir` is the main checkout from anywhere, because
31
+ # every linked worktree shares that one directory. It is asked FIRST and
32
+ # `--show-toplevel` is the fallback, since the common dir is also correct in a
33
+ # non-worktree checkout: there `.git` is a real directory in the root.
34
+ #
35
+ # PHYSICAL, through `pwd -P`: `git worktree list` and `--show-toplevel` print
36
+ # resolved paths, and a desk root composed from a logical one (`/tmp` against
37
+ # `/private/tmp` on macOS) is a prefix no worktree path ever starts with.
38
+ plot_repo_root() {
39
+ local common root=''
40
+ common=$(git rev-parse --git-common-dir 2>/dev/null) && [ -n "$common" ] && {
41
+ common=$(cd -- "$common" 2>/dev/null && pwd -P) || common=''
42
+ [ -n "$common" ] && root=$(dirname -- "$common")
43
+ }
44
+ [ -n "$root" ] || root=$(git rev-parse --show-toplevel 2>/dev/null) || root=$(pwd)
45
+ printf '%s\n' "$root"
46
+ }
47
+
48
+ # Resolved ONCE at source time, the way `plot-pr-merged.sh:105` resolves its
49
+ # own bundle. Computing it inside a function reads `BASH_SOURCE[0]` at call
50
+ # time, which is the caller's file once the function has been exported.
51
+ _plot_desk_root_mjs="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/board/plot-desk-root.mjs"
52
+ _plot_desk_root_config="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/plot-config.sh"
53
+
54
+ # The desk root for a repository, or exit 3 with the reason on stderr.
55
+ #
56
+ # A second argument is a value the caller was handed in place of the key — a
57
+ # `--worktrees DIR` flag — and goes through the same rule; without one the
58
+ # `Worktree root` key is read.
59
+ #
60
+ # READ THE EXIT CODE. A caller that treats an empty answer as a location would
61
+ # compose paths against the filesystem root.
62
+ plot_desk_root() {
63
+ local repo="${1:-}" bundle="$_plot_desk_root_mjs" configured answer
64
+ [ -n "$repo" ] || repo=$(plot_repo_root)
65
+ if [ ! -f "$bundle" ]; then
66
+ printf 'plot: cannot resolve the desk root: %s is missing\n' "$bundle" >&2
67
+ return 3
68
+ fi
69
+ if [ "$#" -ge 2 ]; then
70
+ configured="$2"
71
+ else
72
+ # Read from the TARGET repository, never the ambient one: `plot-config.sh`
73
+ # walks up from its cwd, so a caller asking about another checkout would
74
+ # otherwise get this one's key.
75
+ # A read that fails is a refusal, never the absent row: reading it as empty
76
+ # would answer the default for a repository that configured another root.
77
+ configured=$(cd -- "$repo" 2>/dev/null && bash "$_plot_desk_root_config" get "Worktree root" "" 2>/dev/null) || {
78
+ printf 'plot: cannot resolve the desk root: the Worktree root key in %s could not be read\n' "$repo" >&2
79
+ return 3
80
+ }
81
+ fi
82
+ answer=$(node "$bundle" "$repo" "$configured" 2>&1) || {
83
+ printf 'plot: cannot resolve the desk root: %s\n' "$answer" >&2
84
+ return 3
85
+ }
86
+ [ -n "$answer" ] || {
87
+ printf 'plot: the desk root rule answered nothing for %s\n' "$repo" >&2
88
+ return 3
89
+ }
90
+ printf '%s\n' "$answer"
91
+ }
92
+
93
+ # Keep the desk root out of `git status`, when it lies inside the repository.
94
+ #
95
+ # The line goes into the COMMON git directory's `info/exclude`: git reads that
96
+ # file from the common directory only, so a linked worktree's private gitdir is
97
+ # the wrong place and a desk writing there would exclude nothing. The write is
98
+ # idempotent, and `info/exclude` is never committed.
99
+ #
100
+ # Called by whoever CREATES the directory. Best-effort and always exit 0: a
101
+ # failure leaves untracked files in a listing, which is untidy, while refusing
102
+ # to create a desk over it would stop the work.
103
+ plot_exclude_desk_root() {
104
+ local repo="${1:-}" bundle="$_plot_desk_root_mjs" line common exclude configured
105
+ [ -n "$repo" ] || repo=$(plot_repo_root)
106
+ [ -f "$bundle" ] || return 0
107
+ configured=$(cd -- "$repo" 2>/dev/null && bash "$_plot_desk_root_config" get "Worktree root" "" 2>/dev/null) || configured=''
108
+ line=$(node "$bundle" --exclude-line "$repo" "$configured" 2>/dev/null) || return 0
109
+ # Empty means the root lies outside the repository, which needs no line.
110
+ [ -n "$line" ] || return 0
111
+ # Already ignored, by a `.gitignore` line /plot-init wrote or by an earlier
112
+ # run. A second rule for a path already ignored is noise in a file people read.
113
+ ( cd -- "$repo" 2>/dev/null && git check-ignore -q ".$line" ) && return 0
114
+ common=$(cd -- "$repo" 2>/dev/null && git rev-parse --git-common-dir 2>/dev/null) || return 0
115
+ [ -n "$common" ] || return 0
116
+ case "$common" in /*) ;; *) common="$repo/$common" ;; esac
117
+ exclude="$common/info/exclude"
118
+ if [ -f "$exclude" ] && grep -qxF "$line" "$exclude" 2>/dev/null; then return 0; fi
119
+ mkdir -p "$common/info" 2>/dev/null || return 0
120
+ # A file not ending in a newline would otherwise join this line to its last.
121
+ if [ -s "$exclude" ] && [ "$(tail -c 1 "$exclude" 2>/dev/null)" != "" ]; then
122
+ printf '\n%s\n' "$line" >> "$exclude" 2>/dev/null || true
123
+ else
124
+ printf '%s\n' "$line" >> "$exclude" 2>/dev/null || true
125
+ fi
126
+ return 0
127
+ }