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

Conversation

@cheesycod
Copy link

No description provided.

checkraisefold and others added 30 commits October 18, 2025 21:29
#449)

This is a pre-req for a future PR for Multi-File bytecode compilation.
Doing this lets me use the module path interface more flexibly.
I was trying to get the code generation to run through CMake (which
would run lute in the build). When integrating this into luthier, I
needed a way to identify the current lute executable to pass to CMake.

This adds `execpath` to `@lute/process`, which mirrors Node.js'
[process.execPath](https://nodejs.org/docs/latest/api/process.html#processexecpath)
to get the lute executable path - this is immune to `exec -a foo lute`
having `foo` as `argv[0]`.


[`uv_setup_args`](https://docs.libuv.org/en/v1.x/misc.html#c.uv_setup_args)
can allocate on some platforms. That memory should be free'd with
[`uv_library_shutdown`](https://docs.libuv.org/en/v1.x/misc.html#c.uv_library_shutdown).
I'm not sure where it's appropriate to call this.

Passing around the `argv0` also seems a bit wrong. Maybe this path
shouldn't be stored in `Runtime`?
Small change, but "CI" makes more sense than "Gated Commits" for the
README icon:
<img width="253" height="52" alt="image"
src="https://github.com/user-attachments/assets/82b052c7-c445-47a0-993e-ac9943d2881b"
/>
This is a super common assertion and something I wanted to use in a
project I was working on so figure'd I would add it.

Not sure what the larger vision is for testing API, but hopefully this
fits somewhere.

Can also add an optional `expectedError` param
[Rendered](https://github.com/luau-lang/lute/blob/vrn-sn/contributing-md/CONTRIBUTING.md).

Feel free to commit to this branch directly.

---------

Co-authored-by: ariel <arielweiss@roblox.com>
### Problem
Lute did not support user input yet.

### Solution
We introduce user input support to the Lute and the Lute standard
library!
Users can use the `input()` function found in`@std/io` to process and
store user input from command line, piped input, or file redirection.
See examples below and in `examples/user_input.luau`.
Functionality was implemented using `libuv`'s library and can be found
in `lute/io`

### Examples

#### Scripts

Get user input
```lua
local io = require("@std/io")

local input = io.input()
print(input)
```

Get user input with prompt
```lua
local io = require("@std/io")

local name = io.input("Please enter your name: ")
print(name)
```

#### Ways to execute the script

Command line
```bash
$ lute user_input.luau
> [will wait for user input in command line]
```

Piped input
```bash
$ echo hello | lute user_input.luau
```

Input redirected from file
```bash
$ lute user_input.luau < input_text.txt
```

### Future Work
- Tests
- `stdout` and `stderr` functionality and other I/O utilities.
- Currently, providing a prompt to the user with `.input()` will produce
a new line between said prompt and the user input, this will most likely
be resolved once `stdout` is implemented

Thank you @vrn-sn for massive help (esp with `libuv`) 🙏

Resolves #360
Not visible in a monospaced font, but the mighty en dash strikes again.
😉
Refactors the `lute setup` command to:
1. Put the regular lute typedefs into a `lute` subdirectory, and add a
`std` subdirectory with the standard library files inside
2. Accept a flag to create a new luaurc, or overwrite the aliases of one
if it exists, to add the type definition folders. Unfortunate caveat is
that the std lib json encoder is not deterministic, so each time it
moves the json keys around - this is pretty annoying and creates a lot
of diff noise. Not sure if there's much to be done about this

Luthier:
1. Fix a backslash escaping bug for std lib and command C++ file gen
that cropped up when I added this
2. Change definition generation to use above structure
3. Use projectRelative more
4. Change order of `generateFilesIfNeeded` calls to fix a bug - CLI
commands rely on the generated type def output, so they should be
generated after type defs

Also fix the trailing comma in the project luaurc which is typically not
valid json

Closes #424

---------

Co-authored-by: ariel <aweiss@hey.com>
Forgot to rename the `.read()` call in `definitions/io.luau` when
renaming the `input` to `read` in `io.cpp` in
#437 and was causing a type error
For the `0.1.0-nightly.20251018` release, there was a race condition
between the "Create Draft Release" and "Publish Release" steps of the
release workflow.

We successfully created the draft release with all the built binaries:
<img width="696" height="158" alt="image"
src="https://github.com/user-attachments/assets/c7f18bc4-4207-4bb0-8746-b61f1cdb3a90"
/>

However, when the release was being published, GitHub was still
internally registering the new release tag. Rather than publishing the
draft release, the publish step was unable to find the still-registering
tag, so it instead published a brand-new release. This one wasn't set to
a prerelease, and it had none of the binaries attached since the draft
release's settings didn't carry over.

<img width="693" height="266" alt="image"
src="https://github.com/user-attachments/assets/2b326998-2286-4632-be30-cdcd9d5a9d7c"
/>

I've since deleted both of these since releases being immutable makes it
difficult to fix this retroactively. To avoid this in the future, I've
added a short `sleep` to our release workflow; even 1 second seems to
have prevented this issue in all other nightly releases, but I've put 5
seconds to be safe. I've also replaced our final release step with a
call to `gh release edit`, which will immediately fail if the tag cannot
be found (couldn't find an analogue in
`luau-lang/action-gh-release@v2`).
… files directory. (#466)

Varying OSes provide different preferred locations for temporary files,
and libuv provides an API by which we can get at that. We should make
that available so that people can build cross-platform code that
interacts with these directories safely.
)

I looked at all of our usage of `lua_pushstring` in Lute today, and
replaced any instance with `lua_pushlstring` if it was a dynamic string
value where we know the size already (e.g. because we determined the
size using libuv APIs).
This needed to happen sooner or later, and I preferred sooner because
the old tests were spitting out a bunch of output which makes it hard to
debug CI
We changed the domain to not be under a folder, but be under a subdomain
(`lute.luau.org`, instead of `luau-lang.github.io/lute/`), so we need to
update the vitepress default.
… code from a bytecode bundle. (#450)

This PR implements a 'bundle' virtual file system, for navigating
requires and loading bytecode from an executable compiled with `lute
compile`.
We got some useful feedback from @vocksel about not being able to get a
clean refinement between array and object with the existing types setup,
and the correct solution to this problem here is for us to leverage
another newproxy as a key to distinguish between objects and arrays.
We've provided some additional functions to the interface of `json` both
to construct `object`s and to test against values being `object`s or
`array`s. There's also some clean up in here for json as a library
generally, including correcting its casing now that it's a standard
library and including `object` and `array` as part of the exported types
as well.
…path` and `pathlike` types instead of `string` (#462)

### Problem
Some Lute `fs` and `process` functions have been processing file paths
as `string` types while other places in Lute have been using `path` or
`pathlike` for file path handling/processing. We want to add support for
`path` and `pathlike` file paths to `fs` and `process` functions.

### Solution

We're introducing `fs` and `process` to the Lute standard library as
`@std/fs` and `@std/process` that act as wrappers around the existing
Lute `fs` and `process` files where we can pass in `pathlike` type paths
in `@std/fs` and return `path` type paths in `@std/process` instead of
needing to parse and format each call.

There's also a refactor of the `path/` directory that separates out type
definitions into a separate file outside of the `init`. This was
partially due to a previous attempt of handling path types and running
into cyclic dependencies due to the nature of the `process.luau` file,
but seemed reasonable to keep around for potential future use.

Added tests and found some minor bugs in `process.cpp` that is also
fixed in this pr
reverting the `fs` and `process` of `reference.luau` for docs gen to use
`@lute` instead of `@std` because it uses `table.concat` on the `string`
version of cwd
fixes failing build for docs

reverted both just for consistency in the requires for this file (that
will hopefully be replaced with another version of doc gen soon)
We suddenly started getting CI failures for `getSourceRoot`, but we can
set the environment variable instead to make sure it works consistently.
Fixes the build to work with clang-cl.

- `clang-cl` errored out on the generated strings, because they had `\r`
at the end (from the default Windows line endings[^1]).
- `/Zc:externConstexpr` is unsupported/not needed on `clang-cl`

[^1]: Might be worth to have something like a `splitlines` that works
with both LF and CRLF.

Co-authored-by: ariel <arielweiss@roblox.com>
…orrectly when bytecode compiling them. (#452)

This PR implement a static require tracer for Luau as a prerequisite to
enabling multi file bytecode compilation. This module statically
resolves requires relative to a given entry module, effectively
snapshotting the state of the filesystem for embedding in a lute
executable. This module graph will be embedded in the lute executable
when `lute compile` is invoked and will let the bundle virtual file
system [PR](#450) correctly
navigate the directory structure to resolve `require` calls and match up
those paths to the pre-compiled bytecode embedded in the bundle.
Separating this out from a different PR so the fix can get in sooner
(resolves #463)

Co-authored-by: ariel <arielweiss@roblox.com>
This will make those files not an unidentified language, which makes me
personally slightly happier.
Wrap `system.tmpdir` in path to make our stdlib interfaces more
consistent

---------

Co-authored-by: ariel <arielweiss@roblox.com>
skberkeley and others added 30 commits January 14, 2026 11:31
Adds support for autofixing reported lint violations (if the lint rules
provide suggested fixes). The core logic for applying the fixes is
pretty simple: split the content by line and do the replacements to the
relevant lines. For now, we don't handle the cases where suggested fixes
overlap (although my approach would probably be to just ignore fixes
that overlap with previously applied fixes). We rerun the lints after
applying fixes and report any violations that are still left. It's
possible that those reported violations have suggested fixes, but we
ignore them to prevent the chance of looping between suggested fixes
infinitely.
Continuation of #661 and one part
of making file system APIs asynchronous
(#709)
Addresses #709's journey of making our file system APIs asynchronous
Co-authored-by: ariel <arielweiss@roblox.com>
#734)

This PR just updates the `run`, `test` and `compile` cli command
reference.
This PR just pulls in the Luau CLI's Profiler and Code Coverage modules
into `lute`. We're doing this instead of exposing them from Luau because
these features are not really products, so much as best effort attempts,
so we don't necessarily want to expose them from Luau yet.

This is just copied from Luau/CLI - no changes have been made.
Adds some more description to the docs for `lute lint` and `lute
transform`
**Luau**: Updated from `0.704` to `0.705`

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

---
*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: ariel <arielweiss@roblox.com>
**Lute**: Updated from `0.1.0-nightly.20260109` to
`0.1.0-nightly.20260116`

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

---
*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: Annie Tang <98965493+annieetang@users.noreply.github.com>
This PR just pulls in @checkraisefold 's fix here:
#740. The main change is to check
the return error code from `uv_fs_scandir`.

Using the UVRequest abstractions a) helps make this function suitable
for use cooperatively (async), and handles the additional memory
management improvments that @checkraisefold added.

Helps address one of the functions listed in
#709
To support registering code actions in Mandolin, it is essential that
the `suggestedfix` data is serialized as part of `lute lint`'s JSON
diagnostic output.

This PR adds support for this and a sanity check test case
GitHub does not preserve permissions when uploading files as an
artifact, causing the executable bit of the binaries within the release
artifacts to be lost. This makes Lute not executable when installing it
using [mise-en-place's GitHub
backend](https://mise.jdx.dev/dev-tools/backends/github.html).

This PR re-adds the executable bit to the release artifacts.

---------

Co-authored-by: Varun Saini <61795485+vrn-sn@users.noreply.github.com>
So we can use `fileutils` without including `Lute.CLI`
…ath-like types (#749)

I noticed some errors in `std/libs/fs.luau` that seemed like false
positives, it looks like we were requiring that "pathlike" data either
be a string or `path`, the latter of which must be a table with the
correct metatable. Based on the definitions of `posixtypes.pathlike` and
`win32types.pathlike`, it seems like this type was _intended_ to take
the underlying data as well, so one can write something like:

```luau
local pathlib = require("@std/path")
print(pathlib.format({ absolute = true, parts = {"foo", "bar", "baz"}}))
```
…hronous (#745)

Another four `fs` functions for
#709!
Initial version of a new `lute doc` Command Line Interface! 

tldr; this is basically a refactor of the `scripts/reference.luau` file
via CLI to make reviewing easier

Details:

This currently follows the exact logic of `scripts/reference.luau` that
string matches generating the `@lute` and `@std` parts of
lute.luau.org/reference as well as the default pages, so it's very much
hard coded and not intended on being used by any other repo yet, but I
wanted to get the CLI set up and iterate incrementally on this
afterwards to avoid massive PRs.

Current workflow:

```bash
$ lute doc
```

is the equivalent of 

```bash
$ lute run scripts/reference.luau
```

There's an option to specify the output directory, which github actions
needs because it's run in a different cwd I think? So you can also run
with

```bash
$ lute doc -o ./specified-docs-folder
```

That generates this lute repo's `definitions/` and `std/` docs the exact
same way the website shows it as.

#### Immediate next steps (PRs):

1. Refactor and add an `--module` option that specifies which module to
generate, so the current `generateAllDocs` won't be hard coding the
`definitions` and `std` paths.
1. Note: for this I'd then want `--module` to be a required option and
not have the CLI generate docs for everything since the script isn't
reliable yet.
3. Update the `processDirectory` to use the `typeofmodule` API in
`@lute/lute` that gets the actual type info of the module instead of
this string matching pattern.
1. `luau.typeofmodule` is currently returning a string representation of
the module type so this code will probably look a bit ugly too until
we're unblocked on having that API be represented in some data structure
form.
5. Have `lute doc` generate docs for everything in the current working
directory by default, so `generateAllDocs` actually generates all docs.

then there's more after that but just listing these for now!
I reordered tableext methods to group dictionary and array methods more
distinctly
(I ensured `keys` and `toset` are at the boundary as they convert
between the two table formats)

This PR is intended to be merged after:
- #699
Next step towards lute doc gen!

1st follow up from #748

`lute doc` now requires module paths to be specified:

```bash
Usage: lute doc [OPTIONS] [...MODULE_PATHS]
```

Example:

```bash
$ lute doc -o mydocs module1 module2
```

For the Lute repo, this would be:

```bash
$ lute doc definitions lute/std/libs
```
(since the default directory is `docs/`)

Will find the `definitions` and `lute/std/libs` folder from current
working directory and generate docs for them. The module paths can be
relative or absolute as well! This example is basically what the github
actions bot runs to generate the lute site!

I also don't really know how to show the output other than linking the
docs artifact that github ran that shows the folder layout?
Artifact download URL:
https://github.com/luau-lang/lute/actions/runs/21268929608/artifacts/5227316204
…ot in the same directory as the luaurc (#753)

Addresses #708

In the linked issue, removing the entry point limit to the `.luaurc`
discovery doesn't fix the issue. When doing so, `src` doesn't exist as a
path in the bundle VFS and it crashes at runtime when trying to
`require("@ext/bat")`

The LCR calculation calculates `LCR("repo/src/entry.luau",
"repo/src/batteries/bat.luau") = src`, and the final bundle VFS gets
laid out as:
```
@Bundle
  entry.luau
  batteries
    bat.luau
```

The `.luaurc` has this, which doesn't actually match with the bundle
VFS.
```
    "aliases": {
        "ext": "./src/batteries/"
    }
```

So when trying to `require("@ext/bat")`, lute tries to navigate to
`@bundle/src/batteries`. `"@bundle/src"` doesn't exist and crashes
[here](https://github.com/luau-lang/lute/blob/e11f8b0c0d933e7bbd0463c9213a364fb966f920/lute/require/src/modulepath.cpp#L119).

This fix adds any discovered `.luaurc` to the LCR calculation, which
makes the paths between the bundle VFS and the `.luaurc` at the repo
root symmetric.

Alternatively, could have used the LCR to strip prefixes in the bundled
`.luaurc`.
…755)

This PR fixes #703, which
reports high CPU consumption when the runtime should have no work to do.

A fix was contributed here
https://github.com/luau-lang/lute/pull/704/changes, but ended up running
into issues and blocking the runtime thread even though there were
continuations to process. The modification needed here is to check if
there are threads that need to be scheduled, or any continuations, and
if there are, run in NO_WAIT mode. If there aren't any of these, then
block until there is work on the event loop to do.

This is only a patch - ideally, we would always run in UV_RUN_ONCE mode.
Eventually, we should get rid of the continuations vector, and schedule
continuations on the libuv event loop. At that point, we can delete
these checks, and just pass UV_RUN_ONCE to the uv_run method.
We can use additional diagnostic metadata like a `target` URI to surface
additional information about a lint violation in Mandolin [(vscode
API)](https://code.visualstudio.com/api/references/vscode-api#Diagnostic).

This PR supports this by:
- extending `LintViolation` type to include `target`
- extending `Diagnostic` type to align with the vscode API
- serializing `diagnostic.code` as an object with `value` and `target`
fields, if the passed violation includes a `target`

This provides a baseline that can be easily consumed by Mandolin to
surface such metadata. One can imagine the convenience of being able to
follow a lint violation to relevant docs, or something similar:
<img width="1000" height="60" alt="Screenshot 2026-01-22 at 9 58 52 AM"
src="https://github.com/user-attachments/assets/9968c1e3-24fd-4b97-82c0-3df3f9621753"
/>
…l` and `lute pkg run` (#715)

Very early prototype that will likely change substantially in the next
few weeks as we start getting feedback and iterate on the design.

If the current directory has a `loom.config.luau` in it like the
following example:
```luau
-- loom.config.luau
return {
	package = {
		name = "MyProject",
		version = "0.1.0",
		dependencies = {
			["pretty-print"] = { rev = "main", source_kind = "github", source = "https://github.com/afujiwara-roblox/pretty-print" },
			base64 = { rev = "main", source_kind = "github", source = "https://github.com/afujiwara-roblox/base64" },
			toml = { rev = "main", source_kind = "github", source = "https://github.com/afujiwara-roblox/toml" },
		},
	},
}
```

Running `lute pkg install` will install the declared dependencies into a
`Packages` folder in the current directory. (No global package cache
support yet, but there are no technical reasons we can't do that—this is
just simpler as a starting point.)

When the dependencies are installed, a `loom.lock.luau` file will be
generated. When this file is present in a project, we can opt-in to
package awareness by using `lute pkg run <file.luau>`. With package
awareness enabled, case-insensitive aliases to the installed packages
are automatically made available to the Lute runtime, allowing us to run
a script like this:

```luau
-- These three dependencies will be required successfully if:
-- 1. They were declared in a manifest file (`loom.config.luau`).
-- 2. The `lute pkg install` subcommand successfully installed them into the `Packages` folder.
-- 3. This script was run with package awareness enabled (`lute pkg run <this_file.luau>`).

local toml = require("@TomL")
local prettyprint = require("@pretty-print")
local base64 = require("@base64")

local toml_content = [[
[config]
key = "TG9vbSBpcyBzbyBjb29sISB3b3dvd293"
key2 = "VGhlIGJlc3QgdGhpbmcgc2luY2Ugc2xpY2VkIGJyZWFkIQ=="
]]

-- Deserialize the TOML content using the @TomL library
local config = toml.deserialize(toml_content) :: any

print("------------------------------")
print("This is the original config")
print(config)
print("------------------------------")
print("Pretty printed original config:")
print(prettyprint(config))
print("------------------------------")
-- Decode the base64 encoded keys using the @base64 library
config.config.key = buffer.tostring(base64.decode(buffer.fromstring(config.config.key)))
config.config.key2 = buffer.tostring(base64.decode(buffer.fromstring(config.config.key2)))

print("Pretty printed decoded config:")
print(prettyprint(config))
print("------------------------------")
```

This prototype still has rough edges that we (primarily
@afujiwara-roblox and @vrn-sn) hope to iron out as we receive feedback.
…e repo. (#751)

This PR adds a script called `check.luau` that gathers up every .luau
file in `std/libs/` and `tests/` and passes them to the `lute check`
command. `check.luau` takes an optional `--update` argument that will
update a list of all the type errors. I'm using the diffext battery to
show the diff, but I think we need to add some more pretty printing
options for that to be useful atm.

I've also added a CI job that will prevent PR's from merging if they
introduce a new type error.
You can invoke the profiler with:
```
lute --profile <--frequency 1000> <--profile-output filename> myfile.luau
```

to get a trace file that can be inspected by ui.perfetto.dev.

This profiler works by sampling callstacks at a given frequency,
assigning the delta time between samples to _each_ frame in the
currently observed callstack(which is a simplifying assumption, but if
your sample frequency is high enough, end up being okay). By tracking
callstacks between calls from the VM to `interrupt`, we can emit begin
and end events by diffing the stacks, nesting as appropriate. For
example, a callstack like:
``` 
main -> foo -> bar -> baz
```
should produce:
```
BEGIN_main, 
   BEGIN_foo, 
     BEGIN_bar, 
        BEGIN_baz, 
        END_baz, 
      END_bar, 
   END_foo, 
END_main
```
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.