Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 22 additions & 15 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ lyracore packages config NAME [KEY [VALUE]] [--new]
lyracore packages disable NAME [--yes]
lyracore packages enable NAME
lyracore packages list
lyracore packages new NAME
lyracore packages new NAME [--from RUNG]
lyracore packages remove NAME [--yes]
lyracore packages replay [DATABASE ...] [--check] [--yes] [--force-all] [--client-data PATH]
lyracore packages update [NAME] [--yes]
Expand Down Expand Up @@ -102,7 +102,7 @@ lyracore update
| `packages disable` | run Package Teardown on every Shard, then move the Package out of the build's sight, keeping it on disk |
| `packages enable` | move a disabled Package back into the build |
| `packages list` | every installed Package: enabled or disabled, where it came from, and whether it has drifted |
| `packages new` | scaffold a new Package offline, by copying and renaming the reference Package this checkout ships |
| `packages new` | copy and rename a Reference Package from the collection tag matching this checkout's Package API |
| `packages remove` | delete a disabled Package, after a confirmation and a check for local changes |
| `packages replay` | reapply every enabled Package's claims and Runtime Scripts onto the named Shards, or the whole recorded fixture topology by default |
| `packages update` | advance a Git-backed Package, or every one of them, to the repository's current commit |
Expand Down Expand Up @@ -229,7 +229,8 @@ for you**, so a plain `./lyracore import` never asks twice.
./lyracore packages add https://host/greeter.git # clone a repository whose root is one Package
./lyracore packages add greeter # bare name: resolve from the Official Package Collection
./lyracore packages list
./lyracore packages new my-package # scaffold one from nothing but this checkout
./lyracore packages new my-package # start with example-script
./lyracore packages new my-package --from example-rust
```

A Package is a drop-in folder under `packages/<name>/`. `module/build.rs` discovers it and compiles
Expand Down Expand Up @@ -298,18 +299,24 @@ Identity, whether the tree on disk still matches it (`clean` or `LOCALLY DRIFTED
registers. A Package with no stamp — dropped into `packages/` by hand, or installed before this
command existed — renders as unrecorded rather than failing the listing.

**`packages new NAME` scaffolds a Package with no network access and nothing external to review.**
It copies `packages/example/` — the maintained reference Package every LyraCore checkout ships,
including a fresh public clone — to `packages/NAME/`, renaming the reference's own identifiers into
the new name, then writes a Provenance Stamp recording a **scaffold** origin rather than a Package
Source (nothing external was installed, so there is nothing to name) and runs `preflight`. The same
name and shape refusals as `add` apply before anything is written. The reference Package is
Rust-only and inert. Its `src/mod.rs` carries one commented hook pattern, and the scaffold has no
`client/` directory. The printed next steps say to add `client/addons/<Name>/` for addons or `client/mpq/`
for client-file overrides, and that `client sync` will pack them in once you do. Growing the Rust
half means wiring more hooks from the catalogue in `module/src/hooks.rs`, following the pattern
`packages/NAME/src/mod.rs` already shows. A scaffold ships no Datascript: the authoring toolchain
in `datascripts/` is checkout-wide today, not per-Package.
`packages new NAME [--from RUNG]` fetches a Reference Package from the Official Package Collection.
The checkout's Package API version selects its tag, as with `packages add`. The default is
`example-script`, which needs no Rust. Other rungs are `example-client`, `example-data`,
`example-rust` and `example-all`. A missing tag or rung leaves the Package Inventory unchanged.

The command copies the source into `packages/NAME/`, renames Package names, Rust identifiers and
client filenames, prints its Trust Review and runs `preflight`. The Provenance Stamp keeps the
`scaffold` kind and records the chosen rung and exact collection revision. `packages update`
does not replace scaffolded code.

Rungs with Runtime Scripts or Datascripts need a lowercase Package name of at most 64 characters.
Each `<name>.<script file stem>` must also fit the 64-character Runtime Script name limit.

Generated artifacts are omitted because the renamed sources need new Build Identities. Before
using a copy beside another, choose distinct `@id` values for Runtime Scripts or a distinct Package
Spell ID in its Datascript. Run `packages build` after editing the sources. A Datascript also needs
a Base Snapshot from your own client data. Replay the built artifacts through the normal realm
update; use `client sync` for a client half. Scaffolding requires network access to the collection.

## `packages enable`, `disable`, `remove` — taking a Package out of the build

