Skip to content

Commit 3ebb161

Browse files
committed
build(scripts): convert every remaining .mjs/.d.mts pair to real .ts
Same motivation as the prior commit, extended to scripts/: a hand-maintained .d.mts alongside a .mjs is exactly the duplicated-declaration problem the TypeScript migration was supposed to eliminate, and it can silently drift from the real implementation with no compiler ever checking it. Converts all 39 remaining scripts/*.mjs files that had one -- the mcp-release/ orb-release family, every docs/settings/schema drift checker, and the rest of the standalone generators -- to real .ts, inferring each function's types from its actual behavior rather than trusting the old declaration, per the pattern proven out on the miner/mcp packages. Nothing in scripts/ was ever part of Codecov's coverage surface, so this adds no coverage obligation; it's a straight type-safety and drift-elimination win. Real drift the old .d.mts files had already accumulated, found while converting: - check-schema-drift.ts read a table's name via SQLiteTable.Symbol.Name, an @internal drizzle-orm symbol never in its public type exports (which is exactly why the old hand-written declaration typed it without complaint) -- switched to the public getTableName(). - ci-duration-report.ts's WorkflowRun type was missing the `event` field the code actually filters on. - orb-release-core.ts's IMAGE_RELEVANT_PREFIXES still named two sibling scripts by their old .mjs filenames, now renamed here too -- a commit touching either file under its real name would have silently stopped counting as image-relevant. Every consumer updated to match: .js-suffixed import specifiers (Vite/ esbuild/Wrangler already resolve these to the sibling .ts, same as the prior commit), test imports, and every real invocation site. A script whose own file stays .mjs but now imports something converted here (e.g. check-mcp-package.mjs importing forbidden-content.ts) needs tsx instead of plain node, since only tsx (not node --experimental-strip-types) resolves a same-directory .ts import transitively; a script with zero local imports uses --experimental-strip-types directly, cheaper than spawning tsx. Covers every affected npm script, the three release-watch GitHub workflows (which previously needed no npm install at all -- added ./.github/actions/setup-workspace to each), the Dockerfile, and deploy-selfhost-prebuilt.sh. That last category caught two live regressions already sitting on this branch from the prior commit, beyond the one this commit's own check-miner-deployment-docs.ts conversion fixes (that one's what's been failing this PR's own CI): packages/loopover-miner/scripts/ generate-env-reference.mjs (npm run miner:env-reference, part of test:ci) and the Dockerfile/deploy-selfhost-prebuilt.sh's validate-selfhost-sourcemap invocations were both silently broken the same way -- caught by grepping for every remaining literal .mjs reference to a converted filename repo-wide, not by any test, since the one existing test for the miner env-reference generator imports it through Vite (which already tolerates the mismatch) rather than spawning it as the real subprocess the npm script actually runs.
1 parent 5636cff commit 3ebb161

145 files changed

Lines changed: 1398 additions & 1701 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/contributing-to-loopover/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ Run the matching command(s) and **commit the regenerated file(s)** — CI fails
202202
| A Cloudflare binding/var in `wrangler.jsonc` | `npm run cf-typegen` | `worker-configuration.d.ts` |
203203
| Drizzle schema (`src/db/schema.ts`) | `npm run drizzle:generate` | the new `migrations/NNNN_*.sql` |
204204
| Added a raw-SQL migration | (none — just author it) | next **contiguous** `migrations/NNNN_snake.sql` |
205-
| `src/selfhost/**` (or a few other scanned files — see `scripts/gen-selfhost-env-reference.mjs`'s `DEFAULT_SOURCE_ROOTS`) adding/removing an `env.SOMETHING` read | `npm run selfhost:env-reference` | `apps/loopover-ui/src/lib/selfhost-env-reference.ts` — the doc cites the file only (not `file:line`, deliberately, so an unrelated line shift elsewhere in the file never makes this go stale) |
205+
| `src/selfhost/**` (or a few other scanned files — see `scripts/gen-selfhost-env-reference.ts`'s `DEFAULT_SOURCE_ROOTS`) adding/removing an `env.SOMETHING` read | `npm run selfhost:env-reference` | `apps/loopover-ui/src/lib/selfhost-env-reference.ts` — the doc cites the file only (not `file:line`, deliberately, so an unrelated line shift elsewhere in the file never makes this go stale) |
206206
| CLI command surface | `npm run command-reference` | the generated command-reference doc |
207207
| UI files (`apps/loopover-ui/**`) | `npm --workspace @loopover/ui run format` | formatted files |
208208

.claude/skills/contributing-to-loopover/reference.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ validate the real publishable artifact still compiles and packs cleanly.
6767
Every `vitest.config.ts` in the repo (root, `vitest.workers.config.ts`, and every workspace with its own
6868
config) wires this as `globalSetup`, so it runs once before any test file regardless of how vitest was
6969
invoked — including a direct `npx vitest run test/unit/<file>.test.ts`, which this doc's own §6 ("Iterate,
70-
then verify") recommends for fast iteration. `scripts/check-node-version.mjs`'s `pretest*` hooks
70+
then verify") recommends for fast iteration. `scripts/check-node-version.ts`'s `pretest*` hooks
7171
(`package.json`) only cover 5 high-traffic npm script names (`test`, `test:ci`, `test:coverage`,
7272
`test:workers`, `ui:test`) as a genuinely-faster fail there (before npm even spawns vitest) — they are a
7373
nicety on top of the globalSetup guarantee, not a substitute for it. An earlier version of this guard was

.github/workflows/ci-duration-report.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
- name: Pull ci.yml run stats
3434
env:
3535
GITHUB_TOKEN: ${{ github.token }}
36-
run: node scripts/ci-duration-report.mjs --days=7 --output=ci-duration-report.json
36+
run: node --experimental-strip-types scripts/ci-duration-report.ts --days=7 --output=ci-duration-report.json
3737
- name: Write summary
3838
run: |
3939
node <<'NODE'

.github/workflows/ci.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ jobs:
117117
- 'apps/loopover-extension/**'
118118
- 'apps/loopover-miner-extension/**'
119119
- 'packages/loopover-ui-kit/**'
120-
- 'scripts/build-extension.mjs'
121-
- 'scripts/build-miner-extension.mjs'
120+
- 'scripts/build-extension.ts'
121+
- 'scripts/build-miner-extension.ts'
122122
- 'package.json'
123123
- 'package-lock.json'
124124
# Backend changes that can drift the OpenAPI contract the UI type-checks against, but say
@@ -370,7 +370,7 @@ jobs:
370370
if: ${{ github.event_name == 'push' || needs.changes.outputs.observability == 'true' }}
371371
env:
372372
NODE_OPTIONS: ""
373-
run: node scripts/validate-observability-configs.mjs
373+
run: node --experimental-strip-types scripts/validate-observability-configs.ts
374374
# Runs ahead of Typecheck AND "Test with coverage" (#ci-engine-build-order): src/mcp/find-opportunities.ts
375375
# (root backend, since #2281/#3985) imports packages/loopover-miner/lib/opportunity-fanout.js --
376376
# a .js-suffixed specifier esbuild/Vite resolve straight to the real (gitignored, uncompiled)
@@ -523,7 +523,7 @@ jobs:
523523
- name: Miner package check
524524
if: ${{ github.event_name == 'push' || needs.changes.outputs.miner == 'true' || needs.changes.outputs.engine == 'true' }}
525525
run: npm run test:miner-pack
526-
# scripts/check-miner-deployment-docs.mjs reads packages/loopover-engine/src/miner/**/*.ts
526+
# scripts/check-miner-deployment-docs.ts reads packages/loopover-engine/src/miner/**/*.ts
527527
# (ENGINE_MINER_DIR) to build the registered-commands list checked against DEPLOYMENT.md, so an
528528
# engine-only PR touching that directory used to skip this audit entirely.
529529
- name: Miner deployment docs audit

