When a script/txt/csv child is renamed by name_for_inst (e.g. "Init" →
"_Init.luau"), the adjacent meta file must follow the same name. All
three callers were using the Roblox instance name to construct the meta
path, producing "Init.meta.json" instead of "_Init.meta.json" — which
collides with the parent directory's "init.meta.json" on
case-insensitive file systems.
Fix by deriving the meta stem from the first dot-segment of the
snapshot path file name, which already holds the resolved name.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When a child instance has a Roblox name that would produce a filesystem
name of "init" (case-insensitive), syncback now automatically prefixes
it with '_' (e.g. "Init" → "_Init.luau") instead of erroring. The
corresponding meta.json writes the original name via the `name` property
so Rojo can restore it on the next snapshot.
The sibling dedup check is updated to use actual on-disk names for
existing children and the resolved (init-prefixed) name for new ones,
so genuine collisions still error while false positives from the `name`
property are avoided.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The VFS only sets up file watches via read() and read_dir(), not
metadata(). When git filtering caused snapshot_from_vfs to return
early for $path directories, read_dir was never called, so no file
watch was established. This meant file modifications never generated
VFS events and were silently ignored until the server was restarted.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two issues prevented --git-since from working correctly during live sync:
1. Server: File changes weren't detected because git-filtered project nodes
had empty relevant_paths, so the change processor couldn't map VFS events
back to tree instances. Fixed by registering $path directories and the
project folder in relevant_paths even when filtered.
2. Plugin: When a previously-filtered file was first acknowledged, it appeared
as an ADD patch. The plugin created a new instance instead of adopting the
existing one in Studio, causing duplicates. Fixed by checking for untracked
children with matching Name+ClassName before calling Instance.new.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add new GitFilter struct for tracking files changed since a Git reference
- Only sync changed (added/deleted/modified) files to Roblox Studio
- Files remain acknowledged once synced, even if content is reverted
- Add enhanced logging for debugging sync issues
- Force acknowledge project structure to prevent 'Cannot sync a model as a place' errors
Replaces `serde_json` parsing with `jsonc-parser` throughout the
codebase, enabling support for **comments** and **trailing commas** in
all JSON files including `.project.json`, `.model.json`, and
`.meta.json` files.
MSRV bumps from `1.83.0` to `1.88.0` in order to
use the jsonc_parser dependency.
Closes#858.
If a project is named `default.project.json`, it acts as an `init` file
and gains the name of the folder it's inside of. If it is named
something other than `default.project.json`, it gains the name of the
file with `.project.json` trimmed off. So e.g. `foo.project.json`
becomes `foo`.
Resolves#667
This PR:
- Introduces a new field in the project file: `scriptType` which has the
default value of `Class` (in parity with previous versions), but can
also be `RunContext`.
- This is then passed to `InstanceContext` from the `Project` struct.
- This then changes the RunContext in the lua `snapshot_middleware`
---------
Co-authored-by: Micah <dekkonot@rocketmail.com>
Services, `StarterPlayerScripts`, and `StarterCharacterScripts` are
currently special-cased to allow them to be specified in project files
without a classname. This does the same to `Terrain` since it's a
singleton in the same style as those.
TOML maps well to Lua, is easier to read and write than JSON, and is
commonly used by Roblox tools.
Use cases:
* Put game, plugin, or library config in a toml file
* Sync in toml files generated by tools
* Sync in config files for tools so that the game can double-check that
the config file has been followed. (e.g. check that packages match
versions specified in wally.toml)
Ref now is an optional inside, so it's redundant to have an option
wrapping an option. The only snapshots that were changed were any that
had a Ref within (from none to zeroed). Some also had some newlines
added in the end.
* Support implicit values for primitive attributes
This commit adds support for strings, numbers, and booleans to be implicitly typed in attribute maps, reducing the redundancy of needing to specify their types.
I also quietly adjusted one of the tests to use a more stable class/property pair. Since SourceAssetId is locked to Roblox, it could potentially disappear at any time.
* Apply formatting.
* Address feedback
* Backwards compatible format usage.
* Axe UnresolvedValueMap in favor of $attributes
Attributes can be defined directly on instances, with support for unambiguous types.
* Adjust test.
* to_string() -> into()
* Made attribute test more concise.
* small cleanup
* Update src/resolution.rs
* Update src/resolution.rs
* Update src/resolution.rs
* Update src/resolution.rs
Co-authored-by: Lucien Greathouse <me@lpghatguy.com>
* Disambiguate camelCase and PascalCase.
*.meta.json forces camelCase while *.model.json forces PascalCase. This commit reinforces camelCase as the preference for both, but allows for PascalCase in both as well.
* Made requested changes, breaking due to serde bug.
* Make work with existing Serde stuff
* Work around MSRV
Co-authored-by: Lucien Greathouse <me@lpghatguy.com>
* Use WeakDom::into_raw for faster snapshot generation from models
* Make compute_patch_set take snapshots by value
* Stop deferring property application in apply_patch_set
* Use InstanceBuilder::empty to avoid extra name allocations
* Git dependencies, skip dropping ServeSession
* Use std::mem::forget instead of ManuallyDrop
* Switch to latest rbx-dom crates.io dependencies
* Update other dependencies
* Add PathNode with optional fields to project. This allows a path to be defined either as `"$path": "src"` or `"$path": { "optional": "src" }`
* Make $path truly optional
* Prevent rojo from erroring if no project node is resolved
* Use match instead of if-statement
* Add end-to-end tests (credit to MobiusCraftFlip for initial scenario)
* Pass option with ref inside instead of reference to option
* Empty commit to restart GitHub Actions
* Simplify build test
* Minimize serve test: it fails
* Simplify serve test even more
* Ignore failing serve test
Co-authored-by: Lucien Greathouse <me@lpghatguy.com>