cursedops 0.2.3 → 0.2.5
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/README.md +12 -1
- package/package.json +1 -1
- package/src/apiFloor.ts +13 -4
- package/src/roots.ts +48 -2
package/README.md
CHANGED
|
@@ -88,6 +88,12 @@ A generation is defined by a `forge.env` above the checkout — the same rule it
|
|
|
88
88
|
`null` rather than guessing, because a function that invented a root would write files
|
|
89
89
|
into a stranger's tree.
|
|
90
90
|
|
|
91
|
+
🔴 **A git worktree counts** (0.2.5). Worktrees live outside every generation by
|
|
92
|
+
construction, so the walk up alone answered `null` there and a repo whose gate asks for
|
|
93
|
+
the root was red in every worktree — the runner's subset gate included. When the walk
|
|
94
|
+
fails, `git rev-parse --git-common-dir` leads back to the primary checkout and the walk
|
|
95
|
+
runs from there. A clone is its own primary and still gets `null`.
|
|
96
|
+
|
|
91
97
|
🔴 The state root is **read out of `forge.env`**, never spelled here. A published
|
|
92
98
|
library that hardcoded `$HOME/.<name>` would be correct for exactly one generation and
|
|
93
99
|
silently wrong for its successor — which is the defect this replaced.
|
|
@@ -156,7 +162,7 @@ const floor = (c) => {
|
|
|
156
162
|
if (canonicalApiPath(urlPath) !== null) return app.fetch(canonicalApiRequest(c.req.raw));
|
|
157
163
|
return Response.json(apiNotFoundBody(c.req.method, urlPath, "myapp", commit), { status: 404 });
|
|
158
164
|
};
|
|
159
|
-
app.all(API_PREFIX, floor);
|
|
165
|
+
app.all(API_PREFIX, floor);
|
|
160
166
|
app.all(`${API_PREFIX}/*`, floor);
|
|
161
167
|
```
|
|
162
168
|
|
|
@@ -173,6 +179,11 @@ drives `app.fetch` — and a wrap installed at one of them is absent from the re
|
|
|
173
179
|
the exact fault the previous generation's artifact shipped for six days with a green
|
|
174
180
|
harness.
|
|
175
181
|
|
|
182
|
+
Both patterns are registered although `"/api/*"` alone already matches a bare `/api` on
|
|
183
|
+
hono@4.13.7 (measured 2026-09-18) — that is an undocumented property of one matcher
|
|
184
|
+
version, and one extra route registration is cheaper than a floor with a hole in it the
|
|
185
|
+
day it tightens.
|
|
186
|
+
|
|
176
187
|
No `node:` import, no `Bun.` global, no `process` — asserted by `apiFloor.test.ts`, not
|
|
177
188
|
by this paragraph — so it mounts unchanged inside a Cloudflare Worker, which is where
|
|
178
189
|
`patterns` mounts it. `apiNotFoundBody` is the DEFAULT body and not the only one: an app
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cursedops",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "The build-and-ops answers this generation's apps wrote independently and identically: finding a generation's roots without knowing a path, macOS launchd agent install/replace/remove, the scaffolding of a deployed smoke, and the static-serving helpers eight apps copied — the path-traversal guard among them — and the API floor that keeps an unmatched /api/... from ever being answered with the app shell. Mechanism only — no app knows its name from here. Bun, zero dependencies, ships source.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
package/src/apiFloor.ts
CHANGED
|
@@ -50,10 +50,19 @@ export const API_PREFIX = "/api";
|
|
|
50
50
|
/**
|
|
51
51
|
* Is this path inside the API namespace? `/api` itself counts; `/apiary` does not.
|
|
52
52
|
*
|
|
53
|
-
* 🔴
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
53
|
+
* 🔴 `/apiary` and `/api-docs` are the cases a `startsWith("/api")` gets wrong, and they
|
|
54
|
+
* are page URLs — a floor that swallowed them would answer JSON where the client expects
|
|
55
|
+
* its own route. The namespace ITSELF counting is the other half: a caller that types
|
|
56
|
+
* `/api` by hand is inside it.
|
|
57
|
+
*
|
|
58
|
+
* 🔴 **This does NOT mirror what Hono's router does, and the difference is the reason to
|
|
59
|
+
* register both patterns.** Measured 2026-09-18 against hono@4.13.7: `app.all("/api/*")`
|
|
60
|
+
* already matches a bare `/api` — the `*` matches zero segments including the slash in
|
|
61
|
+
* front of it. So `app.all(API_PREFIX, floor)` is redundant TODAY. It is in the wiring
|
|
62
|
+
* anyway because that is an undocumented property of one matcher version, it costs one
|
|
63
|
+
* route registration, and the alternative is a floor with a hole in it the day the
|
|
64
|
+
* matcher tightens. What proves the rule is each app's spec asking for `/api` and
|
|
65
|
+
* getting the phrase — never this arithmetic.
|
|
57
66
|
*/
|
|
58
67
|
export const isApiPath = (urlPath: string): boolean =>
|
|
59
68
|
urlPath === API_PREFIX || urlPath.startsWith(`${API_PREFIX}/`);
|
package/src/roots.ts
CHANGED
|
@@ -31,6 +31,20 @@
|
|
|
31
31
|
* doing nothing and saying so; {@link requireForgeState} is the one-line way to do
|
|
32
32
|
* that with a message worth reading.
|
|
33
33
|
*
|
|
34
|
+
* 🔴 **A git worktree of a generation's repo IS inside that generation**, even though no
|
|
35
|
+
* `forge.env` sits above it: the working agreement puts every worktree under the
|
|
36
|
+
* machine-wide worktrees root, outside every generation by construction. Walking up
|
|
37
|
+
* from one finds nothing, so until 0.2.5 every caller here answered `null` in the
|
|
38
|
+
* one place agents are told to work — and the runner's subset gate, which proves a
|
|
39
|
+
* pathspec commit in a throwaway worktree, found `desk`'s gate red on EVERY change
|
|
40
|
+
* (`test/build/advisories-queue.test.ts` asks for the root; 2026-09-21, the
|
|
41
|
+
* `cursedauth` bump stranded for a day and blamed on the work). A worktree's `.git`
|
|
42
|
+
* is a file pointing at the primary checkout's git directory, so
|
|
43
|
+
* {@link findForgeRootViaWorktree} follows it back with no environment variable and
|
|
44
|
+
* no guess — the same rule every repo's `scripts/paths.ts` already used. A clone,
|
|
45
|
+
* an archive or a `node_modules` copy is not a worktree of anything in a generation
|
|
46
|
+
* and still gets `null`.
|
|
47
|
+
*
|
|
34
48
|
* 🔴 **This library is published, so it may not know a generation's NAME either.**
|
|
35
49
|
* `apps/flix/scripts/forgeRoot.ts` fell back to `$HOME/.cursedforge` when the
|
|
36
50
|
* environment carried no `FORGE_STATE`, which is correct for exactly one
|
|
@@ -39,6 +53,7 @@
|
|
|
39
53
|
* generation being called something else.
|
|
40
54
|
*/
|
|
41
55
|
|
|
56
|
+
import { spawnSync } from "node:child_process";
|
|
42
57
|
import { existsSync, readFileSync } from "node:fs";
|
|
43
58
|
import { dirname, join, resolve } from "node:path";
|
|
44
59
|
import { fileURLToPath } from "node:url";
|
|
@@ -71,9 +86,40 @@ function walkUp(from: string, marker: string): string | null {
|
|
|
71
86
|
return null;
|
|
72
87
|
}
|
|
73
88
|
|
|
74
|
-
/**
|
|
89
|
+
/**
|
|
90
|
+
* The generation above the checkout a git WORKTREE at `from` was cut from, or `null`.
|
|
91
|
+
*
|
|
92
|
+
* `git rev-parse --git-common-dir` names the primary checkout's git directory; the
|
|
93
|
+
* ordinary walk runs from the directory holding it. For a primary checkout, a clone
|
|
94
|
+
* or a plain repo that is its own `.git`, so the answer is exactly what the walk up
|
|
95
|
+
* from `from` already said. `null` on anything unexpected — no git, not a repo, a
|
|
96
|
+
* directory that is not there — because inventing a root is the failure this module
|
|
97
|
+
* is against.
|
|
98
|
+
*/
|
|
99
|
+
export function findForgeRootViaWorktree(from: string): string | null {
|
|
100
|
+
try {
|
|
101
|
+
const git = spawnSync("git", ["rev-parse", "--path-format=absolute", "--git-common-dir"], {
|
|
102
|
+
cwd: from,
|
|
103
|
+
encoding: "utf8",
|
|
104
|
+
timeout: 5_000,
|
|
105
|
+
});
|
|
106
|
+
if (git.status !== 0) return null;
|
|
107
|
+
const common = (git.stdout ?? "").trim();
|
|
108
|
+
if (!common.startsWith("/")) return null;
|
|
109
|
+
return walkUp(dirname(common), MARKER);
|
|
110
|
+
} catch {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The directory holding `forge.env`, or `null` when `from` is not inside a generation.
|
|
117
|
+
*
|
|
118
|
+
* The walk up first — the only answer for a launchd job, and git is never asked when
|
|
119
|
+
* it succeeds — then a worktree followed back to its primary checkout.
|
|
120
|
+
*/
|
|
75
121
|
export function findForgeRoot(from: string): string | null {
|
|
76
|
-
return walkUp(from, MARKER);
|
|
122
|
+
return walkUp(from, MARKER) ?? findForgeRootViaWorktree(from);
|
|
77
123
|
}
|
|
78
124
|
|
|
79
125
|
/** {@link findForgeRoot} from a module's own location. Pass `import.meta.url`. */
|