coding-supervisor 0.0.0-stage → 0.1.0-rc4

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 special-place-ai-heaven
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,228 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const childProcess = require("child_process");
5
+ const fs = require("fs");
6
+ const path = require("path");
7
+ const { resolveBinary, formatResolveError } = require("../lib/resolve-binary.js");
8
+
9
+ // Best-effort, path-only scan of $PATH for every `supervisor` entry, in PATH
10
+ // order. Never spawns anything (this runs on every MCP server start, so it must
11
+ // add negligible latency). On Windows it honors PATHEXT (defaulting to the
12
+ // usual shim extensions) so the npm `.cmd`/`.exe` shim is found. Returns the
13
+ // list of existing candidate paths, deduplicated, in the order PATH would
14
+ // resolve them.
15
+ function whichAllSupervisor(env, platform) {
16
+ const environ = env || {};
17
+ const rawPath = environ.PATH || environ.Path || "";
18
+ if (!rawPath) return [];
19
+
20
+ const isWindows = platform === "win32";
21
+ // Candidate basenames to probe inside each PATH dir. On Windows, PATHEXT
22
+ // decides which extensions are executable; we only care about the ones a
23
+ // supervisor shim would ever use. The bare name covers a shell function / shim
24
+ // without an extension and the WSL-bleed case where a Linux `supervisor` sits
25
+ // on PATH.
26
+ let names = ["supervisor"];
27
+ if (isWindows) {
28
+ const pathext = (environ.PATHEXT || ".COM;.EXE;.BAT;.CMD")
29
+ .split(";")
30
+ .map((ext) => ext.trim().toLowerCase())
31
+ .filter((ext) => ext === ".exe" || ext === ".cmd" || ext === ".bat" || ext === ".com");
32
+ const exts = pathext.length > 0 ? pathext : [".exe", ".cmd"];
33
+ names = ["supervisor", ...exts.map((ext) => `supervisor${ext}`)];
34
+ }
35
+
36
+ const found = [];
37
+ const seen = new Set();
38
+ for (const dir of rawPath.split(path.delimiter)) {
39
+ if (!dir) continue;
40
+ for (const name of names) {
41
+ const candidate = path.join(dir, name);
42
+ if (seen.has(candidate)) continue;
43
+ seen.add(candidate);
44
+ try {
45
+ const stat = fs.statSync(candidate);
46
+ if (stat.isFile()) found.push(candidate);
47
+ } catch (_err) {
48
+ // Missing path entry — skip silently.
49
+ }
50
+ }
51
+ }
52
+ return found;
53
+ }
54
+
55
+ // Same file on disk: realpaths equal, so a symlinked npm bin shim
56
+ // (`<prefix>/bin/supervisor` -> `.../supervisor/bin/supervisor.js`) matches its target.
57
+ // A path that cannot be resolved falls back to its absolute form.
58
+ function sameFile(a, b) {
59
+ const real = (p) => {
60
+ try {
61
+ return fs.realpathSync.native(p);
62
+ } catch (_err) {
63
+ return path.resolve(p);
64
+ }
65
+ };
66
+ return real(a) === real(b);
67
+ }
68
+
69
+ // True when `shadowPath` is THIS launcher's own npm bin shim, not a foreign
70
+ // install. The thing on PATH is normally the npm-generated shim
71
+ // (`supervisor` / `supervisor.cmd`), which lives in the npm prefix `bin` dir that
72
+ // is a sibling of this package's install dir (…/node_modules/supervisor). We
73
+ // treat a shim as "ours" when it sits in the bin dir adjacent to our package
74
+ // root, or when its file contents reference this package's launcher. Either
75
+ // proves the first PATH `supervisor` would dispatch back into this very launcher,
76
+ // so there is nothing to warn about.
77
+ function isOwnShim(shadowPath, selfDir) {
78
+ try {
79
+ // selfDir is …/supervisor/bin (this launcher's directory). The package root
80
+ // is its parent; the install prefix bin dir is a sibling of node_modules.
81
+ const packageRoot = path.dirname(selfDir); // …/supervisor
82
+ const nodeModules = path.dirname(packageRoot); // …/node_modules
83
+ const prefix = path.dirname(nodeModules); // npm prefix root
84
+ const shimDir = path.dirname(path.resolve(shadowPath));
85
+
86
+ // npm places global shims in <prefix>/bin (POSIX) or <prefix> (Windows).
87
+ const prefixBinPosix = path.join(prefix, "bin");
88
+ if (shimDir === prefix || shimDir === prefixBinPosix) {
89
+ return true;
90
+ }
91
+
92
+ // The shim may itself be the package's own bin file (e.g. local linked
93
+ // install where PATH points directly at bin/supervisor.js's dir).
94
+ if (shimDir === selfDir) {
95
+ return true;
96
+ }
97
+
98
+ // Fall back to content inspection: npm shims embed the relative path back
99
+ // to the package launcher. If the shim text references this package, it is
100
+ // ours regardless of where the prefix sits.
101
+ const text = fs.readFileSync(path.resolve(shadowPath), "utf8");
102
+ if (text.includes("node_modules/coding-supervisor/bin/") || text.includes("node_modules\\supervisor\\bin\\")) {
103
+ return true;
104
+ }
105
+ } catch (_err) {
106
+ // Unreadable / non-shim — fall through and treat as foreign so we do not
107
+ // suppress a genuine shadow on a transient read error.
108
+ }
109
+ return false;
110
+ }
111
+
112
+ // Classify the shadowing install so the warning names the kind of copy that wins
113
+ // (what `where supervisor` / `which -a supervisor` would list first).
114
+ function classifyShadow(shadowPath, env, platform) {
115
+ const environ = env || {};
116
+ if (platform !== "win32") {
117
+ let procVersion = "";
118
+ try {
119
+ procVersion = fs.readFileSync("/proc/version", "utf8").toLowerCase();
120
+ } catch (_err) {
121
+ // Not Linux / unreadable — not WSL.
122
+ }
123
+ const underWsl = /microsoft|wsl/.test(procVersion);
124
+ if (underWsl && /^\/mnt\/[a-z]\//i.test(shadowPath)) {
125
+ return "windows-bleed";
126
+ }
127
+ if (/^\/usr\/local\//.test(shadowPath) || /^\/usr\//.test(shadowPath) || /^\/opt\//.test(shadowPath)) {
128
+ return "root/system";
129
+ }
130
+ }
131
+ return "foreign-prefix";
132
+ }
133
+
134
+ // Best-effort PATH-shadow warning. When the launcher runs but a DIFFERENT
135
+ // `supervisor` would win on $PATH, print one or two stderr lines pointing the
136
+ // operator at the binary's richer remediation. NEVER blocks or breaks the
137
+ // spawn: the entire body is wrapped in try/catch by the caller and any failure
138
+ // is swallowed. Output goes to stderr only (stdout is the MCP stdio channel).
139
+ function maybeWarnPathShadow(consoleMod, env, platform, resolvedBinaryPath, selfDir) {
140
+ const environ = env || {};
141
+ if (environ.SUPERVISOR_NO_SHADOW_WARN) return;
142
+
143
+ const entries = whichAllSupervisor(environ, platform);
144
+ if (entries.length === 0) return;
145
+
146
+ const first = entries[0];
147
+
148
+ // The launcher already "wins" when the first PATH supervisor IS the resolved
149
+ // native binary, IS this launcher itself (by realpath, so a symlinked bin
150
+ // shim in any prefix counts), or is this launcher's own npm shim that
151
+ // dispatches here.
152
+ if (sameFile(first, resolvedBinaryPath)) return;
153
+ if (sameFile(first, path.join(selfDir, "supervisor.js"))) return;
154
+ if (sameFile(first, path.join(selfDir, "launcher.js"))) return;
155
+ if (isOwnShim(first, selfDir)) return;
156
+
157
+ const kind = classifyShadow(first, environ, platform);
158
+ consoleMod.error(
159
+ `supervisor: warning: a different 'supervisor' (${kind}) is first on your PATH: ${first}`
160
+ );
161
+ consoleMod.error(
162
+ " This launcher is running, but that one shadows it. Put this npm prefix first on PATH or remove that copy, then rerun 'supervisor install'."
163
+ );
164
+ }
165
+
166
+ function createLauncher(overrides = {}) {
167
+ const processMod = overrides.process || process;
168
+ const consoleMod = overrides.console || console;
169
+ const spawnSyncFn = overrides.spawnSync || childProcess.spawnSync;
170
+ const resolveBinaryFn = overrides.resolveBinary || ((opts) => resolveBinary({
171
+ ...opts,
172
+ platform: processMod.platform,
173
+ arch: processMod.arch,
174
+ requireResolve: overrides.requireResolve || require.resolve,
175
+ }));
176
+ const selfDir = overrides.selfDir || __dirname;
177
+
178
+ function main(args) {
179
+ const resolved = resolveBinaryFn({ binary: "supervisor" });
180
+ if (resolved.reason !== "ok") {
181
+ consoleMod.error(formatResolveError(resolved, {
182
+ platform: processMod.platform,
183
+ arch: processMod.arch,
184
+ }));
185
+ return 64;
186
+ }
187
+
188
+ // Best-effort PATH-shadow warning. Must never block or break the spawn, so
189
+ // swallow any error from the detection path entirely.
190
+ try {
191
+ maybeWarnPathShadow(
192
+ consoleMod,
193
+ processMod.env,
194
+ processMod.platform,
195
+ resolved.binaryPath,
196
+ selfDir
197
+ );
198
+ } catch (_err) {
199
+ // Detection failure must not stop supervisor from running.
200
+ }
201
+
202
+ const result = spawnSyncFn(resolved.binaryPath, args, {
203
+ stdio: "inherit",
204
+ env: processMod.env,
205
+ shell: false,
206
+ });
207
+ if (result.error) {
208
+ consoleMod.error(`supervisor: failed to spawn ${resolved.binaryPath}: ${result.error.code || result.error.message}`);
209
+ return result.error.code === "ENOENT" ? 127 : 126;
210
+ }
211
+ return result.status ?? 1;
212
+ }
213
+
214
+ return {
215
+ main,
216
+ };
217
+ }
218
+
219
+ module.exports = {
220
+ createLauncher,
221
+ whichAllSupervisor,
222
+ isOwnShim,
223
+ classifyShadow,
224
+ };
225
+
226
+ if (require.main === module) {
227
+ process.exit(createLauncher().main(process.argv.slice(2)));
228
+ }
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const { createLauncher } = require("./launcher.js");
5
+
6
+ try {
7
+ process.exit(createLauncher().main(process.argv.slice(2)));
8
+ } catch (err) {
9
+ console.error(err.message);
10
+ process.exit(1);
11
+ }
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+
6
+ const SUPPORTED_TARGETS = Object.freeze([
7
+ Object.freeze({
8
+ platform: "linux",
9
+ arch: "x64",
10
+ pkg: "coding-supervisor-linux-x64",
11
+ monorepoDir: "linux-x64",
12
+ binaryName: "supervisor",
13
+ }),
14
+ Object.freeze({
15
+ platform: "win32",
16
+ arch: "x64",
17
+ pkg: "coding-supervisor-windows-x64",
18
+ monorepoDir: "windows-x64",
19
+ binaryName: "supervisor.exe",
20
+ }),
21
+ ]);
22
+
23
+ const ALLOWED_BINARIES = Object.freeze(["supervisor"]);
24
+
25
+ function findPlatformPackageJson(target, requireResolve) {
26
+ try {
27
+ return requireResolve(`${target.pkg}/package.json`);
28
+ } catch (_err) {
29
+ // Fall through to local development lookup.
30
+ }
31
+
32
+ const local = path.join(__dirname, "..", "platforms", target.monorepoDir, "package.json");
33
+ if (fs.existsSync(local)) {
34
+ return local;
35
+ }
36
+
37
+ let dir = path.join(__dirname, "..");
38
+ for (let i = 0; i < 6; i += 1) {
39
+ const nested = path.join(dir, "node_modules", target.pkg, "package.json");
40
+ if (fs.existsSync(nested)) {
41
+ return nested;
42
+ }
43
+ const parent = path.dirname(dir);
44
+ if (parent === dir) break;
45
+ dir = parent;
46
+ }
47
+
48
+ return null;
49
+ }
50
+
51
+ function resolveBinary(opts) {
52
+ const options = opts || {};
53
+ const binary = options.binary;
54
+ const platform = options.platform || process.platform;
55
+ const arch = options.arch || process.arch;
56
+ const requireResolve = options.requireResolve || require.resolve;
57
+
58
+ if (!ALLOWED_BINARIES.includes(binary)) {
59
+ return {
60
+ reason: "invalid_binary",
61
+ platformPackage: null,
62
+ binaryPath: null,
63
+ supportedTargets: SUPPORTED_TARGETS,
64
+ };
65
+ }
66
+
67
+ const target = SUPPORTED_TARGETS.find((t) => t.platform === platform && t.arch === arch);
68
+ if (!target) {
69
+ return {
70
+ reason: "unsupported_platform",
71
+ platformPackage: null,
72
+ binaryPath: null,
73
+ supportedTargets: SUPPORTED_TARGETS,
74
+ };
75
+ }
76
+
77
+ const pkgJsonPath = findPlatformPackageJson(target, requireResolve);
78
+ if (!pkgJsonPath) {
79
+ return {
80
+ reason: "platform_package_missing",
81
+ platformPackage: target.pkg,
82
+ binaryPath: null,
83
+ supportedTargets: SUPPORTED_TARGETS,
84
+ };
85
+ }
86
+
87
+ const binaryPath = path.join(path.dirname(pkgJsonPath), "bin", target.binaryName);
88
+ if (!fs.existsSync(binaryPath)) {
89
+ return {
90
+ reason: "platform_package_missing",
91
+ platformPackage: target.pkg,
92
+ binaryPath: null,
93
+ supportedTargets: SUPPORTED_TARGETS,
94
+ };
95
+ }
96
+
97
+ return {
98
+ reason: "ok",
99
+ platformPackage: target.pkg,
100
+ binaryPath,
101
+ supportedTargets: SUPPORTED_TARGETS,
102
+ };
103
+ }
104
+
105
+ // Detect the WSL trap: a non-Windows process executing a supervisor install whose
106
+ // own files live under a Windows drive mount (`/mnt/<letter>/...`). That means
107
+ // the launcher came from a Windows npm prefix that bled onto the WSL PATH, so it
108
+ // only ships the Windows platform package — `npm install -g` from here just
109
+ // rewrites the Windows prefix again. The fix is to install into the Linux prefix.
110
+ function isWindowsPrefixUnderUnix(platform, selfPath) {
111
+ if (platform === "win32") return false;
112
+ if (typeof selfPath !== "string") return false;
113
+ return /^\/mnt\/[a-z]\//i.test(selfPath);
114
+ }
115
+
116
+ function formatResolveError(result, opts) {
117
+ const options = opts || {};
118
+ const platform = options.platform || process.platform;
119
+ const arch = options.arch || process.arch;
120
+ const selfPath = options.selfPath || __dirname;
121
+ const targets = result.supportedTargets.map((t) => `${t.platform}-${t.arch}`).join(", ");
122
+
123
+ if (result.reason === "ok") return null;
124
+ if (result.reason === "unsupported_platform") {
125
+ return `supervisor: unsupported platform ${platform}-${arch}; supported: ${targets}`;
126
+ }
127
+ if (result.reason === "platform_package_missing") {
128
+ if (isWindowsPrefixUnderUnix(platform, selfPath)) {
129
+ return (
130
+ `supervisor: platform package ${result.platformPackage} is missing because this is a Windows ` +
131
+ `npm install running under ${platform}.\n` +
132
+ ` This launcher lives at ${selfPath} — a Windows drive mount, not your ${platform} npm prefix.\n` +
133
+ ` Cause: a shared Windows ~/.npmrc 'prefix=' (e.g. C:\\Users\\<you>\\.npm-global) is bleeding ` +
134
+ `into ${platform}, so 'npm install -g' lands in the Windows prefix and only ships the Windows binary.\n` +
135
+ ` Give ${platform} its own npm prefix, then reinstall:\n` +
136
+ ` npm config set prefix "$HOME/.npm-global"\n` +
137
+ ` export PATH="$HOME/.npm-global/bin:$PATH" # ahead of any /mnt/* entries; add to ~/.profile to persist\n` +
138
+ ` hash -r && npm install -g coding-supervisor@latest\n` +
139
+ ` Verify with: which supervisor # expect $HOME/.npm-global/bin/supervisor, not /mnt/...\n` +
140
+ ` Then rerun: supervisor install --harness <name> --project <dir>`
141
+ );
142
+ }
143
+ return (
144
+ `supervisor: platform package ${result.platformPackage} not installed or missing its binary. ` +
145
+ "Reinstall with optional dependencies enabled: npm install -g coding-supervisor@latest"
146
+ );
147
+ }
148
+ if (result.reason === "invalid_binary") {
149
+ return "supervisor: internal error: invalid binary name passed to resolver";
150
+ }
151
+ return `supervisor: unknown resolver state ${result.reason}`;
152
+ }
153
+
154
+ module.exports = {
155
+ ALLOWED_BINARIES,
156
+ SUPPORTED_TARGETS,
157
+ formatResolveError,
158
+ resolveBinary,
159
+ };
package/package.json CHANGED
@@ -1,6 +1,36 @@
1
1
  {
2
2
  "name": "coding-supervisor",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0-rc4",
4
+ "description": "Completion gate for coding agents: a task is done only when every mandatory check has a current, observed receipt",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/special-place-ai-heaven/coding-supervisor"
9
+ },
10
+ "bin": {
11
+ "supervisor": "bin/supervisor.js"
12
+ },
13
+ "scripts": {
14
+ "test": "node --test tests/*.test.js"
15
+ },
16
+ "optionalDependencies": {
17
+ "coding-supervisor-linux-x64": "0.1.0-rc4",
18
+ "coding-supervisor-windows-x64": "0.1.0-rc4"
19
+ },
20
+ "files": [
21
+ "bin/",
22
+ "lib/",
23
+ "LICENSE"
24
+ ],
25
+ "keywords": [
26
+ "mcp",
27
+ "claude-code",
28
+ "codex",
29
+ "coding-agents",
30
+ "verification",
31
+ "hooks"
32
+ ],
33
+ "engines": {
34
+ "node": ">=18"
35
+ }
36
+ }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.