.github/workflows/gittensor-impact.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: Gittensor Impact
22

3-
# Renders the README contributor-impact card with scripts/gittensor-impact-card.mjs
3+
# Renders the README contributor-impact card with scripts/gittensor-impact-card.ts
44
# (our own script, styled to this repo's brand — see apps/loopover-ui/src/styles.css)
55
# and publishes it to the gittensor-impact-assets branch, which the README embeds
66
# directly. No third-party action: this replaced matthewevans/gittensor-impact-action
@@ -39,7 +39,7 @@ jobs:
3939
node-version: 22.23.1
4040

4141
- name: Render impact card
42-
run: node scripts/gittensor-impact-card.mjs JSONbored/loopover gittensor-impact-dark.svg
42+
run: node --experimental-strip-types scripts/gittensor-impact-card.ts JSONbored/loopover gittensor-impact-dark.svg
4343

4444
- name: Publish to gittensor-impact-assets
4545
env:

.github/workflows/mcp-release-please.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ jobs:
126126
set -euo pipefail
127127
git config user.name "github-actions[bot]"
128128
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
129-
trusted_sync_script="${RUNNER_TEMP}/sync-release-lockfile-versions.mjs"
130-
cp scripts/sync-release-lockfile-versions.mjs "$trusted_sync_script"
129+
trusted_sync_script="${RUNNER_TEMP}/sync-release-lockfile-versions.ts"
130+
cp scripts/sync-release-lockfile-versions.ts "$trusted_sync_script"
131131
git remote set-url origin "https://github.com/${GITHUB_REPOSITORY}.git"
132132
gh auth setup-git
133133
branches="$(git ls-remote --heads origin 'release-please--branches--main--*' | awk '{print $2}' | sed 's#refs/heads/##')"
@@ -137,7 +137,7 @@ jobs:
137137
for branch in $branches; do
138138
git fetch origin "$branch"
139139
git checkout -B "sync-check-$(printf '%s' "$branch" | tr '/' '-')" "origin/$branch"
140-
node "$trusted_sync_script" packages/loopover-mcp packages/loopover-engine packages/loopover-miner packages/loopover-ui-kit
140+
node --experimental-strip-types "$trusted_sync_script" packages/loopover-mcp packages/loopover-engine packages/loopover-miner packages/loopover-ui-kit
141141
if git diff --quiet package-lock.json; then
142142
echo "package-lock.json already in sync on $branch."
143143
else

