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
8 changes: 4 additions & 4 deletions build/release-evidence.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
"schema_version": 2,
"module": {
"repository": "NDDev-it-com/nddev-zcode-app",
"setup_digest": "sha256:ae37209353cd6a10f43312c24941975d845587558619ade8f37ba55e535bfac5"
"setup_digest": "sha256:1ae439320693f777e93ae341cc4b2341a006bb6abe6fa417abdfcba8860bc072"
},
"harness": {
"repository": "NDDev-it-com/nddev-harnesses",
"commit": "a598102aff438239c8efcd2c790cd31356278267"
"commit": "1254bf60ddc5e50017b761f837893b85709ebe9f"
},
"adapter": {
"id": "zcode",
Expand All @@ -30,8 +30,8 @@
}
],
"lanes": [],
"generated_at_utc": "2026-07-17T18:03:49Z",
"expires_at_utc": "2027-01-13T18:03:49Z",
"generated_at_utc": "2026-07-18T01:26:53Z",
"expires_at_utc": "2027-01-14T01:26:53Z",
"promotion": {
"decision": "pending",
"waivers": []
Expand Down
35 changes: 35 additions & 0 deletions cli-tools/scripts/lib/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1209,6 +1209,40 @@ nddev::render_env() {
nddev::parse_env_file "$src_env" "$NDDEV_ENV_DIGEST" "$target/.env" >/dev/null || return 1
}

nddev::flatten_plugin_components() {
# ZCode loads user-scope skills, commands, and agents from ~/.zcode/skills,
# ~/.zcode/commands, and ~/.zcode/agents -- never from
# marketplaces/<mp>/plugins/. Surface each installed plugin's components at
# user scope so a headless install is actually loaded by the client, while the
# marketplace tree stays intact for the plugin/marketplace model and any later
# UI-managed installation. A name collision between two plugins, or between a
# plugin and a direct user-scope component, fails closed rather than silently
# shadowing one -- important as setups grow to many plugins.
local target=$1 mp_name plugins_root plugin component source entry name dest
mp_name="$(basename "$SOURCE_DIR")"
plugins_root="$target/marketplaces/$mp_name/plugins"
[ -d "$plugins_root" ] || return 0
for plugin in "$plugins_root"/*/; do
[ -d "$plugin" ] || continue
for component in skills commands agents; do
source="$plugin$component"
[ -d "$source" ] || continue
nddev::ensure_dir "$target/$component" || return 1
for entry in "$source"/*; do
[ -e "$entry" ] || continue
name="$(basename "$entry")"
[ "$name" = ".gitkeep" ] && continue
dest="$target/$component/$name"
if [ -e "$dest" ] && [ "${NDDEV_DRY_RUN:-1}" -eq 0 ]; then
nddev::log "error" "user-scope $component name collision: $name"
return 1
fi
nddev::copy "$entry" "$dest" || return 1
done
done
done
}

nddev::copy_source_tree() {
local target=$1 mp_name directory
mp_name="$(basename "$SOURCE_DIR")"
Expand All @@ -1222,6 +1256,7 @@ nddev::copy_source_tree() {
nddev::copy "$SOURCE_DIR/$directory/." "$target/$directory/" || return 1
fi
done
nddev::flatten_plugin_components "$target" || return 1
}

nddev::build_clean() {
Expand Down
Loading