@buildinternet/uploads 0.42.1 → 0.42.2

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.
@@ -2,12 +2,20 @@
2
2
  * Install thin user-global hook manifests for Grok and Cursor.
3
3
  *
4
4
  * Claude and Codex ship the same PreToolUse hook via their plugins
5
- * (`hooks/hooks.json` → `uploads hook pre-pr-screenshot`). Do not also write
5
+ * (`hooks/hooks.json` → HOOK_COMMAND). Do not also write
6
6
  * ~/.codex/hooks.json here, or the reminder would fire twice.
7
7
  *
8
8
  * Idempotent: skip when our command string is already present.
9
+ * An older bare `uploads hook …` entry is upgraded in place.
9
10
  */
10
- export declare const HOOK_COMMAND = "uploads hook pre-pr-screenshot";
11
+ /** What the harness actually runs once `uploads` is on PATH. */
12
+ export declare const HOOK_INVOCATION = "uploads hook pre-pr-screenshot";
13
+ /**
14
+ * Fail-open shell used in every harness manifest.
15
+ * A missing `uploads` binary is a silent no-op (exit 0, no stderr) so plugin
16
+ * users without the CLI do not get a hook-failure annotation on every shell tool.
17
+ */
18
+ export declare const HOOK_COMMAND = "if command -v uploads >/dev/null 2>&1; then uploads hook pre-pr-screenshot; fi";
11
19
  export type HookWriteResult = {
12
20
  path: string;
13
21
  action: "wrote" | "merged" | "skipped" | "would-write" | "would-merge";
@@ -2,15 +2,23 @@
2
2
  * Install thin user-global hook manifests for Grok and Cursor.
3
3
  *
4
4
  * Claude and Codex ship the same PreToolUse hook via their plugins
5
- * (`hooks/hooks.json` → `uploads hook pre-pr-screenshot`). Do not also write
5
+ * (`hooks/hooks.json` → HOOK_COMMAND). Do not also write
6
6
  * ~/.codex/hooks.json here, or the reminder would fire twice.
7
7
  *
8
8
  * Idempotent: skip when our command string is already present.
9
+ * An older bare `uploads hook …` entry is upgraded in place.
9
10
  */
10
11
  import fs from "node:fs";
11
12
  import os from "node:os";
12
13
  import path from "node:path";
13
- export const HOOK_COMMAND = "uploads hook pre-pr-screenshot";
14
+ /** What the harness actually runs once `uploads` is on PATH. */
15
+ export const HOOK_INVOCATION = "uploads hook pre-pr-screenshot";
16
+ /**
17
+ * Fail-open shell used in every harness manifest.
18
+ * A missing `uploads` binary is a silent no-op (exit 0, no stderr) so plugin
19
+ * users without the CLI do not get a hook-failure annotation on every shell tool.
20
+ */
21
+ export const HOOK_COMMAND = `if command -v uploads >/dev/null 2>&1; then ${HOOK_INVOCATION}; fi`;
14
22
  const TIMEOUT_SEC = 15;
15
23
  const GROK_PAYLOAD = {
16
24
  description: "Advisory reminder to stage screenshots on uploads.sh before opening a PR that touches UI files.",
@@ -38,6 +46,16 @@ function containsCommand(filePath) {
38
46
  return false;
39
47
  }
40
48
  }
49
+ function hookCommandOf(entry) {
50
+ if (!entry || typeof entry !== "object")
51
+ return undefined;
52
+ const command = entry.command;
53
+ return typeof command === "string" ? command : undefined;
54
+ }
55
+ function isOurHookEntry(entry) {
56
+ const command = hookCommandOf(entry);
57
+ return Boolean(command?.includes(HOOK_INVOCATION));
58
+ }
41
59
  function writeJson(filePath, value) {
42
60
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
43
61
  fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
@@ -79,7 +97,17 @@ function mergeCursor(home, dryRun) {
79
97
  ? { ...existing.hooks }
80
98
  : {};
81
99
  const list = Array.isArray(hooks.beforeShellExecution) ? [...hooks.beforeShellExecution] : [];
82
- list.push({ command: HOOK_COMMAND, timeout: TIMEOUT_SEC });
100
+ const ours = list.findIndex(isOurHookEntry);
101
+ const nextEntry = { command: HOOK_COMMAND, timeout: TIMEOUT_SEC };
102
+ if (ours >= 0) {
103
+ if (hookCommandOf(list[ours]) === HOOK_COMMAND) {
104
+ return { path: filePath, action: "skipped" };
105
+ }
106
+ list[ours] = { ...list[ours], ...nextEntry };
107
+ }
108
+ else {
109
+ list.push(nextEntry);
110
+ }
83
111
  hooks.beforeShellExecution = list;
84
112
  existing.hooks = hooks;
85
113
  if (existing.version === undefined)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buildinternet/uploads",
3
- "version": "0.42.1",
3
+ "version": "0.42.2",
4
4
  "description": "CLI and client for uploads.sh — workspace-scoped image hosting for GitHub embeds",
5
5
  "type": "module",
6
6
  "sideEffects": false,