.github/workflows/mcp-release-watch.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ jobs:
2424
fetch-depth: 0
2525
persist-credentials: false
2626

27-
- name: Setup Node
28-
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
29-
with:
30-
node-version-file: .nvmrc
27+
- name: Setup workspace
28+
uses: ./.github/actions/setup-workspace
3129

3230
- name: Check MCP release status
3331
env:
3432
GITHUB_TOKEN: ${{ github.token }}
35-
run: node scripts/check-mcp-release-due.mjs --json --output mcp-release-due.json --upsert-issue
33+
# check-mcp-release-due.ts imports mcp-release-core.ts directly, so it needs tsx (not plain node) to
34+
# resolve that local .ts import.
35+
run: npx tsx scripts/check-mcp-release-due.ts --json --output mcp-release-due.json --upsert-issue
3636

3737
- name: Summarize MCP release status
3838
run: |

.github/workflows/mcp-ui-version-sync.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Keeps apps/loopover-ui/src/lib/mcp-package.ts's MCP_PACKAGE_KNOWN_LATEST_VERSION -- the client-side
22
# graceful-degradation fallback shown when the live npm-registry fetch (useMcpPackageMetadata) fails or hasn't
33
# resolved yet -- in sync with @loopover/mcp's real npm dist-tags.latest, without ever requiring a human/agent
4-
# to notice a new release and manually edit the constant (#6580). scripts/check-ui-mcp-version-copy.mjs's
4+
# to notice a new release and manually edit the constant (#6580). scripts/check-ui-mcp-version-copy.ts's
55
# --write mode does the actual sync; this just runs it on a schedule and keeps a standing PR up to date, the
66
# same shape as orb-stable-release-pr.yml. Nothing ships until a maintainer reviews and merges the PR -- this
77
# workflow never pushes to main directly.
@@ -38,7 +38,7 @@ jobs:
3838

3939
# No npm ci -- the script only imports Node built-ins.
4040
- name: Sync the known-latest constant
41-
run: node scripts/check-ui-mcp-version-copy.mjs --write
41+
run: node --experimental-strip-types scripts/check-ui-mcp-version-copy.ts --write
4242

4343
- name: Check for a diff
4444
id: diff

.github/workflows/orb-beta-release.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# Automated ORB (self-host container image, ghcr.io/jsonbored/loopover-selfhost) beta channel.
22
# Daily (or on demand via workflow_dispatch), checks whether any image-relevant commit has landed
3-
# since the last orb-v tag (scripts/check-orb-release-due.mjs / scripts/orb-release-core.mjs) and,
3+
# since the last orb-v tag (scripts/check-orb-release-due.mjs / scripts/orb-release-core.ts) and,
44
# if so, cuts the next `orb-vX.Y.Z-beta.N` tag and dispatches release-selfhost.yml to build + publish
55
# it -- fully unattended: that workflow's `environment:` routes an actual beta version to
66
# `release-beta` (no required reviewers), while a stable/rc version still requires the human-gated
77
# `release` environment. Promoting a beta to a stable release stays a manual `git tag orb-vX.Y.Z` by
88
# a maintainer -- this workflow never bumps orb-manifest.json's version or cuts a non-beta tag.
99
#
1010
# Deliberately independent of the MCP package's release automation (mcp-release-watch.yml /
11-
# mcp-release-core.mjs) -- see scripts/orb-release-core.mjs's own header for why.
11+
# mcp-release-core.ts) -- see scripts/orb-release-core.ts's own header for why.
1212
name: orb-beta-release
1313

