cursedops 0.19.1 → 0.19.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.
- package/package.json +1 -1
- package/src/paths.ts +11 -0
- package/src/workerDeploy.ts +21 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cursedops",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.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, the billed-CPU tail check around a deploy's walk and smoke, and each app's worker:secrets and worker:smoke main as one function of its data), the relay a Worker fronts a Mac-bound app with (the Durable Object, the frames, the Mac's dialer and key rotation — lifted from station for roms — and the signed-in stage walk's skeleton and the relay app's whole worker:deploy), the Worker import-graph and await-port checks every Worker app's suite runs over its own source, 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": {
|
package/src/paths.ts
CHANGED
|
@@ -161,6 +161,13 @@ export function runGenerationLaws(from: string, options: LawsOptions = {}): numb
|
|
|
161
161
|
* `scripts/paths.ts` rather than copy a thirteenth wrapper; this is the one place it lives now.
|
|
162
162
|
* A gate that ran `check-paths` before scheduling its own `paths` stage would run it twice, and
|
|
163
163
|
* would pass `--force` to a law that has no idea what it means.
|
|
164
|
+
*
|
|
165
|
+
* 🔴 A `--` ends this wrapper's flags: it and everything after it go to the law verbatim, because
|
|
166
|
+
* that is the command a law like `suite-once.ts` wraps. Reading past it took the inner
|
|
167
|
+
* `forge-paths --only timed.ts` of `forge-paths --only suite-once.ts browser-test -- forge-paths
|
|
168
|
+
* --only timed.ts browser-test -- bun test …` as this wrapper's, so the wrapped command became a bare
|
|
169
|
+
* `forge-paths` and the browser suite ran nothing and stamped green (forge task
|
|
170
|
+
* cursedops-forge-paths-takes-an-inner-only, 2026-10-23).
|
|
164
171
|
*/
|
|
165
172
|
export function parseLawsArgv(argv: readonly string[]): { also: string[]; only: string[]; argv: string[] } {
|
|
166
173
|
const also: string[] = [];
|
|
@@ -168,6 +175,10 @@ export function parseLawsArgv(argv: readonly string[]): { also: string[]; only:
|
|
|
168
175
|
const rest: string[] = [];
|
|
169
176
|
for (let i = 0; i < argv.length; i++) {
|
|
170
177
|
const arg = argv[i] as string;
|
|
178
|
+
if (arg === "--") {
|
|
179
|
+
rest.push(...argv.slice(i));
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
171
182
|
const flag = arg === "--also" ? also : arg === "--only" ? only : null;
|
|
172
183
|
if (flag) {
|
|
173
184
|
const next = argv[i + 1];
|
package/src/workerDeploy.ts
CHANGED
|
@@ -802,6 +802,23 @@ export function runWorkerDeploy(spec: WorkerDeploySpec, deps: DeployDeps): Deplo
|
|
|
802
802
|
return finish({ code: 1, step, detail, commit, dirty });
|
|
803
803
|
};
|
|
804
804
|
const step = (message: string): void => log(`\n▸ ${message}`);
|
|
805
|
+
/**
|
|
806
|
+
* 🔴 The clean-tree refusal, asked again where production READS the tree (forge task 3601). It
|
|
807
|
+
* was asked once, at the start — and the stage leg is minutes long. On 2026-10-23 the ship's
|
|
808
|
+
* station lane passed it clean at 9ab4e676, deployed the stage clean, then built production from
|
|
809
|
+
* a session's half-written edit landed in between: `build.json` stamped `9ab4e676 (dirty)`, and
|
|
810
|
+
* only the asset budget stopped a production that would have reported one commit and run
|
|
811
|
+
* another. So before the production build, and again before anything is uploaded, HEAD must
|
|
812
|
+
* still be the commit stamped and the tree must still be clean.
|
|
813
|
+
*/
|
|
814
|
+
const moved = (during: string): DeployResult | null => {
|
|
815
|
+
if (spec.env !== "production") return null;
|
|
816
|
+
const head = deps.git(["rev-parse", "HEAD"]);
|
|
817
|
+
const now = deps.git(["status", "--porcelain"]);
|
|
818
|
+
if (head === commit && now.length === 0) return null;
|
|
819
|
+
const what = head !== commit ? `HEAD is now ${head.slice(0, 8) || "unreadable"}, not ${commit.slice(0, 8)}` : `it has uncommitted changes:\n${now}`;
|
|
820
|
+
return stop("tree-moved", `the tree moved ${during} — ${what}\nProduction would report ${commit.slice(0, 8)} and run something else, so nothing was deployed to it. Deploy again once the tree is still.`);
|
|
821
|
+
};
|
|
805
822
|
/** What passed under a CPU tail that never attached — decision 6 of the CPU check. */
|
|
806
823
|
const unmeasured: string[] = [];
|
|
807
824
|
|
|
@@ -879,6 +896,8 @@ export function runWorkerDeploy(spec: WorkerDeploySpec, deps: DeployDeps): Deplo
|
|
|
879
896
|
else if (walked !== 0) return stop("stage", `\`${command.join(" ")}\` failed — production was NOT touched.`);
|
|
880
897
|
}
|
|
881
898
|
}
|
|
899
|
+
const beforeBuild = moved(spec.stageFirst?.length || spec.stageWalk?.length ? "while the stage deployed" : "before the build");
|
|
900
|
+
if (beforeBuild) return beforeBuild;
|
|
882
901
|
if (spec.build) {
|
|
883
902
|
step("build");
|
|
884
903
|
enter("build");
|
|
@@ -889,6 +908,8 @@ export function runWorkerDeploy(spec: WorkerDeploySpec, deps: DeployDeps): Deplo
|
|
|
889
908
|
const why = refusal();
|
|
890
909
|
if (why) return stop("refusal", `${why} — nothing was deployed.`);
|
|
891
910
|
}
|
|
911
|
+
const beforeUpload = moved("while it built");
|
|
912
|
+
if (beforeUpload) return beforeUpload;
|
|
892
913
|
const envArgs = wranglerEnvArgs(spec.env);
|
|
893
914
|
if (spec.databaseName) {
|
|
894
915
|
const schema = spec.schemaFile ?? "db/schema.sql";
|