Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
8e8a37e
ci: re-arm release-merge on every check-producing workflow
Shinrai Sep 28, 2026
80c5884
ci: re-arm release-merge on every check-producing workflow (#490)
Shinrai Sep 28, 2026
0c31d5c
chore: bump version to 3.21.1
cldmv-bot[bot] Sep 28, 2026
44b285e
fix(api): remove() no longer throws on a module's frozen or sealed ex…
Shinrai Sep 28, 2026
a281499
chore(tools): make analyze and i18n:check skip gitignored paths
Shinrai Sep 28, 2026
b8c9321
fix(package): stop shipping the rolldown native binding to consumers
Shinrai Sep 28, 2026
9999304
ci: measure the published JS files in the bundle-size workflow
Shinrai Sep 28, 2026
a4baf8b
ci: measure the published JS files in the bundle-size workflow (#494)
Shinrai Sep 28, 2026
475b090
chore(tools): make analyze and i18n:check skip gitignored paths (#492)
Shinrai Sep 28, 2026
5b2c1bd
fix(api): remove() no longer throws on a module's frozen or sealed ex…
Shinrai Sep 28, 2026
6d73b89
fix(package): stop shipping the rolldown native binding to consumers …
Shinrai Sep 28, 2026
9d9dca3
fix(unified-wrapper): land object/function writes through a live view…
Shinrai Sep 28, 2026
214459b
Merge remote-tracking branch 'origin/next' into fix/live-view-object-…
Shinrai Sep 28, 2026
0a5e031
fix(typescript): ship strict mode's type-generation worker in the pac…
Shinrai Sep 28, 2026
76073e4
fix(unified-wrapper): land object/function writes through a live view…
Shinrai Sep 28, 2026
a1bd77c
fix(context): route patched once through the emitter's own on/removeL…
Shinrai Sep 28, 2026
fbd6862
docs(typescript): use jsdoc-parseable callback types in the type-gene…
Shinrai Sep 28, 2026
a7c1fe5
test: assert resolve-from-caller returns the test file's directory, n…
Shinrai Sep 28, 2026
54e36bf
test: assert resolve-from-caller returns the test file's directory, n…
Shinrai Sep 28, 2026
2bab84d
fix(typescript): ship strict mode's type-generation worker in the pac…
Shinrai Sep 28, 2026
f2f65db
fix(context): route patched once through the emitter's own on/removeL…
Shinrai Sep 28, 2026
b0c5ef7
feat(typegen): type the composed api, self, and slothlet() from each …
Shinrai Sep 28, 2026
3f0a8e8
fix(wrapper): don't adopt a function's non-enumerable own properties …
Shinrai Sep 28, 2026
39f8464
feat(typegen): type the composed api, self, and slothlet() from each …
Shinrai Sep 28, 2026
d2ac48c
chore: bump version to 3.22.0
cldmv-bot[bot] Sep 28, 2026
aba22f8
feat(permissions): add global.checkCall — call-gate query with args, …
Shinrai Sep 28, 2026
7654b71
fix(events): evaluate event-rule conditions against the user context
Shinrai Sep 29, 2026
cf53e7b
feat(permissions): add global.checkCall — call-gate query with args, …
Shinrai Sep 29, 2026
bd1069b
fix(events): evaluate event-rule conditions against the user context …
Shinrai Sep 29, 2026
cad818d
fix(typescript): honour module, strict, compilerOptions and sourcemap…
Shinrai Sep 28, 2026
5620bfd
feat(permissions): add slothlet.lockCaller.caller to pin the calling …
Shinrai Sep 28, 2026
d7c414c
fix(typescript): honour module, strict, compilerOptions and sourcemap…
Shinrai Sep 29, 2026
067a822
feat(permissions): add slothlet.lockCaller.caller to pin the calling …
Shinrai Sep 29, 2026
0a303ef
fix(context): attribute live-runtime callers by what is actually in f…
Shinrai Sep 29, 2026
eb8ce71
fix(context): answer a host-pinned call as the host on the running-ca…
Shinrai Sep 29, 2026
6edafe5
chore: add the missing file header to event-rule-condition-context.te…
Shinrai Sep 29, 2026
183c31e
fix: attribute live-runtime callers by what is actually in flight (#519)
Shinrai Sep 29, 2026
830687d
feat(hooks): add an around hook type that wraps the call pipeline
Shinrai Sep 28, 2026
8411e7c
deps: update @cldmv/vitest-runner to 1.5.1 and exclude tmp/ from test…
Shinrai Sep 29, 2026
8ed8d6c
feat(hooks): add an around hook type that wraps the call pipeline (#517)
Shinrai Sep 29, 2026
2beeac8
deps: update @cldmv/vitest-runner to 1.5.1 and exclude tmp/ from test…
Shinrai Sep 29, 2026
43a02cf
fix(typescript): turn source maps on during coverage runs and documen…
Shinrai Sep 29, 2026
f07548a
fix(typescript): turn source maps on during coverage runs and documen…
Shinrai Sep 29, 2026
9d88739
fix(loader): load CommonJS .js leaves through the per-instance Common…
Shinrai Sep 29, 2026
3d5cb8f
fix(loader): load CommonJS .js leaves through the per-instance Common…
Shinrai Sep 29, 2026
79c93ab
style: apply automated lint/format fixes
cldmv-bot Sep 29, 2026
d5e9fe1
fix(typescript): guard strict mode against TypeScript 7's compiler-AP…
Shinrai Sep 29, 2026
77f71a0
feat(permissions): add permissions.owner to let a module reach every …
Shinrai Sep 29, 2026
562ca14
feat(permissions): add permissions.owner to let a module reach every …
Shinrai Sep 29, 2026
1bec309
fix(typescript): guard strict mode against TypeScript 7's compiler-AP…
Shinrai Sep 29, 2026
0231ad9
style: apply automated lint/format fixes
cldmv-bot Sep 29, 2026
e91b261
feat(events): host-controlled event delivery via event.strategy and e…
Shinrai Sep 29, 2026
f0221a3
feat(events): host-controlled event delivery via event.strategy and e…
Shinrai Sep 29, 2026
a951d9a
fix(ownership): record a forceOverwrite add's module as owner of the …
Shinrai Sep 29, 2026
9e2912d
fix(ownership): record a forceOverwrite add's module as owner of the …
Shinrai Sep 29, 2026
287e43b
deps: bump vitest from 5.0.1 to 5.0.2 in the vitest group
dependabot[bot] Sep 30, 2026
2341ca3
deps: bump prettier from 3.9.8 to 3.9.9 in the prettier group
dependabot[bot] Sep 30, 2026
2f00fdb
deps: bump prettier from 3.9.8 to 3.9.9 in the prettier group (#539)
cldmv-bot[bot] Sep 30, 2026
779d1f5
deps: bump vitest from 5.0.1 to 5.0.2 in the vitest group (#538)
cldmv-bot[bot] Sep 30, 2026
562094e
deps: bump @types/node in the patch group across 1 directory
dependabot[bot] Sep 30, 2026
500bec2
deps: bump @types/node from 26.6.2 to 26.6.3 in the patch group acros…
cldmv-bot[bot] Sep 30, 2026
c5fa0c8
fix(loader): give every relative helper a leaf imports the leaf's ins…
Shinrai Sep 29, 2026
0e0bab7
fix(api-manager): restore an overwritten namespace into its live wrap…
Shinrai Sep 29, 2026
9732e9e
fix(unified-wrapper): keep values assigned to a lazy namespace while …
Shinrai Oct 2, 2026
0c4a21d
fix(loader): give every relative helper a leaf imports the leaf's ins…
Shinrai Oct 2, 2026
52f3d60
fix(api-manager): restore an overwritten namespace into its live wrap…
Shinrai Oct 2, 2026
a4fd0b5
fix(unified-wrapper): keep values assigned to a lazy namespace while …
Shinrai Oct 2, 2026
7ec43e5
fix(permissions): make reload, shutdown and the default routines' roo…
Shinrai Sep 29, 2026
a8a6355
fix(reload): keep co-mounted modules' contributions across a scoped r…
Shinrai Sep 29, 2026
6667954
Merge branch 'next' into fix/builtin-deny-lifecycle
Shinrai Oct 2, 2026
eba0424
fix(permissions): make reload, shutdown and the default routines' roo…
Shinrai Oct 2, 2026
6491954
Merge branch 'next' into fix/scoped-reload-comount
Shinrai Oct 2, 2026
54278b8
fix(reload): keep co-mounted modules' contributions across a scoped r…
Shinrai Oct 2, 2026
0e11353
feat(reload): add api.slothlet.restart() — a clean-slate rebuild behi…
Shinrai Sep 29, 2026
52334c0
feat(reload): add api.slothlet.restart() — a clean-slate rebuild behi…
Shinrai Oct 2, 2026
f6b235a
fix(reload): keep a replace/forceOverwrite add's outcome across a sco…
Shinrai Oct 2, 2026
899287a
fix(reload): keep a replace/forceOverwrite add's outcome across a sco…
Shinrai Oct 2, 2026
6f7bd70
fix(routines): run a root shutdown/destroy export once per teardown
Shinrai Oct 2, 2026
18d5295
test(lazy): guard that a lazy api.add loads only the shared subfolder…
Shinrai Oct 2, 2026
4818222
test(lazy): guard that a lazy api.add loads only the shared subfolder…
Shinrai Oct 2, 2026
f703cd6
fix(loader): keep helpers per instance across ESM/CommonJS boundaries
Shinrai Oct 2, 2026
6f08c92
fix(loader): keep helpers per instance across ESM/CommonJS boundaries…
Shinrai Oct 2, 2026
94ae23c
Merge branch 'next' into fix/root-shutdown-once
Shinrai Oct 2, 2026
53d46b1
ci: stop the skipped PR-run mirror from satisfying Required PR Check
Shinrai Oct 2, 2026
613c6a4
ci: stop the skipped PR-run mirror from satisfying Required PR Check …
Shinrai Oct 2, 2026
968db1b
fix(routines): run a root shutdown/destroy export once per teardown (…
Shinrai Oct 2, 2026
070d022
fix(unified-wrapper): make a plain namespace callable when a later mo…
Shinrai Oct 2, 2026
ebfe906
fix(unified-wrapper): make a plain namespace callable when a later mo…
Shinrai Oct 2, 2026
70d2ec4
ci: run the in-repo PR mirror job instead of skipping it
Shinrai Oct 2, 2026
a563571
fix(remove): keep other modules' children when the module that create…
Shinrai Oct 2, 2026
1ccfc86
ci: run the in-repo PR mirror job instead of skipping it (#557)
Shinrai Oct 3, 2026
46249f4
fix(remove): keep other modules' children when the module that create…
Shinrai Oct 3, 2026
59ed33e
docs: v3.22.0 changelog and README What's New
Shinrai Oct 2, 2026
eb5fe7e
docs: v3.22.0 changelog and README What's New (#559)
Shinrai Oct 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
10 changes: 10 additions & 0 deletions .configs/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@ export default defineConfig([
}
},
{ files: ["**/*.js"], languageOptions: { sourceType: "commonjs" } },
// ESM-syntax `.js` fixtures for #521 (a "type": "module" package and a package with no type field,
// which Node loads as ESM by syntax detection), and the `.js` ES module a CommonJS leaf requires (#534).
{
files: [
"api_tests/api_test_cjs_js/esm/**/*.js",
"api_tests/api_test_cjs_js/untypedesm/**/*.js",
"api_tests/api_test_helper_imports/__mixed/lib/esm-plain.js"
],
languageOptions: { sourceType: "module" }
},
{ files: ["**/*.{js,mjs,cjs}"], languageOptions: { globals: { ...globals.node, ...globals.browser } } },
{
files: ["**/test/**/*test.js"],
Expand Down
12 changes: 11 additions & 1 deletion .configs/vitest.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { defineConfig } from "vitest/config";
import { DefaultReporter } from "vitest/node";
import { existsSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { fileURLToPath, pathToFileURL } from "node:url";

const __dirname = path.dirname(fileURLToPath(import.meta.url));

Expand Down Expand Up @@ -94,7 +94,17 @@ const workerNodeOptions = useSourceCondition
? [`--conditions=${slothletCondition}`, "--import=./tests/vitests/setup/env-preload.mjs"]
: ["--import=./tests/vitests/setup/env-preload.mjs"];

// Leaves load through this config's vite module graph (slothlet's source is inlined here, so its
// `import()` of a leaf is vite's), where Node's resolve hooks never see a leaf's imports. The
// plugin gives a leaf's relative helpers the leaf's per-instance query inside that graph (#518) —
// the same step a consumer takes when loading leaves through slothlet's `import` hook.
// A computed file URL (not a literal specifier) so the config bundler leaves the import to runtime.
const { slothletInstanceImports } = await import(
pathToFileURL(path.resolve(__dirname, srcExists ? "../src" : "../dist", "lib/helpers/instance-imports.mjs")).href
);

export default defineConfig({
plugins: [slothletInstanceImports()],
pool: "forks",
// pool: "threads",
resolve: {
Expand Down
6 changes: 0 additions & 6 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,6 @@ updates:
open-pull-requests-limit: 5
commit-message:
prefix: "deps"
ignore:
# ABI-locked rolldown native binding (npm #4828 workaround): it must track the exact
# rolldown version vite ships (vite exact-pins rolldown, e.g. 1.0.3), not be bumped
# independently. The #149 bump to 1.1.0 had no rolldown consumer and shipped an unused
# ~21MB duplicate; keep this pinned in lockstep with vite's rolldown instead.
- dependency-name: "@rolldown/binding-linux-x64-gnu"
groups:
# vitest and @vitest/coverage-v8 (and other @vitest/* packages) peer
# each other EXACTLY, so a partial bump (e.g. vitest to 5.0.0 while
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/bundle-size.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ jobs:
uses: CLDMV/.github/.github/workflows/reusable-bundle-size.yml@v4
with:
build_command: "npm run build:ci"
dist_paths: "dist/**"
# Every pattern starts with `*` on purpose: the v4.29.2 measure action matches nothing for a bare top-level file and double-counts files when patterns have different roots.
dist_paths: "*.mjs,*.cjs,*dist/**/*.mjs,*bin/**"
# warning_pct: 5
# warning_bytes: 500
# comment_mode: "update"
Expand Down
55 changes: 39 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ on:
required: false
default: "lts/*"
min_node_version:
description: "Minimum Node.js version for matrix testing (default: 22.12.0 — the floor vitest 5 actually runs on)"
description: "Minimum Node.js version for matrix testing (default: 22.15.0 — slothlet's engines floor (in-thread module.registerHooks))"
type: string
required: false
default: "22.12.0"
default: "22.15.0"
max_node_major:
description: "Max Node.js major version for the test matrix. Leave blank (the default) to inherit the CLDMV/.github reusable workflow's default; set a value only to pin/override for a specific run."
type: string
Expand Down Expand Up @@ -220,7 +220,7 @@ jobs:
.gitignore
debug: ${{ github.event.inputs.debug == 'true' }}
node_version: ${{ github.event.inputs.node_version || 'lts/*' }}
min_node_version: ${{ github.event.inputs.min_node_version || '22.12.0' }}
min_node_version: ${{ github.event.inputs.min_node_version || '22.15.0' }}
max_node_major: ${{ github.event.inputs.max_node_major || '' }} # blank ⇒ inherit the CLDMV/.github reusable default
# LTS-only matrix (even majors: 20, 22, 24, …) on every event. Odd majors
# (21, 23, …) are non-LTS interim releases, and the native-binding test
Expand Down Expand Up @@ -300,23 +300,37 @@ jobs:
# automatically — no `pull_request` round-trip needed for non-fork
# non-release PRs.
required-check:
name: ✅ Required PR Check
needs: ci
# Mirror the `ci` job's gating exactly. The four cases that run:
# Which name this job reports under is the whole point of it.
#
# The ruleset gates merges on `✅ Required PR Check`, so a check with that
# name must only ever exist on a head SHA after the full test matrix for
# that SHA has finished, mirroring its result. `needs: ci` guarantees the
# timing: the job is only created once every Build & Test leg and the
# coverage job are done.
#
# On an in-repo feature PR the `pull_request` run does not own the status
# (the push run on the head branch does), so it must not post
# `✅ Required PR Check` at all. Two traps rule out the obvious shapes:
# - A job SKIPPED by `if:` still posts a check run under its name, and
# GitHub treats a skipped required check as satisfied. Under the real
# name that let PRs merge mid-test (CLDMV/slothlet#553).
# - GitHub does not evaluate the `name:` of a skipped job, so a
# conditional name on a skippable job shows up as the raw expression
# text (#350).
# So the job never skips: it runs on every path, the name expression is
# always evaluated, and the in-repo PR path lands on a readable,
# non-required name and passes as a no-op. The condition below is
# repeated in the step's OWNS_STATUS and must stay identical. The paths
# that own the status:
# 1. push events (job needs CI run)
# 2. fork PRs (push doesn't cover forks)
# 3. release PRs from `next` → master/main (push covers SHA but commit-gate skips chore-bump)
# 4. release PRs from `hotfixes` → master/main (same reason)
# In-repo feature PRs targeting `next` / `hotfixes` skip on
# pull_request — push on the head branch already posted the status
# on the SHA, and mirroring here would overwrite it.
if: |
always() && (
github.event_name != 'pull_request' ||
github.event.pull_request.head.repo.fork == true ||
github.event.pull_request.head.ref == 'next' ||
github.event.pull_request.head.ref == 'hotfixes'
)
name: ${{ (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == true || github.event.pull_request.head.ref == 'next' || github.event.pull_request.head.ref == 'hotfixes') && '✅ Required PR Check' || '⏭️ Required PR Check (reported by the push run)' }}
needs: ci
# always(): run even when `ci` is skipped (the in-repo PR path) or failed
# (so the mirror can report red).
if: always()
# Match the reusable's runner routing (workflow-ci.yml): private CLDMV
# repos run on self-hosted cldmv-runners (GitHub-hosted Actions budget is
# private-metered and exhausted), public repos use free GitHub-hosted, and
Expand All @@ -330,10 +344,19 @@ jobs:
steps:
- name: Mirror reusable result
env:
OWNS_STATUS: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == true || github.event.pull_request.head.ref == 'next' || github.event.pull_request.head.ref == 'hotfixes' }}
IS_MASTER_SYNC: ${{ needs.ci.outputs.is_master_sync }}
DOCS_ONLY: ${{ needs.ci.outputs.docs_only }}
CI_RESULT: ${{ needs.ci.result }}
run: |
# In-repo feature PR: the push run on the head branch reports
# `✅ Required PR Check`. This job runs under the
# `⏭️ Required PR Check (reported by the push run)` name and
# must not gate anything.
if [ "$OWNS_STATUS" != "true" ]; then
echo "In-repo PR event — the push run reports ✅ Required PR Check for this SHA."
exit 0
fi
echo "ci.result=$CI_RESULT docs_only=$DOCS_ONLY is_master_sync=$IS_MASTER_SYNC"
# next/hotfixes was force-synced to master — head SHA matches the
# default branch, nothing new to test, green-light without running CI.
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ on:
required: false
default: true
min_node_version:
description: "Minimum Node.js version for matrix testing (enables matrix when set; default: 22.12.0 — the floor vitest 5 actually runs on)"
description: "Minimum Node.js version for matrix testing (enables matrix when set; default: 22.15.0 — slothlet's engines floor (in-thread module.registerHooks))"
type: string
required: false
default: "22.12.0"
default: "22.15.0"
max_node_major:
description: "Max Node.js major version for the test matrix. Leave blank (the default) to inherit the CLDMV/.github reusable workflow's default; set a value only to pin/override for a specific run."
type: string
Expand Down Expand Up @@ -104,7 +104,7 @@ jobs:
publish_to_github_packages: ${{ github.event.inputs.publish_to_github_packages != 'false' }}
publish_command: ""
github_packages_publish_command: ""
min_node_version: ${{ github.event.inputs.min_node_version || '22.12.0' }}
min_node_version: ${{ github.event.inputs.min_node_version || '22.15.0' }}
max_node_major: ${{ github.event.inputs.max_node_major || '' }} # blank ⇒ inherit the CLDMV/.github reusable default
test_command: "npm test" # Use defaults: NODE_ENV=development, NODE_OPTIONS=--conditions=development
# test_command: "NODE_OPTIONS='--conditions=slothlet-dev' npm test" # Override NODE_OPTIONS only
Expand Down
41 changes: 32 additions & 9 deletions .github/workflows/release-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,17 @@
# merge check, because check_suite silently never fired for that case at all.
# `workflow_run` is GitHub's documented replacement for exactly this pattern.
#
# IMPORTANT: `workflows:` below must list the exact `name:` of THIS repo's own
# ci.yml (matched by literal workflow name, not filename) — update it if you
# renamed that workflow. If more than one top-level workflow in your repo can
# plausibly be the last to finish (e.g. a separately-scheduled CodeQL run that
# sometimes outlasts ci.yml), list all of them; a workflow that finishes and
# isn't listed here won't re-arm the merge check, though the manual
# workflow_dispatch fallback below always will.
# IMPORTANT: the merge gate waits on EVERY check-run on the release PR's head
# commit, from any workflow — so `workflows:` below must name every workflow in
# your repo that puts a check on that commit, not just ci.yml. Only the one that
# finishes LAST can see a fully green head; if it isn't listed, nothing re-fires
# and the PR sits approved + green until you dispatch this workflow by hand.
# CodeQL in particular routinely outlasts ci.yml (CLDMV/.github PR #322 stuck
# exactly this way). The list below covers the standard v4 template set by their
# template `name:`s — names are matched literally (not by filename), so fix any
# you renamed, and add any extra PR-triggered workflow your repo has. Listing a
# workflow your repo doesn't have is harmless. `branches:` limits re-fires to
# runs on the integration branches, so feature-branch CI doesn't wake this up.
#
# Thin caller: all logic lives in the reusable, pinned at @v4.
# NOTE: pull_request_review / workflow_run events run the copy of this file on
Expand All @@ -46,13 +50,32 @@ name: 🚦 Release Merge (v4)
on:
pull_request_review:
types: [submitted] # your approval arms it
workflow_run:
workflows: ["🧪 CI Tests & Build"] # ← match your ci.yml's `name:` — see #318
workflow_run: # re-evaluate as each check-producing workflow finishes — see #318
workflows: # ← must match your workflows' `name:`s — see IMPORTANT above
- "🧪 CI Tests & Build"
- "🔍 CodeQL"
- "🔒 Dependency Review"
- "📊 Bundle Size"
- "🚀 Next Release (v4)"
- "🚑 Hotfixes Release (v4)"
- "🌿 Branch Retention"
- "🏷️ PR Labeler"
- "🏷️ PR Title Normalizer"
- "👋 Welcome Contributor"
- "🔀 Hotfix PR Redirector (v4)"
- "🚀 Member Auto-Enable Auto-Merge"
- "🤖 Dependabot Auto-Merge"
- "🔁 Dependabot Auto-Recreate"
- "📜 CLA"
- "📥 PR Notify"
types: [completed]
branches: [next, hotfixes]
workflow_dispatch: # manual re-evaluation

# Serialize per repo: each run re-resolves the release PR + re-gates the head,
# so queue (don't cancel) to avoid racing a merge that's already in flight.
# GitHub keeps one pending run per group and a newer arrival replaces it — that
# is harmless, since every run re-reads approval + check state from the API.
concurrency:
group: release-merge-${{ github.repository }}
cancel-in-progress: false
Expand Down
Loading
Loading