1414
on:
@@ -35,16 +35,16 @@ jobs:
3535
fetch-depth: 0
3636
persist-credentials: false
3737

38-
- name: Setup Node
39-
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
40-
with:
41-
node-version-file: .nvmrc
38+
- name: Setup workspace
39+
uses: ./.github/actions/setup-workspace
4240

4341
- name: Check whether an ORB beta is due
4442
id: report
43+
# check-orb-release-due.mjs imports orb-release-core.ts directly, so it needs tsx (not plain node) to
44+
# resolve that local .ts import.
4545
run: |
4646
set -euo pipefail
47-
node scripts/check-orb-release-due.mjs --json --output orb-release-due.json
47+
npx tsx scripts/check-orb-release-due.mjs --json --output orb-release-due.json
4848
node <<'NODE'
4949
const fs = require("node:fs");
5050
const report = JSON.parse(fs.readFileSync("orb-release-due.json", "utf8"));
@@ -60,7 +60,7 @@ jobs:
6060
# push alone. Mirrors publish-engine.yml / publish-mcp.yml's identical reasoning and tagging
6161
# idiom.
6262
# Exposes created=true/false so the dispatch step below never fires against a tag this run didn't
63-
# actually just create -- a defense-in-depth backstop (independent of orb-release-core.mjs's own
63+
# actually just create -- a defense-in-depth backstop (independent of orb-release-core.ts's own
6464
# correctness) against ever re-triggering a build for an already-published version/tag.
6565
- name: Tag the new beta
6666
id: tag

.github/workflows/orb-stable-release-pr.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Automated ORB (self-host container image, ghcr.io/jsonbored/loopover-selfhost) STABLE-channel Release PR --
22
# the release-please-equivalent for ORB, whose cross-cutting image-relevant scoping (src/** shared with
3-
# UI/MCP-only subtrees it must exclude -- see orb-release-core.mjs's IMAGE_RELEVANT_PREFIXES/EXCLUDED_PREFIXES)
3+
# UI/MCP-only subtrees it must exclude -- see orb-release-core.ts's IMAGE_RELEVANT_PREFIXES/EXCLUDED_PREFIXES)
44
# doesn't fit release-please's directory-component model the way packages/loopover-mcp and
55
# packages/loopover-engine do (see mcp-release-please.yml). Same UX contract as those, hand-rolled: on the
66
# same schedule (or on demand), (re)compute the next stable version from conventional commits since the last
7-
# STABLE orb-v tag (scripts/check-orb-stable-release-due.mjs / orb-release-core.mjs's buildOrbStableReleaseReport)
7+
# STABLE orb-v tag (scripts/check-orb-stable-release-due.mjs / orb-release-core.ts's buildOrbStableReleaseReport)
88
# and keep a standing `release-orb-stable` branch + PR in sync with that proposal. Nothing ships until a
99
# maintainer reviews and merges it -- see orb-stable-release-tag.yml for what happens then. Never touches the
1010
# daily fully-unattended beta channel (orb-beta-release.yml).
@@ -34,16 +34,16 @@ jobs:
3434
fetch-depth: 0
3535
persist-credentials: false
3636

37-
- name: Setup Node
38-
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
39-
with:
40-
node-version-file: .nvmrc
37+
- name: Setup workspace
38+
uses: ./.github/actions/setup-workspace
4139

4240
- name: Check whether a stable ORB release is due
4341
id: report
42+
# check-orb-stable-release-due.mjs imports orb-release-core.ts directly, so it needs tsx (not plain
43+
# node) to resolve that local .ts import.
4444
run: |
4545
set -euo pipefail
46-
node scripts/check-orb-stable-release-due.mjs --json --output orb-stable-release-due.json
46+
npx tsx scripts/check-orb-stable-release-due.mjs --json --output orb-stable-release-due.json
4747
node <<'NODE'
4848
const fs = require("node:fs");
4949
const report = JSON.parse(fs.readFileSync("orb-stable-release-due.json", "utf8"));

0 commit comments

Comments
 (0)