cursedops 0.5.1 → 0.5.3

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.
Files changed (3) hide show
  1. package/README.md +17 -2
  2. package/package.json +24 -7
  3. package/src/paths.ts +25 -7
package/README.md CHANGED
@@ -176,8 +176,13 @@ after `%h/` or `$HOME/` — never the generation's name.
176
176
  ```jsonc
177
177
  "paths": "forge-paths" // check-paths + check-doc-citations
178
178
  "paths": "forge-paths --also check-gate-graph.ts" // cursedbelt's extra law, as an OPTION
179
+ "gate": "forge-paths --only gate.ts" // 0.5.3: the shared gate runner, and ONLY it
179
180
  ```
180
181
 
182
+ `--only <law>` (0.5.3, task 474) replaces the default laws instead of adding to them, so a repo's
183
+ `gate` reaches `$FORGE/tools/gate.ts` through the same walk without running `check-paths` a
184
+ second time or handing it `--force`. A law it names that is missing from `tools/` exits 1.
185
+
181
186
  Rule 1, eighteen times: `scripts/paths.ts` was in every app, `autopilot` and every library,
182
187
  sixteen byte-identical and three already forked (`cursedbelt` +`check-gate-graph.ts`, `station`
183
188
  +`check-no-clock.ts`, `autopilot` split into its own `generation.ts`). `check-copies` prices
@@ -185,8 +190,18 @@ exported definitions and this file exports nothing, so eighteen copies read as z
185
190
  wrapper exists because `bun ../../tools/check-paths.ts .` died on its first step in every
186
191
  worktree (2026-09-17). The walk and the worktree follow-back are the copies' own; **no
187
192
  generation is still no pass** — a lone clone exits 1 saying which walk came back empty. Every
188
- argument that is not `--also` passes through to the laws (`bun run paths --prune`). This repo
189
- dogfoods it: `"paths": "bun src/paths.ts"`, and its own copy is gone.
193
+ argument that is not `--also`/`--only` passes through to the laws (`bun run paths --prune`).
194
+
195
+ 🔴 **Until the roster rule can read the bin, the wrapper is two lines that NAME the laws.**
196
+ `check-doc-citations`' `pathsRunsThis` proves a repo runs it by reading the `paths` command or
197
+ the one `scripts/` file it delegates to, so a bare `forge-paths` reads as unwired. The form that
198
+ passes today — and the one this repo uses — is:
199
+
200
+ ```ts
201
+ // scripts/paths.ts, with "paths": "bun run scripts/paths.ts"
202
+ import { runGenerationLaws } from "cursedops/paths";
203
+ process.exit(runGenerationLaws(import.meta.dir, { laws: ["check-paths.ts", "check-doc-citations.ts"], argv: process.argv.slice(2) }));
204
+ ```
190
205
 
191
206
  ## `cursedops/launchd`
192
207
 
package/package.json CHANGED
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "cursedops",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "description": "The build-and-ops answers this generation's apps wrote independently and identically: finding a generation's roots — and printing a command that runs when pasted — without knowing a path, the generation's whole-tree laws run over one repo from a checkout or a worktree, macOS launchd agent install/replace/remove and the live port a job serves, the scaffolding and verdicts of a deployed smoke (origin probe, the smoke's own environment, a network that lies about DNS, a settled version), the static-serving helpers eight apps copied — the path-traversal guard among them — the API floor that keeps an unmatched /api/... from ever being answered with the app shell, the commit and dirty flag a checkout-served process reports, the Cloudflare Worker deploy toolkit four apps copied (the deploy sequence, exact-set secrets over a pipe, origin-first rollback, the curl edge fetch, the row-for-row D1 import proof), and the public-surface ratchet three published libraries each carried a forked copy of. Mechanism only — no app knows its name from here. Bun, zero runtime dependencies (typescript is an optional peer, for public-surface only), ships source.",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "typecheck": "tsc -p tsconfig.json --noEmit",
8
- "lint": "biome check .",
9
- "test": "bun test src",
10
- "paths": "bun src/paths.ts",
11
- "verify": "bun run paths && bun run typecheck && bun run lint && bun run test",
12
- "prepublishOnly": "bun run verify"
8
+ "lint": "biome check --error-on-warnings .",
9
+ "test": "bun test --timeout 60000 --parallel=4 src",
10
+ "paths": "bun run scripts/paths.ts",
11
+ "verify": "bun run gate",
12
+ "prepublishOnly": "bun run gate --force",
13
+ "gate": "bun src/paths.ts --only gate.ts"
13
14
  },
