Skip to content
This repository was archived by the owner on Dec 27, 2025. It is now read-only.

sync - #2

Open
cheesycod wants to merge 690 commits into
mluau:primaryfrom
luau-lang:primary
Open

sync#2
cheesycod wants to merge 690 commits into
mluau:primaryfrom
luau-lang:primary

Conversation

@cheesycod

Copy link
Copy Markdown

No description provided.

skberkeley and others added 30 commits April 1, 2026 20:34
All instances of `execpath` have become `execPath`.
This PR renames all the test lifecycle methods
(beforeEach/afterEach/beforeAll/afterAll) etc + updates the
documentation.
I've also fixed the remaining type checker errors in the examples,
either by re-writing them or adding casts or annotations where
appropriate.
We should still support writing tests without using `lute test`, but now
the method for doing this is explicitly moved into @std/test/runner.
This PR makes `lute check` a blocking check, instead of a 'don't add new
type errors to lute' job.

For the remaining type check errors in the lint rules, I've explicitly
silenced them and cut this ticket
:#932 to track un-silencing them
when we bump our luau dependency to version 716.
I discovered an issue in CI where `lute test` would fail to require the
`difftext` test file. Instead of causing CI to fail, this would silently
skip that test suite. Moreover, there is a divergence in how tests run
in the presence of the .ci.luaurc file vs the .luaurc file.

Today, we don't define a batteries alias in the .ci.luaurc because we
have tests that rely on asserting that user code cannot require
batteries. This also causes a divergence in how C++ and luau tests are
run
- luau tests pass with the regular .luaurc because some tests rely on
the .luaurc to figure out where batteries are located.
- luau tests fail with the .luaurc.ci because that doesn't have a
batteries alias.
- C++ tests pass with the .luaurc.i because that doesn't have a
batteries alias
- C++ tests fail with the regular .luaurc because the batteries alias is
defined in the root of the repo

