@henols/vice-mcp 0.1.4

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,169 @@
1
+ #!/usr/bin/env bash
2
+ # .claude/mcp/vice/resources/vice-launcher.sh
3
+ #
4
+ # HAND-AUTHORED -- not generated. It lives beside the generated vice-broker.mjs
5
+ # purely because install-resources.mjs deploys the whole resources/ directory
6
+ # as a unit; this is the one file in this directory a maintainer edits
7
+ # directly (see ./.claude/CLAUDE.md's Emulator Access three-tier rule).
8
+ #
9
+ # HOST-ONLY. Phase 01.6.2: the container guard no longer lives in bash here
10
+ # -- it ported to TypeScript (container-guard.mts, PD-03) and now runs at
11
+ # the BROKER PROCESS's own startup, closing the invocation-scoped hole
12
+ # recorded in RE-FINDINGS.md (running the compiled broker directly, bypassing
13
+ # this launcher, was previously unguarded). This launcher no longer sources
14
+ # the bash guard module or calls its enforce/report functions itself --
15
+ # --check-container is now forwarded through to the Node entry point, which
16
+ # answers it, preserving the exact same exit-code contract this launcher
17
+ # always had: 2 when the guard refuses, 3 for the report path, 0 for
18
+ # --print-paths.
19
+ #
20
+ # Copies vice-broker.sh's own opening shape: SELF_PATH/SELF_DIR resolution,
21
+ # resolve_repo_root(). Plan 11 INLINES resolve_repo_root() here (it used to
22
+ # live in a small sourced-only library under resources/lib/, one function and
23
+ # nothing else) in the same commit that deletes that library directory
24
+ # wholesale, the retiring bash broker, the retiring per-instance supervisor,
25
+ # and the retiring bash container guard's own sourced module -- the shell
26
+ # must resolve its own root before it can construct the command that starts
27
+ # the broker, so by the time a Node process exists there is nothing left to
28
+ # decide. This is the ONLY place that logic lives now.
29
+ set -euo pipefail
30
+
31
+ SELF_PATH="${BASH_SOURCE[0]}"
32
+ SELF_DIR="$(cd "$(dirname "$SELF_PATH")" && pwd)"
33
+
34
+ # resolve_repo_root() -- inlined from the former sourced-only repo-root
35
+ # library (deleted alongside this inline), mirroring repo-root.ts's
36
+ # documented ladder (D-2) so the shell and Node halves of this tree can
37
+ # never resolve to two different `.vice-supervisor` directories.
38
+ #
39
+ # WHY THIS FUNCTION EXISTS AT ALL: a fixed `".."` hop (`REPO_ROOT="$(cd
40
+ # "$(dirname "$SELF_PATH")/.." && pwd)"`) is wrong from this launcher's own
41
+ # location, `.claude/mcp/vice/resources/` -- four levels below the repo root,
42
+ # not one. NOTHING would error on a wrong fixed hop count: the script would
43
+ # just read a permanently-empty `.vice-supervisor` state directory forever,
44
+ # and restart detection would quietly stop working while every command kept
45
+ # "succeeding". See repo-root.ts's own header comment for the Node-side
46
+ # telling of the same failure class this function exists to prevent.
47
+ #
48
+ # One-time stderr notes, so a long process (or a test driving this function
49
+ # repeatedly) does not spam stderr -- mirrors repo-root.ts's
50
+ # warnedEnvOutsideFrom / warnedNoMarkerFound module-level latches.
51
+ _REPO_ROOT_WARNED_ENV_OUTSIDE=0
52
+ _REPO_ROOT_WARNED_NO_MARKER=0
53
+
54
+ # resolve_repo_root <absolute-dir>
55
+ #
56
+ # Prints the resolved repo root for a script whose own directory is
57
+ # <absolute-dir>. Precedence, in order (mirrors repo-root.ts's repoRoot()):
58
+ #
59
+ # 1. CONTAINER_WORKSPACE_PATH, when set AND <absolute-dir> resolves inside
60
+ # it -- this devcontainer sets it, and it is the most explicit signal
61
+ # available.
62
+ # 2. Otherwise, walk up from <absolute-dir> toward the filesystem root,
63
+ # returning the first directory containing a `.git` entry (tested with
64
+ # `-e`, so a worktree's `.git` FILE matches just as well as a real
65
+ # `.git` DIRECTORY). This is what keeps the script correct once exported
66
+ # into a project that sets no such variable at all -- the ONLY branch
67
+ # that ever runs on the real host, which sets no such env var.
68
+ # 3. Otherwise, CONTAINER_WORKSPACE_PATH if it is set at all (just not
69
+ # containing <absolute-dir> -- an exported copy of this skill living
70
+ # outside the mounted workspace the variable names). Silence here would
71
+ # be exactly the quiet-wrong-answer failure class this function exists
72
+ # to prevent, so this path emits a one-time stderr note naming both
73
+ # paths.
74
+ # 4. Otherwise, a location-shaped last resort, also with a one-time stderr
75
+ # note: FOUR levels up when <absolute-dir>'s own directory is named
76
+ # `resources` (matching `<root>/.claude/mcp/vice/resources`),
77
+ # ONE level up otherwise.
78
+ resolve_repo_root() {
79
+ local from="$1" dir parent base
80
+
81
+ if [ -n "${CONTAINER_WORKSPACE_PATH:-}" ]; then
82
+ case "$from" in
83
+ "$CONTAINER_WORKSPACE_PATH" | "$CONTAINER_WORKSPACE_PATH"/*)
84
+ printf '%s\n' "$CONTAINER_WORKSPACE_PATH"
85
+ return 0
86
+ ;;
87
+ esac
88
+ fi
89
+
90
+ dir="$from"
91
+ while :; do
92
+ if [ -e "$dir/.git" ]; then
93
+ printf '%s\n' "$dir"
94
+ return 0
95
+ fi
96
+ parent="$(dirname "$dir")"
97
+ if [ "$parent" = "$dir" ]; then
98
+ break # reached the filesystem root -- no .git found anywhere above $from
99
+ fi
100
+ dir="$parent"
101
+ done
102
+
103
+ if [ -n "${CONTAINER_WORKSPACE_PATH:-}" ]; then
104
+ if [ "$_REPO_ROOT_WARNED_ENV_OUTSIDE" -eq 0 ]; then
105
+ _REPO_ROOT_WARNED_ENV_OUTSIDE=1
106
+ echo "warn: CONTAINER_WORKSPACE_PATH is set ($CONTAINER_WORKSPACE_PATH) but does not contain $from, and no .git ancestor was found either -- falling back to CONTAINER_WORKSPACE_PATH itself as the repo root. This is expected for an exported copy of this skill living outside its mounted workspace; if that is not the situation here, the repo root this resolved to may be wrong." >&2
107
+ fi
108
+ printf '%s\n' "$CONTAINER_WORKSPACE_PATH"
109
+ return 0
110
+ fi
111
+
112
+ base="$(basename "$from")"
113
+ if [ "$base" = "resources" ]; then
114
+ dir="$(cd "$from/../../../.." && pwd)"
115
+ else
116
+ dir="$(cd "$from/.." && pwd)"
117
+ fi
118
+
119
+ if [ "$_REPO_ROOT_WARNED_NO_MARKER" -eq 0 ]; then
120
+ _REPO_ROOT_WARNED_NO_MARKER=1
121
+ echo "warn: could not find a .git ancestor above $from and CONTAINER_WORKSPACE_PATH is not set -- falling back to a location-shaped last resort ($dir). This is a last resort; if it's wrong, set CONTAINER_WORKSPACE_PATH or run from inside a git repo." >&2
122
+ fi
123
+ printf '%s\n' "$dir"
124
+ }
125
+
126
+ REPO_ROOT="$(resolve_repo_root "$SELF_DIR")"
127
+
128
+ # Resolved as a SIBLING of this running script ($SELF_DIR), matching
129
+ # vice-broker.sh's own supervisor-resolution rationale: a launcher run from
130
+ # resources/ must launch the resources/ copy, not silently reach across to a
131
+ # deployed tools/ copy that may be stale or hand-edited.
132
+ BROKER_ARTIFACT="$SELF_DIR/vice-broker.mjs"
133
+
134
+ # ---------------------------------------------------------------- --print-paths
135
+ #
136
+ # Prints already-resolved variables only -- writes no state, spawns nothing,
137
+ # so (like vice-broker.sh's own --print-paths) it needs no guard enforcement
138
+ # to report what this launcher would use. Checked BEFORE --check-container is
139
+ # forwarded, since --print-paths needs no guard verdict at all.
140
+ PRINT_PATHS=0
141
+ for arg in "$@"; do
142
+ case "$arg" in
143
+ --print-paths)
144
+ PRINT_PATHS=1
145
+ ;;
146
+ esac
147
+ done
148
+
149
+ if [ "$PRINT_PATHS" -eq 1 ]; then
150
+ echo "repo_root=$REPO_ROOT"
151
+ echo "self_dir=$SELF_DIR"
152
+ echo "broker_artifact=$BROKER_ARTIFACT"
153
+ exit 0
154
+ fi
155
+
156
+ # ---------------------------------------------------------------- exec
157
+ #
158
+ # The guard now runs INSIDE the Node entry point, at its own process
159
+ # startup, before any state is read or written and before anything is
160
+ # spawned -- both --check-container (exit 3, reporting) and the plain
161
+ # enforcement path (exit 2, refusal) are the broker's own job now. This
162
+ # launcher forwards every argument, including --repo-root, unchanged, and
163
+ # no longer inspects --check-container itself; the exit-code contract this
164
+ # launcher always exposed (2/3/0) is preserved because the guard functions
165
+ # ported into container-guard.mts return the SAME codes
166
+ # container_guard_enforce()/container_guard_report() always did. Signal
167
+ # delivery still passes straight through to the broker process with no bash
168
+ # trap in between.
169
+ exec node "$BROKER_ARTIFACT" --repo-root "$REPO_ROOT" "$@"