14
15
  "exports": {
15
16
  "./roots": {
@@ -122,5 +123,21 @@
122
123
  "publishConfig": {
123
124
  "access": "public"
124
125
  },
125
- "license": "MIT"
126
+ "license": "MIT",
127
+ "gate": {
128
+ "stages": [
129
+ {
130
+ "script": "paths"
131
+ },
132
+ {
133
+ "script": "typecheck"
134
+ },
135
+ {
136
+ "script": "lint"
137
+ },
138
+ {
139
+ "script": "test"
140
+ }
141
+ ]
142
+ }
126
143
  }
package/src/paths.ts CHANGED
@@ -7,6 +7,7 @@
7
7
  * // package.json — the whole wiring; no scripts/paths.ts at all
8
8
  * "paths": "forge-paths" // check-paths + check-doc-citations
9
9
  * "paths": "forge-paths --also check-gate-graph.ts" // cursedbelt's extra law, as an OPTION
10
+ * "gate": "forge-paths --only gate.ts" // ONE tool, never the defaults
10
11
  * ```
11
12
  *
12
13
  * ```ts
@@ -150,24 +151,41 @@ export function runGenerationLaws(from: string, options: LawsOptions = {}): numb
150
151
  }
151
152
 
152
153
  /**
153
- * The bin's arguments: `--also <law>` / `--also=<law>` (repeatable) are this wrapper's; every
154
- * other argument goes through to the laws untouched, so `bun run paths --prune` still prunes.
154
+ * The bin's arguments: `--also <law>` and `--only <law>` (both repeatable, both also spelled
155
+ * `--flag=<law>`) are this wrapper's; every other argument goes through to the laws untouched,
156
+ * so `bun run paths --prune` still prunes and `bun run gate --force` still forces.
157
+ *
158
+ * 🔴 `--only` REPLACES {@link DEFAULT_LAWS}, it does not add to them. It exists for
159
+ * `"gate": "forge-paths --only gate.ts"` — the generation's shared gate runner, located the same
160
+ * way the laws are (task 474, 2026-09-23). Twelve apps had grown the same flag in their copied
161
+ * `scripts/paths.ts` rather than copy a thirteenth wrapper; this is the one place it lives now.
162
+ * A gate that ran `check-paths` before scheduling its own `paths` stage would run it twice, and
163
+ * would pass `--force` to a law that has no idea what it means.
155
164
  */
156
- export function parseLawsArgv(argv: readonly string[]): { also: string[]; argv: string[] } {
165
+ export function parseLawsArgv(argv: readonly string[]): { also: string[]; only: string[]; argv: string[] } {
157
166
  const also: string[] = [];
167
+ const only: string[] = [];
158
168
  const rest: string[] = [];
159
169
  for (let i = 0; i < argv.length; i++) {
160
170
  const arg = argv[i] as string;
161
- if (arg === "--also") {
171
+ const flag = arg === "--also" ? also : arg === "--only" ? only : null;
172
+ if (flag) {
162
173
  const next = argv[i + 1];
163
- if (next !== undefined) also.push(next);
174
+ if (next !== undefined) flag.push(next);
164
175
  i++;
165
176
  } else if (arg.startsWith("--also=")) also.push(arg.slice("--also=".length));
177
+ else if (arg.startsWith("--only=")) only.push(arg.slice("--only=".length));
166
178
  else rest.push(arg);
167
179
  }
168
- return { also, argv: rest };
180
+ return { also, only, argv: rest };
181
+ }
182
+
183
+ /** {@link parseLawsArgv}'s result as {@link LawsOptions}: `--only` becomes the whole list. */
184
+ export function lawsOptionsFromArgv(argv: readonly string[]): LawsOptions {
185
+ const { also, only, argv: rest } = parseLawsArgv(argv);
186
+ return { also, argv: rest, ...(only.length > 0 ? { laws: only } : {}) };
169
187
  }
170
188
 
171
189
  if (import.meta.main) {
172
- process.exit(runGenerationLaws(process.cwd(), parseLawsArgv(process.argv.slice(2))));
190
+ process.exit(runGenerationLaws(process.cwd(), lawsOptionsFromArgv(process.argv.slice(2))));
173
191
  }