The cause of the luau tests failing is that `loadModule` loads a test
case as user code, which has no access to @Batteries. It uses a .luaurc
to find the local `@batteries`. The `difftext` battery itself requires
the `deque` module in batteries, which causes us to look for a
@Batteries alias somewhere (which doesn't exist in CI). To fix this,
I've added a .luaurc with the `@batteries` alias defined to the
batteries/ directories.

I've also:
- gotten rid of the step that changes the luaurc we run with in CI
- added .luaurc's to files that rely on local access to batteries,
either for execution (examples/ tools/) or for editor support
(std/libs).
- added a ps.exit(1), so that test running failures will cause CI to
fail.
**Luau**: Updated from `0.714` to `0.715`

**Release Notes:**
https://github.com/luau-lang/luau/releases/tag/0.715

---
*This PR was automatically created by the [Update Luau
workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)*

---------

Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
Co-authored-by: Vighnesh Vijay <vvijay@roblox.com>
This lets us examine stacktraces/other runtime errors being reported in
tests, since we can initialize the runtime with a `TestReporter`.
This also fixes a bug where files containing ".." (such as:
https://github.com/luau-lang/lute/blob/primary/tests/std/JSONParsingTestSuite/n_structure_angle_bracket_..json)
would prevent the repo from being used as a package dependency.
This PR adds support for a variadic argument to the CLI parsing battery.
Any arguments not consumed by an option or positional argument which
come before a `--` is seen will now be consumed by the variadic argument
if present. If a variadic argument isn't specified, then arguments
before a `--` that aren't otherwise consumed will still be considered
forwarded.

I also added a test suite for the CLI battery.

---------

Co-authored-by: ariel <arielweiss@roblox.com>
**Lute**: Updated from `0.1.0-nightly.20260327` to
`0.1.0-nightly.20260403`

**Release Notes:**
https://github.com/luau-lang/lute/releases/tag/0.1.0-nightly.20260403

---
*This PR was automatically created by the [Update Luau
workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)*

Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
Co-authored-by: Nick Winans <nick@winans.io>
Co-authored-by: ariel <arielweiss@roblox.com>
This results in a slight API change for the CLI. Previously, options
forwarded on to the code transformation scripts could be passed
anywhere, not just after a `--`, but now we only forward them if they
come after a `--`. This is because we now use the CLI battery's shiny
new variadic argument feature to parse file paths to be transformed.
… a killed task (#943)

Cancelling a task should error at call time if closing a coroutine is
not possible, but should not create errors in the runtime. Currently,
running code like:
```
        local task = require("@std/task")
        local t = task.spawn(function()
            task.wait(2)
        end)

        task.cancel(t)/coroutine.close(t)
```
will cause the runtime to print "cannot resume dead coroutine". The
reason that this happens is because of how scheduling resumes works.
When the user calls `coroutine.close()` on the task, we reset the thread
state to 'dead'. If the function passed to `spawn` schedules a
continuation in the runtime, then when this continuation is called, we
**may** end up mutating the state of a cancelled thread.

For example, the `WaitData` uses the resumeToken to schedule a callback
that pushes one value onto the stack associated with the callback.
Because this thread is dead by the time the wait elapses, we end up
pushing a number onto the stack, which makes it so that callback's top
and base are not the same. When this happens, the runtime check for this
thread's state using `lua_costatus` will return CO_SUS instead of
CO_FIN, which causes the subsequent resume in the runtime to fail.

This uncovered another bug with the FS Watch handle, whereby the
combination of task.wait and fs.watch caused a pending token to be
registered with the runtime that never got cleared, which caused the
runtime to loop forever. I refactored the watch handle code a bit to
make it's initialization and tear down clearer, and removed the pending
token, as the existence of a `uv_fs_event_t` handle is already tracked
by the event loop to prevent premature shutdown.
As part of internal explorations, we built a library that reimplements
the Linux `glob` functionality in Lute. Since we anticipate this being
widely useful for ecosystem tooling (particularly for defining
configuration formats for common tools like package managers, unit test
dispatchers, etc.), we want to propose moving our implementation into
batteries so that it can be shared and improved communally, rather than
fragmenting this functionality across the ecosystem.

The new library has two APIs: `glob.matches()`, which returns a boolean
if a path matches a glob pattern, and `glob.discover()`, which
efficiently walks the filesystem with pruning to discover all paths that
match a glob pattern.

---

**Note:** at lute/lute/cli/commands/lib/ignore.luau there are some
similar globbing facilities, but they're pretty divergent in
implementation and in API surface. It's nothing we can't expand this new
glob surface to standardise; I got Claude to summarise:

> **What they share** — both implement the core glob metacharacters (*,
?, **) with the same semantic meaning (don't cross /, match any char,
recurse into subdirectories).
>
> **Where they diverge:**
>
> - **Purpose:** batteries/glob is a filesystem glob that walks the tree
and returns matching paths. parseIgnores is gitignore matching that
tests whether a path matches an ignore rule.
> - **Matching strategy:** batteries/glob does recursive backtracking,
char-by-char, per segment. parseIgnores compiles globs into Lua patterns
and uses string.match on full relative paths.
> - **Filesystem:** batteries/glob walks directories via
fs.listDirectory. parseIgnores has no filesystem interaction — it just
tests a string.
Returns: batteries/glob returns { string } (list of matching paths).
parseIgnores returns boolean.
> - **Character classes:** batteries/glob has full [...], [!...], [a-z]
range support. parseIgnores doesn't support them — [ passes through as a
literal.
> - **Gitignore semantics:** batteries/glob has none. parseIgnores
supports ! negation/whitelists, trailing / for directory-only matching,
anchoring rules (patterns with / anchor to the .gitignore location,
without / they match anywhere), and hierarchical .gitignore chain
resolution.
> - **Separator handling:** batteries/glob handles this implicitly — it
matches one segment name at a time, so separators never appear in the
match input. parseIgnores does it explicitly, baking the platform
separator into compiled patterns ([^\]* vs [^/]*).

I imagine we can introduce an `options` table for enabling/disabling
features like character classes and gitignore patterns, and the choice
between full-string vs per-segment processing, and the idea of whether
to compile to regex or just directly ingest the string, is basically
just a performance tradeoff.
…`@batteries/cli` a bit in support of that) (#951)

I got annoyed by luthier being kinda jank when you do incorrect
invocations, so I put in some work to make the UX of the tool better. It
has colorized help output now, and now will list subcommands and usage
formats for the commands to the user, along side showing the full help
output whenever you invoke it. Longer-term, it would probably be better
if the cli library actually had a proper concept of subcommands because
it could streamline _a lot_ of this logic, but this is an improvement
for now.
…l` (#956)

I meant to do this in the #951 PR, but I forgot to. We should use
`xpcall` instead of `pcall` so that the type system actually works
correctly here.
…rectly without requiring `@lute/time` (#958)

A strange bug got reported on Discord (and unfortunately they never made
a ticket here) where durations that the user got from `@lute/fs` would
ultimately behave incorrectly when `@lute/time` was not imported into
that script. The underlying cause is that the metatable was not
initialized when `@lute/time` was not imported, and therefore the code
that constructs the durations in `@lute/fs` would look for a duration
metatable that did not exist and just set the metatable to `nil`. We fix
this by making initialization of the duration library idempotent and
then invoking that initialization for `@lute/fs` as well.
Adds support for the compile command to support bundling .config.luau
for require alias resolution.
The job that will be used for automating releases and the job that will
be used for nightlies share a lot of common actions. This PR separates
the common chunk out into a re-usable workflow, called shared-build
which is parameterized on the branch name.

1) Nightlies can be manually kicked off, but will continue to run with
the current cadence. These will automatically run of the 'primary'
branch.
2) Releases will be kicked off on release/v{Major}.{Minor}.x branches. 

In both cases the job will check out the branch and derive the tag name
directly from the get_version.cmake command. If the branch is primary,
we'll get 'nightly.YYYMMDD' appended.
#959)

There's a lot of inconsistency between the different runtime library
definitions, and it's bothered me for a while. To try to make things
more structured, this PR introduces a shared interface `LuteLibrary` and
refactors each library namespace to instead be a `struct` that
implements that `LuteLibrary` interface. The goal here is to make it
more difficult to author a library that isn't structured how we would
expect, and to bring all of the existing libraries into that uniform
structure.
previously had some test files here in `docs/` that we wanted to ignore,
but those have been moved and excluding `/test/` caused our `std/test`
doc files and the CLI docs for `test` to not get generated

`@std/test` is now being generated
<img width="224" height="228" alt="image"
src="https://github.com/user-attachments/assets/4bf18b89-3d36-4ed3-bede-9f61a8ab63d0"
/>

same with CLI test docs
<img width="124" height="103" alt="image"
src="https://github.com/user-attachments/assets/a2bf5fcf-99c7-4191-a756-5ee48f6b5c4f"
/>

ty @Vighnesh-V for the catch!
wizhao96 and others added 30 commits July 24, 2026 11:22
Create initial bindings for `lute/debug` to Luau, which primarily
focuses on breakpoint behavior.

- Add some basic Luau tests
- A definitions file for the library for type checking
- Renames `debugger.cpp` to `debuginternals.cpp` to more clearly
separate out the bindings from internal implementation
**Luau**: Updated from `0.730` to `0.731`

**Release Notes:**
https://github.com/luau-lang/luau/releases/tag/0.731

---
*This PR was automatically created by the [Update Luau
workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)*

Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
**Lute**: Updated from `1.0.1-nightly.20260717` to
`1.0.1-nightly.20260723`

**Release Notes:**
https://github.com/luau-lang/lute/releases/tag/v1.0.1-nightly.20260723

---
*This PR was automatically created by the [Update Luau
workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)*

Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
Co-authored-by: Sora Kanosue <kanosuesora@gmail.com>
Add support for multiple sources in the debugger
* Intercept calls to loading new modules by modifying the `RequireCtx`
* also add `getLoadedSources` to debugger Target + bindings
to support partial reads into buffers and more, this PR introduces a new
fs API

```lua
--- Reads up to `count` bytes from `handle` at `fileOffset` into `buf` starting at `bufferOffset`.
--- Returns the number of bytes actually read (may be less than `count` if EOF is reached).
--- - `bufferOffset` defaults to 0.
fs.readIntoBuffer(handle: FileHandle, buf: buffer, fileOffset: number, count: number, bufferOffset: number?): number
```
`tableext.deepClone` failed to correctly clone tables with `__iter`
metamethods that didn't perform conventional key, value iteration. I
discovered this while cloning the CST returned by lute's `parser` APIs,
and found that `CstPunctuated` nodes were missing the `separators` field
due to their `__iter` method.

This PR updates `deepClone`'s iteration over a table to use `pairs`,
such that all key, value pairs of cloned tables are handled.
A basic implementation of a DAP adapter that can handle breakpoints,
continuing, and pausing
* Also changes `onBreakpointInstall` to signal when installation fails
as well

<img width="1203" height="960" alt="Screenshot 2026-07-24 at 3 22 39 PM"
src="https://github.com/user-attachments/assets/4db8b3e1-b760-4a2b-b3e8-434e465ff537"
/>
(Note: line highlighting is provided by stack frames, which is why it's
stuck at line 1 above. really the important thing to look at is the
breakpoints bar in the bottom left, where we can see that we've hit a
bp)
**Lute**: Updated from `1.0.1-nightly.20260723` to
`1.0.1-nightly.20260730`

**Release Notes:**
https://github.com/luau-lang/lute/releases/tag/v1.0.1-nightly.20260730

---
*This PR was automatically created by the [Update Luau
workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)*

Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
**Luau**: Updated from `0.731` to `0.732`

**Release Notes:**
https://github.com/luau-lang/luau/releases/tag/0.732

---
*This PR was automatically created by the [Update Luau
workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)*

Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
We've got some interest in trying out a merge queue for lute, which
means that we need to modify our CI to actually _run_ in the event that
we have a merge queue going. Otherwise, everything will just fail
immediately.
Fix `Target` destructor in infinite loop case as part of splitting
#1233 up.
- If the debugger is running an infinite loop, that coroutine would
never break and so the destructor will stall infinitely.
- This PR fixes this by making sure that always coroutines break out of
execution in our destructor by setting the `interrupt` callback. This
interrupt callback is called on back edges of loops or function
calls/returns (which realistically will always occur when the thread is
running an infinite loop)
Adds thread/coroutine inspection for multiple co-routines (part 1/3 of
PRs dealing with inspecting into state)
* Creates data structures to keep track of threads getting created and
destroyed while working with bps
* Make sure `onPause` and `onBreakpointHit` take in threadId, keeping in
align with DAP protocol
* Add `getStoppedThread`, `getThreads` and `getMainThread` for
inspection
* (maybe?) replace `task.spawn()` behavior with `task.defer()` in debug
mode to allow for correct pausing
* switch everything to use 1-indexing to match Luau

btw: i use threads and coroutines interchangeably even though they are
semantically different since we have `Thread` objects tracking
coroutines

<img width="1503" height="927" alt="Screenshot 2026-07-31 at 11 36
06 AM"
src="https://github.com/user-attachments/assets/0be8b04b-79aa-4217-8028-5de6386fc54c"
/>
We got some feedback from folks about the existing README being
misleading because it doesn't clearly delineate between things that are
complete and things that are aspirational, and that it doesn't do enough
to contextualize what our version status indicates. This PR updates the
leading bits of the README to try to address some of this: removing
mention of sockets as a supported feature since we have not implemented
them yet, de-ambitioning claims of unifying runtimes with the standard
library (really, limiting the scope of the claims to what we're actually
able to do work towards ourselves), and contextualizing more of both
"where the software is today, what 1.0.0 means" and "where we would like
the software to go."

Everything beyond the Lute Libraries section is purely formatting
changes with no text. I used mdformat to wrap the whole file to 120
characters so that diffs on it will be hopefully less gross in the
future.
`stoppedThreads` and `scriptThreads` could get garbage collected when
they shouldn't have, which this PR fixes
* this happens for example when stoppedThreads is no longer running and
has been dequeued from the `Runtime` so there's no longer an active
`Ref` to it
Adds output redirection for `lute/debug` when calling `print()`
* When `onPrint` is specified that function is called instead of normal
`print()` to stdout
* Modfied DAP + bindings to incorporate this feature

<img width="1082" height="938" alt="Screenshot 2026-07-31 at 10 18
34 AM"
src="https://github.com/user-attachments/assets/5eb079c9-d0fb-4828-8e8f-1a2a3087a582"
/>
instead of returning `true/false`, surface compile errors on launch to
the user

this is what it looks like:
<img width="1120" height="839" alt="Screenshot 2026-08-03 at 9 46 46 AM"
src="https://github.com/user-attachments/assets/3ca0db3c-0dd3-44e4-894e-97690c06f7ca"
/>
- Related #1272 
- Adds `lute pkg run` to `lute pkg --help`
- <details><summary>Improved `lute pkg install --help`: </summary>
  
  Before:
  ```
  @batteries/cli.luau:103: Unknown argument: help
  stacktrace:
  [C] function assert
  @batteries/cli.luau:103 function parse
  @cli/pkg/loom-core/src/commands/install.luau:43 function install
  @cli/pkg/init.luau:33 function main
  @cli/pkg/init.luau:43
  ```
  After:
  ```
  @batteries/cli.luau:103: Unknown argument: help
  Usage:
    --exclude-dev - Skip dev dependencies
    --locked - Error if lockfile doesn't match manifest (CI mode)
  
  stacktrace:
  [C] function error
  @cli/pkg/loom-core/src/commands/install.luau:48 function install
  @cli/pkg/init.luau:34 function main
  @cli/pkg/init.luau:44
  ```

</details>

- <details><summary>Improved `lute pkg auth --help`: </summary>
  
  Before:
  ```
  @batteries/cli.luau:103: Unknown argument: help
  stacktrace:
  [C] function assert
  @batteries/cli.luau:103 function parse
@cli/pkg/loom-core/src/commands/authenticate.luau:8 function
authenticate
  @cli/pkg/init.luau:35 function main
  @cli/pkg/init.luau:43
  ```
  After:
  ```
  @batteries/cli.luau:103: Unknown argument: help
  Usage:
    --token - (required) Authentication token
    --domain - Domain to authenticate with
  
  stacktrace:
  [C] function error
@cli/pkg/loom-core/src/commands/authenticate.luau:13 function
authenticate
  @cli/pkg/init.luau:36 function main
  @cli/pkg/init.luau:44
  ```

</details>
Incorporate stepping to `lute/debug`
* Add capabilities for `stepIn`, `stepOver`, and `stepOut`
* Also add `getLine()` to streamline testing


https://github.com/user-attachments/assets/2916d967-50b7-43ea-b7de-d9703d780e6b
**Luau**: Updated from `0.732` to `0.733`

**Release Notes:**
https://github.com/luau-lang/luau/releases/tag/0.733

---
*This PR was automatically created by the [Update Luau
workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)*

---------

Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
Co-authored-by: Hunter Goldstein <hgoldstein@roblox.com>
**Lute**: Updated from `1.0.1-nightly.20260730` to
`1.0.1-nightly.20260807`

**Release Notes:**
https://github.com/luau-lang/lute/releases/tag/v1.0.1-nightly.20260807

---
*This PR was automatically created by the [Update Luau
workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)*

Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
Adds stack frames/stack traces (part 2/3 of PRs dealing with inspecting
into state)
* Adds `getStackDepth`, `getStackFrame`, and `getStackTrace` to debugger
* Modify `getLine` to `getStoppedLocation` to include source path
* Allows for delayed stack loading in DAP
* In DAP by supporting stack frames we allow for line highlighting


https://github.com/user-attachments/assets/ea426af3-2952-4141-803f-0797ce2f2f37
- `cli.usage` now prepends the "Usage:" label
- `cli.help` now returns the constructed string (instead of printing it)
- `cli.help` now formats positional and variadic arguments
- The existing lute subcommands have been migrate to a consistent
pattern for rendering usage/help fields
…biguity (#1289)

fixes #1279

When a file like `foo.luau` has a sibling directory named `foo/`, we
previously reported an ambiguity error unconditionally. But if the
directory had no `init.luau` or `init.lua` file, we shouldn't be
reporting an ambiguity error because we know that we aren't requiring
the `foo/` directory directly.

This fix defers the ambiguity check until after we scan the directory
for init files, so now if we `require(foo)` with:
* `foo.luau` + `foo/` with no init = require resolves to `foo.luau` (and
we can still require any files inside the directory)
* `foo.luau` + `foo/` with `init.luau` results in an ambiguous error
Enable variable + scope inspection for `lute/debug`. Part 3/3 of a
series of PRs on inspection.

* Generally, you take a stack frame and first drill into a
`VariableScope` (a scope represents something like a group of local
variables or upvalue variables)
* Each scope has its own `variableReference` and you can get a set of
`Variable` objects per scope.
* For tables, the `Variable` objects themselves may have a
`variableReference`, allowing for additional lazy inspection of deeper
levels of the table



https://github.com/user-attachments/assets/f0346606-3961-429d-92c5-111a4f4fc8aa
this one line fix to stack frames corrects the stack frame display
during multi-threading
* `stoppedLine` correction only should apply on the thread that was
actually dequeued from the Lute runtime queue
* other threads are still stopped but can really on `lua_getinfo` for
accurate information
* significantly buff multi-threaded testing


https://github.com/user-attachments/assets/5d688875-f4ad-40e4-adb6-b6b41e4f5c83

[ignore what happens when you need to press the resume button again at
the end of the video to actually get the program to exit, this issue is
caused by the one documented here
#1250]
@Vighnesh-V mentioned the #1289
logic might've not been fully correct, so this reworks the logic and
adds another test case

logic and the cases we could have are now:
* `if (hasInit && resolvedType)` -> init + sibling (file w same name as
dir) -> ambiguous
* `if hasInit` -> init + no sibling -> file
* `else if !resolvedType` -> no init + no sibling -> directory
* no init -> sibling -> file (already set earlier in the code)
…1250)

Fixes scheduled continuations and callbacks blocking on
`uv_run(getEventLoop(), UV_RUN_ONCE)` in `runOnce`.
* When testing the DAP adapter, I was seeing behavior where callbacks
such as `onExit` would not fire until after receiving I/O from the
VSCode debugging client.
* This uses `uv_async` to attempt to fix that.
* Empirically it fixes the DAP problem above.
**Lute**: Updated from `1.0.1-nightly.20260807` to
`1.0.1-nightly.20260814`

**Release Notes:**
https://github.com/luau-lang/lute/releases/tag/v1.0.1-nightly.20260814

---
*This PR was automatically created by the [Update Luau
workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)*

Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.