Expand Down
4 changes: 2 additions & 2 deletions src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ fn run(args: &[String]) -> Result<i32> {
)
.map(|_| EXIT_OK),
Command::PackagesList => cmd::packages::list(&ProjectLayout::discover()?).map(|_| EXIT_OK),
Command::PackagesNew { name } => {
cmd::packages::new(&ProjectLayout::discover()?, &runner, &name).map(|_| EXIT_OK)
Command::PackagesNew { name, from } => {
cmd::packages::new(&ProjectLayout::discover()?, &runner, &name, &from).map(|_| EXIT_OK)
}
Command::PackagesBuild => {
cmd::packages::build::run(&ProjectLayout::discover()?, &runner).map(|_| EXIT_OK)
Expand Down
84 changes: 68 additions & 16 deletions src/cmd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,12 @@ USAGE:
Package Source, its recorded content identity,
whether the installed copy has drifted from it,
and what it registers
lyracore packages new NAME scaffold from the maintained reference Package in
this checkout (packages/example/), without fetching
a template. Refuses enabled/disabled collisions,
then runs ordinary preflight (whose Cargo checks may
use its configured cache/network). No client content;
the printed next steps explain how to add it
lyracore packages new NAME [--from RUNG] copy a Reference Package from the collection tag for
this checkout's Package API. Defaults to example-script.
Other rungs: example-client, example-data, example-rust,
example-all. Records the rung and revision, renames
source and runs preflight. Build new artifacts with
`packages build` after choosing distinct IDs
lyracore production status --server URI --gateway-log PATH --realm-core DB DATABASE ...
read-only production topology, schema, connection,
realm-core and listener verdicts
Expand Down Expand Up @@ -263,6 +263,7 @@ pub enum Command {
PackagesList,
PackagesNew {
name: String,
from: String,
},
PackagesBuild,
PackagesCheck,
Expand Down Expand Up @@ -419,15 +420,7 @@ impl Command {
["packages", "list", other, ..] => Err(Error::Usage(format!(
"`packages list` takes no arguments (got '{other}')"
))),
["packages", "new", name] => Ok(Command::PackagesNew {
name: (*name).to_string(),
}),
["packages", "new"] => Err(Error::Usage(
"`packages new` needs a name, e.g. `packages new my-package`".to_string(),
)),
["packages", "new", _name, other, ..] => Err(Error::Usage(format!(
"`packages new` takes one name (got a second argument: '{other}')"
))),
["packages", "new", rest @ ..] => parse_packages_new(rest),
["packages", "replay", rest @ ..] => parse_packages_replay(rest),
["packages", "config", rest @ ..] => parse_packages_config(rest),
["packages", "build"] => Ok(Command::PackagesBuild),
Expand Down Expand Up @@ -693,6 +686,41 @@ fn parse_packages_replay(args: &[&str]) -> Result<Command> {
Ok(Command::PackagesReplay(options))
}

fn parse_packages_new(args: &[&str]) -> Result<Command> {
let mut name = None;
let mut from = None;
let mut args = args.iter();
while let Some(arg) = args.next() {
match *arg {
"--from" if from.is_none() => {
from = Some(
args.next()
.filter(|value| !value.starts_with('-'))
.ok_or_else(|| {
Error::Usage("`--from` needs a Reference Package name".to_string())
})?
.to_string(),
);
}
option if option.starts_with('-') => {
return Err(Error::Usage(format!(
"unknown or repeated `packages new` option '{option}'; use NAME [--from RUNG]"
)))
}
value if name.is_none() => name = Some(value.to_string()),
value => {
return Err(Error::Usage(format!(
"`packages new` takes one name, got '{value}' too"
)))
}
}
}
Ok(Command::PackagesNew {
name: name.ok_or_else(|| Error::Usage("`packages new` needs a name".to_string()))?,
from: from.unwrap_or_else(|| packages::DEFAULT_REFERENCE.to_string()),
})
}

/// `client pack --out DIR [--zip]`.
///
/// `--out` and `--zip` interleave freely, the same as `packages replay`'s options — but this verb
Expand Down Expand Up @@ -1692,13 +1720,37 @@ mod tests {
parse("packages new greeter").unwrap(),
Command::PackagesNew {
name: "greeter".to_string(),
from: packages::DEFAULT_REFERENCE.to_string(),
}
);
}

#[test]
fn packages_new_accepts_from_on_either_side_of_the_name() {
for line in [
"packages new greeter --from example-rust",
"packages new --from example-rust greeter",
] {
assert_eq!(
parse(line).unwrap(),
Command::PackagesNew {
name: "greeter".to_string(),
from: "example-rust".to_string(),
}
);
}
}

#[test]
fn packages_new_refuses_no_name_and_a_second_argument() {
for line in ["packages new", "packages new greeter extra"] {
for line in [
"packages new",
"packages new greeter extra",
"packages new greeter --from",
"packages new greeter --from --bad",
"packages new greeter --from example-rust --from example-data",
"packages new --bad greeter",
] {
let error = parse(line).unwrap_err();
assert_eq!(error.exit_code(), crate::error::EXIT_USAGE, "{line}");
}
Expand Down
3 changes: 2 additions & 1 deletion src/cmd/packages/lifecycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -863,7 +863,8 @@ pub(crate) mod tests {

// A scaffold was copied out of this checkout and renamed. Re-adding it would not bring
// back the Package that is being deleted.
let scaffold = ProvenanceStamp::scaffolded("packages/example/", String::new(), 0);
let scaffold =
ProvenanceStamp::scaffolded("example-script", "abcdef".to_string(), String::new(), 0);
let name = PackageName::parse("greeter").unwrap();
assert!(recovery_note(&name, Some(&scaffold)).contains("final"));
assert!(recovery_note(&name, Some(&missing_kind)).contains("final"));
Expand Down
Loading
Loading