@ericrisco/rsc 2.0.6 → 2.0.7

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/manifest.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.0.6",
2
+ "version": "2.0.7",
3
3
  "counts": {
4
4
  "skills": 273,
5
5
  "agents": 33,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ericrisco/rsc",
3
- "version": "2.0.6",
3
+ "version": "2.0.7",
4
4
  "description": "A guided harness builder that turns your goal into a minimal, verified AI-agent setup using strict best practices.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,8 +18,8 @@
18
18
  // read. Anything it cannot read with certainty (editor commit, -F file, --amend
19
19
  // --no-edit, an unparseable command) is ALLOWED: a guard that guesses is a guard that
20
20
  // gets turned off. Every deny names its recovery. Opt out with .rsc/.no-gitmoji.
21
- import { pathToFileURL } from 'node:url';
22
- import { existsSync, readFileSync } from 'node:fs';
21
+ import { fileURLToPath } from 'node:url';
22
+ import { existsSync, readFileSync, realpathSync } from 'node:fs';
23
23
  import { join } from 'node:path';
24
24
 
25
25
  // The official gitmoji set (gitmoji.dev/api/gitmojis), as data: [emoji, code, semver, meaning].
@@ -222,7 +222,34 @@ export function denyMessage(message) {
222
222
 
223
223
  // ---- hook entrypoint -----------------------------------------------------------
224
224
  // Skipped when imported by a test (P2: the mechanism is testable without a subprocess).
225
- if (import.meta.url === pathToFileURL(process.argv[1]).href) {
225
+ /**
226
+ * "Was this file run directly?" — the same question `clone-bootstrap.mjs` answers, and the same two
227
+ * traps, so the same answer. Written out here rather than imported because hooks are materialized
228
+ * file by file under `.rsc/`: an import would be a second file to copy for six lines.
229
+ *
230
+ * `process.argv[1]` MAY NOT EXIST. Under `node -e`, `--input-type=module` or the REPL there is no
231
+ * script path, and `pathToFileURL(undefined)` throws — at module load, so merely IMPORTING this
232
+ * file takes the importer down with it. A module that cannot be imported is a module nobody can
233
+ * build a tool on top of, and people do exactly that with this package.
234
+ *
235
+ * SYMLINKS MAKE THE TWO SIDES DISAGREE. `import.meta.url` is what the loader resolved (symlinks
236
+ * RESOLVED); `process.argv[1]` is the raw string the client passed (symlinks INTACT). One
237
+ * symlinked component — `/tmp` and `/var` on macOS, or an ordinary `~/code -> /Volumes/…` — and a
238
+ * string compare says "no", the main block never runs, node exits 0 having printed nothing, and
239
+ * the hook becomes a silent no-op that `doctor` still reports as wired.
240
+ */
241
+ function isMainModule(metaUrl) {
242
+ const invoked = process.argv[1];
243
+ if (!invoked) return false;
244
+ const self = fileURLToPath(metaUrl);
245
+ try {
246
+ return realpathSync(self) === realpathSync(invoked);
247
+ } catch {
248
+ return self === invoked;
249
+ }
250
+ }
251
+
252
+ if (isMainModule(import.meta.url)) {
226
253
  const root = process.argv[2] || process.cwd();
227
254
  const allow = () => process.exit(0);
228
255
 
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { pathToFileURL } from 'node:url';
3
- import { existsSync, readFileSync } from 'node:fs';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { existsSync, readFileSync, realpathSync } from 'node:fs';
4
4
  import { resolve, join, dirname } from 'node:path';
5
5
  import { capture, resume } from './session-memory-core.mjs';
6
6
 
@@ -126,7 +126,34 @@ function stdinJson() {
126
126
  }
127
127
  }
128
128
 
129
- if (import.meta.url === pathToFileURL(process.argv[1]).href) {
129
+ /**
130
+ * "Was this file run directly?" — the same question `clone-bootstrap.mjs` answers, and the same two
131
+ * traps, so the same answer. Written out here rather than imported because hooks are materialized
132
+ * file by file under `.rsc/`: an import would be a second file to copy for six lines.
133
+ *
134
+ * `process.argv[1]` MAY NOT EXIST. Under `node -e`, `--input-type=module` or the REPL there is no
135
+ * script path, and `pathToFileURL(undefined)` throws — at module load, so merely IMPORTING this
136
+ * file takes the importer down with it. A module that cannot be imported is a module nobody can
137
+ * build a tool on top of, and people do exactly that with this package.
138
+ *
139
+ * SYMLINKS MAKE THE TWO SIDES DISAGREE. `import.meta.url` is what the loader resolved (symlinks
140
+ * RESOLVED); `process.argv[1]` is the raw string the client passed (symlinks INTACT). One
141
+ * symlinked component — `/tmp` and `/var` on macOS, or an ordinary `~/code -> /Volumes/…` — and a
142
+ * string compare says "no", the main block never runs, node exits 0 having printed nothing, and
143
+ * the hook becomes a silent no-op that `doctor` still reports as wired.
144
+ */
145
+ function isMainModule(metaUrl) {
146
+ const invoked = process.argv[1];
147
+ if (!invoked) return false;
148
+ const self = fileURLToPath(metaUrl);
149
+ try {
150
+ return realpathSync(self) === realpathSync(invoked);
151
+ } catch {
152
+ return self === invoked;
153
+ }
154
+ }
155
+
156
+ if (isMainModule(import.meta.url)) {
130
157
  const result = handleLifecycle({ target: process.argv[2], event: process.argv[3], native: stdinJson() });
131
158
  process.stdout.write(`${JSON.stringify(result.output)}\n`);
132
159
  }