@prmichaelsen/remember-mcp 3.15.4 → 3.15.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENT.md +363 -5
- package/CHANGELOG.md +7 -0
- package/agent/commands/acp.clarification-capture.md +386 -0
- package/agent/commands/acp.clarification-create.md +50 -0
- package/agent/commands/acp.command-create.md +60 -0
- package/agent/commands/acp.design-create.md +62 -0
- package/agent/commands/acp.design-reference.md +355 -0
- package/agent/commands/acp.index.md +423 -0
- package/agent/commands/acp.init.md +48 -0
- package/agent/commands/acp.package-create.md +1 -0
- package/agent/commands/acp.package-info.md +1 -0
- package/agent/commands/acp.package-install.md +19 -0
- package/agent/commands/acp.package-list.md +1 -0
- package/agent/commands/acp.package-publish.md +1 -0
- package/agent/commands/acp.package-remove.md +1 -0
- package/agent/commands/acp.package-search.md +1 -0
- package/agent/commands/acp.package-update.md +1 -0
- package/agent/commands/acp.package-validate.md +1 -0
- package/agent/commands/acp.pattern-create.md +60 -0
- package/agent/commands/acp.plan.md +25 -0
- package/agent/commands/acp.proceed.md +621 -75
- package/agent/commands/acp.project-create.md +3 -0
- package/agent/commands/acp.project-info.md +3 -0
- package/agent/commands/acp.project-list.md +3 -1
- package/agent/commands/acp.project-set.md +1 -0
- package/agent/commands/acp.project-update.md +14 -3
- package/agent/commands/acp.projects-restore.md +228 -0
- package/agent/commands/acp.projects-sync.md +347 -0
- package/agent/commands/acp.report.md +13 -0
- package/agent/commands/acp.resume.md +3 -1
- package/agent/commands/acp.sessions.md +301 -0
- package/agent/commands/acp.status.md +13 -0
- package/agent/commands/acp.sync.md +1 -0
- package/agent/commands/acp.task-create.md +105 -3
- package/agent/commands/acp.update.md +1 -0
- package/agent/commands/acp.validate.md +32 -2
- package/agent/commands/acp.version-check-for-updates.md +1 -0
- package/agent/commands/acp.version-check.md +1 -0
- package/agent/commands/acp.version-update.md +1 -0
- package/agent/commands/command.template.md +23 -0
- package/agent/commands/git.commit.md +1 -0
- package/agent/commands/git.init.md +1 -0
- package/agent/design/complete-tool-set.md +157 -233
- package/agent/design/design.template.md +18 -0
- package/agent/design/user-preferences.md +11 -7
- package/agent/milestones/milestone-19-new-search-ghost-tools.md +46 -0
- package/agent/package.template.yaml +50 -0
- package/agent/patterns/pattern.template.md +18 -0
- package/agent/progress.yaml +162 -6
- package/agent/scripts/acp.common.sh +258 -15
- package/agent/scripts/acp.install.sh +91 -4
- package/agent/scripts/acp.package-create.sh +0 -1
- package/agent/scripts/acp.package-info.sh +19 -1
- package/agent/scripts/acp.package-install-optimized.sh +1 -1
- package/agent/scripts/acp.package-install.sh +388 -38
- package/agent/scripts/acp.package-list.sh +52 -4
- package/agent/scripts/acp.package-remove.sh +77 -1
- package/agent/scripts/acp.package-search.sh +2 -2
- package/agent/scripts/acp.package-update.sh +91 -12
- package/agent/scripts/acp.package-validate.sh +136 -1
- package/agent/scripts/acp.project-info.sh +34 -11
- package/agent/scripts/acp.project-list.sh +4 -0
- package/agent/scripts/acp.project-update.sh +66 -19
- package/agent/scripts/acp.projects-restore.sh +170 -0
- package/agent/scripts/acp.projects-sync.sh +155 -0
- package/agent/scripts/acp.sessions.sh +725 -0
- package/agent/scripts/acp.version-update.sh +21 -3
- package/agent/scripts/acp.yaml-parser.sh +20 -6
- package/agent/tasks/milestone-19-new-search-ghost-tools/task-203-create-search-by-tool.md +143 -0
- package/agent/tasks/milestone-19-new-search-ghost-tools/task-204-add-new-filters-existing-tools.md +77 -0
- package/agent/tasks/milestone-19-new-search-ghost-tools/task-205-add-feel-fields-create-update.md +137 -0
- package/agent/tasks/milestone-19-new-search-ghost-tools/task-206-add-byproperty-bysignificance-modes.md +135 -0
- package/agent/tasks/milestone-19-new-search-ghost-tools/task-207-add-emotional-composites-search-results.md +88 -0
- package/agent/tasks/milestone-19-new-search-ghost-tools/task-208-add-bybroad-byrandom-modes.md +115 -0
- package/agent/tasks/milestone-19-new-search-ghost-tools/task-209-create-ghost-memory-tools.md +192 -0
- package/agent/tasks/milestone-19-new-search-ghost-tools/task-210-create-get-core-tool.md +203 -0
- package/agent/tasks/milestone-19-new-search-ghost-tools/task-211-create-search-space-by-tool.md +182 -0
- package/agent/tasks/task-1-{title}.template.md +19 -0
- package/agent/tasks/unassigned/bug-report-remember-core-e2e-findings.md +99 -0
- package/dist/e2e-helpers.d.ts +26 -0
- package/dist/ghost-persona.e2e.d.ts +8 -0
- package/dist/memory-crud.e2e.d.ts +8 -0
- package/dist/preferences.e2e.d.ts +8 -0
- package/dist/relationships.e2e.d.ts +8 -0
- package/dist/search-modes.e2e.d.ts +8 -0
- package/dist/server-factory.js +1971 -94
- package/dist/server.js +1168 -45
- package/dist/shared-spaces.e2e.d.ts +8 -0
- package/dist/tools/create-ghost-memory.d.ts +70 -0
- package/dist/tools/create-memory.d.ts +175 -0
- package/dist/tools/get-core.d.ts +28 -0
- package/dist/tools/get-core.spec.d.ts +2 -0
- package/dist/tools/ghost-tools.spec.d.ts +2 -0
- package/dist/tools/query-ghost-memory.d.ts +34 -0
- package/dist/tools/query-memory.d.ts +4 -0
- package/dist/tools/search-by.d.ts +147 -0
- package/dist/tools/search-by.spec.d.ts +2 -0
- package/dist/tools/search-ghost-memory-by.d.ts +54 -0
- package/dist/tools/search-ghost-memory.d.ts +53 -0
- package/dist/tools/search-memory.d.ts +19 -0
- package/dist/tools/search-space-by.d.ts +78 -0
- package/dist/tools/search-space-by.spec.d.ts +2 -0
- package/dist/tools/search-space.d.ts +2 -0
- package/dist/tools/update-ghost-memory.d.ts +51 -0
- package/dist/tools/update-memory.d.ts +175 -0
- package/jest.e2e.config.js +11 -0
- package/package.json +2 -2
- package/src/e2e-helpers.ts +86 -0
- package/src/ghost-persona.e2e.ts +215 -0
- package/src/memory-crud.e2e.ts +203 -0
- package/src/preferences.e2e.ts +88 -0
- package/src/relationships.e2e.ts +156 -0
- package/src/search-modes.e2e.ts +184 -0
- package/src/server-factory.ts +56 -0
- package/src/shared-spaces.e2e.ts +204 -0
- package/src/tools/create-ghost-memory.ts +103 -0
- package/src/tools/create-memory.ts +45 -1
- package/src/tools/get-core.spec.ts +223 -0
- package/src/tools/get-core.ts +109 -0
- package/src/tools/ghost-tools.spec.ts +361 -0
- package/src/tools/query-ghost-memory.ts +63 -0
- package/src/tools/query-memory.ts +4 -0
- package/src/tools/search-by.spec.ts +325 -0
- package/src/tools/search-by.ts +298 -0
- package/src/tools/search-ghost-memory-by.ts +80 -0
- package/src/tools/search-ghost-memory.ts +73 -0
- package/src/tools/search-memory.ts +23 -0
- package/src/tools/search-space-by.spec.ts +289 -0
- package/src/tools/search-space-by.ts +173 -0
- package/src/tools/search-space.ts +20 -1
- package/src/tools/update-ghost-memory.ts +86 -0
- package/src/tools/update-memory.ts +45 -1
|
@@ -19,10 +19,12 @@ INSTALL_PATTERNS=false
|
|
|
19
19
|
INSTALL_COMMANDS=false
|
|
20
20
|
INSTALL_DESIGNS=false
|
|
21
21
|
INSTALL_FILES=false
|
|
22
|
+
INSTALL_INDICES=false
|
|
22
23
|
PATTERN_FILES=()
|
|
23
24
|
COMMAND_FILES=()
|
|
24
25
|
DESIGN_FILES=()
|
|
25
26
|
FILE_FILES=()
|
|
27
|
+
INDEX_FILES=()
|
|
26
28
|
LIST_ONLY=false
|
|
27
29
|
GLOBAL_INSTALL=false
|
|
28
30
|
INSTALL_EXPERIMENTAL=false
|
|
@@ -49,7 +51,7 @@ while [[ $# -gt 0 ]]; do
|
|
|
49
51
|
--patterns)
|
|
50
52
|
INSTALL_PATTERNS=true
|
|
51
53
|
shift
|
|
52
|
-
while [[ $# -gt 0 && ! $1 =~
|
|
54
|
+
while [[ $# -gt 0 && ! $1 =~ ^- ]]; do
|
|
53
55
|
PATTERN_FILES+=("$1")
|
|
54
56
|
shift
|
|
55
57
|
done
|
|
@@ -57,7 +59,7 @@ while [[ $# -gt 0 ]]; do
|
|
|
57
59
|
--commands)
|
|
58
60
|
INSTALL_COMMANDS=true
|
|
59
61
|
shift
|
|
60
|
-
while [[ $# -gt 0 && ! $1 =~
|
|
62
|
+
while [[ $# -gt 0 && ! $1 =~ ^- ]]; do
|
|
61
63
|
COMMAND_FILES+=("$1")
|
|
62
64
|
shift
|
|
63
65
|
done
|
|
@@ -65,7 +67,7 @@ while [[ $# -gt 0 ]]; do
|
|
|
65
67
|
--designs)
|
|
66
68
|
INSTALL_DESIGNS=true
|
|
67
69
|
shift
|
|
68
|
-
while [[ $# -gt 0 && ! $1 =~
|
|
70
|
+
while [[ $# -gt 0 && ! $1 =~ ^- ]]; do
|
|
69
71
|
DESIGN_FILES+=("$1")
|
|
70
72
|
shift
|
|
71
73
|
done
|
|
@@ -73,11 +75,19 @@ while [[ $# -gt 0 ]]; do
|
|
|
73
75
|
--files)
|
|
74
76
|
INSTALL_FILES=true
|
|
75
77
|
shift
|
|
76
|
-
while [[ $# -gt 0 && ! $1 =~
|
|
78
|
+
while [[ $# -gt 0 && ! $1 =~ ^- ]]; do
|
|
77
79
|
FILE_FILES+=("$1")
|
|
78
80
|
shift
|
|
79
81
|
done
|
|
80
82
|
;;
|
|
83
|
+
--indices)
|
|
84
|
+
INSTALL_INDICES=true
|
|
85
|
+
shift
|
|
86
|
+
while [[ $# -gt 0 && ! $1 =~ ^- ]]; do
|
|
87
|
+
INDEX_FILES+=("$1")
|
|
88
|
+
shift
|
|
89
|
+
done
|
|
90
|
+
;;
|
|
81
91
|
--list)
|
|
82
92
|
LIST_ONLY=true
|
|
83
93
|
shift
|
|
@@ -98,11 +108,12 @@ if [ -z "$REPO_URL" ]; then
|
|
|
98
108
|
fi
|
|
99
109
|
|
|
100
110
|
# Default: install everything if no selective flags specified
|
|
101
|
-
if [[ "$INSTALL_PATTERNS" == false && "$INSTALL_COMMANDS" == false && "$INSTALL_DESIGNS" == false && "$INSTALL_FILES" == false ]]; then
|
|
111
|
+
if [[ "$INSTALL_PATTERNS" == false && "$INSTALL_COMMANDS" == false && "$INSTALL_DESIGNS" == false && "$INSTALL_FILES" == false && "$INSTALL_INDICES" == false ]]; then
|
|
102
112
|
INSTALL_PATTERNS=true
|
|
103
113
|
INSTALL_COMMANDS=true
|
|
104
114
|
INSTALL_DESIGNS=true
|
|
105
115
|
INSTALL_FILES=true
|
|
116
|
+
INSTALL_INDICES=true
|
|
106
117
|
fi
|
|
107
118
|
|
|
108
119
|
echo "${BLUE}📦 ACP Package Installer (Optimized)${NC}"
|
|
@@ -122,9 +133,15 @@ TEMP_DIR=$(mktemp -d)
|
|
|
122
133
|
trap "rm -rf $TEMP_DIR" EXIT
|
|
123
134
|
|
|
124
135
|
echo "Cloning repository..."
|
|
125
|
-
if
|
|
136
|
+
if [ -d "$REPO_URL" ]; then
|
|
137
|
+
# Local directory - copy contents instead of clone
|
|
138
|
+
cp -r "$REPO_URL"/* "$TEMP_DIR/" 2>/dev/null || cp -r "$REPO_URL"/.[!.]* "$TEMP_DIR/" 2>/dev/null || true
|
|
139
|
+
echo "${GREEN}✓${NC} Local directory copied"
|
|
140
|
+
elif ! git clone --depth 1 "$REPO_URL" "$TEMP_DIR" &>/dev/null; then
|
|
126
141
|
echo "${RED}Error: Failed to clone repository${NC}"
|
|
127
142
|
exit 1
|
|
143
|
+
else
|
|
144
|
+
echo "${GREEN}✓${NC} Repository cloned"
|
|
128
145
|
fi
|
|
129
146
|
|
|
130
147
|
echo "${GREEN}✓${NC} Repository cloned"
|
|
@@ -160,12 +177,6 @@ COMMIT_HASH=$(get_commit_hash "$TEMP_DIR")
|
|
|
160
177
|
info "Commit: $COMMIT_HASH"
|
|
161
178
|
echo ""
|
|
162
179
|
|
|
163
|
-
# List mode (unchanged)
|
|
164
|
-
if [ "$LIST_ONLY" = true ]; then
|
|
165
|
-
# ... (same as original)
|
|
166
|
-
exit 0
|
|
167
|
-
fi
|
|
168
|
-
|
|
169
180
|
# Validate dependencies
|
|
170
181
|
if [ -f "$TEMP_DIR/package.yaml" ]; then
|
|
171
182
|
if ! validate_project_dependencies "$TEMP_DIR/package.yaml"; then
|
|
@@ -181,6 +192,7 @@ INSTALL_DIRS=()
|
|
|
181
192
|
[ "$INSTALL_DESIGNS" = true ] && INSTALL_DIRS+=("design")
|
|
182
193
|
[ "$INSTALL_COMMANDS" = true ] && INSTALL_DIRS+=("scripts")
|
|
183
194
|
[ "$INSTALL_FILES" = true ] && INSTALL_DIRS+=("files")
|
|
195
|
+
[ "$INSTALL_INDICES" = true ] && INSTALL_DIRS+=("index")
|
|
184
196
|
|
|
185
197
|
# Mapping from dir names to manifest keys (dir → manifest key)
|
|
186
198
|
declare -A MANIFEST_KEYS=(
|
|
@@ -189,6 +201,7 @@ declare -A MANIFEST_KEYS=(
|
|
|
189
201
|
["design"]="designs"
|
|
190
202
|
["scripts"]="scripts"
|
|
191
203
|
["files"]="files"
|
|
204
|
+
["index"]="indices"
|
|
192
205
|
)
|
|
193
206
|
|
|
194
207
|
# ============================================================================
|
|
@@ -199,9 +212,18 @@ declare -A MANIFEST_KEYS=(
|
|
|
199
212
|
declare -A ALL_FILES_TO_INSTALL # Key: dir, Value: space-separated file paths
|
|
200
213
|
declare -A FILE_METADATA # Key: "dir/filename", Value: "version|experimental"
|
|
201
214
|
|
|
215
|
+
# Track installed commands for script-command binding resolution
|
|
216
|
+
INSTALLED_COMMANDS=()
|
|
217
|
+
|
|
202
218
|
INSTALLED_COUNT=0
|
|
203
219
|
SKIPPED_COUNT=0
|
|
204
220
|
|
|
221
|
+
# Template file metadata (populated during scanning when contents.files exists)
|
|
222
|
+
declare -A FILE_TARGETS # Key: "files/relpath", Value: target directory path
|
|
223
|
+
declare -A FILE_VARS # Key: "files/relpath", Value: "VAR1,VAR2,..."
|
|
224
|
+
declare -A COLLECTED_VARS # Key: "VARNAME", Value: user-provided value
|
|
225
|
+
HAS_FILE_METADATA=false
|
|
226
|
+
|
|
205
227
|
echo "Scanning for installable files..."
|
|
206
228
|
echo ""
|
|
207
229
|
|
|
@@ -226,6 +248,7 @@ for dir in "${INSTALL_DIRS[@]}"; do
|
|
|
226
248
|
design) FILE_LIST=DESIGN_FILES ;;
|
|
227
249
|
scripts) FILE_LIST=COMMAND_FILES ;;
|
|
228
250
|
files) FILE_LIST=FILE_FILES ;;
|
|
251
|
+
index) FILE_LIST=INDEX_FILES ;;
|
|
229
252
|
esac
|
|
230
253
|
|
|
231
254
|
# Collect files
|
|
@@ -242,6 +265,31 @@ for dir in "${INSTALL_DIRS[@]}"; do
|
|
|
242
265
|
file_path="$SOURCE_DIR/$file_name"
|
|
243
266
|
if [ -f "$file_path" ]; then
|
|
244
267
|
FILES_TO_PROCESS+=("$file_path")
|
|
268
|
+
|
|
269
|
+
# For selective files, also collect metadata from package.yaml
|
|
270
|
+
if [ "$dir" = "files" ] && [ -f "$TEMP_DIR/package.yaml" ]; then
|
|
271
|
+
_sel_idx=0
|
|
272
|
+
while true; do
|
|
273
|
+
_sel_name=$(yaml_query ".contents.files[$_sel_idx].name" 2>/dev/null || echo "")
|
|
274
|
+
[ -z "$_sel_name" ] || [ "$_sel_name" = "null" ] && break
|
|
275
|
+
if [ "$_sel_name" = "$file_name" ]; then
|
|
276
|
+
HAS_FILE_METADATA=true
|
|
277
|
+
_sel_target=$(yaml_query ".contents.files[$_sel_idx].target" 2>/dev/null || echo "")
|
|
278
|
+
[ -n "$_sel_target" ] && [ "$_sel_target" != "null" ] && FILE_TARGETS["files/$file_name"]="$_sel_target"
|
|
279
|
+
_sel_var_idx=0
|
|
280
|
+
_sel_vars=""
|
|
281
|
+
while true; do
|
|
282
|
+
_sel_var=$(yaml_query ".contents.files[$_sel_idx].variables[$_sel_var_idx]" 2>/dev/null || echo "")
|
|
283
|
+
[ -z "$_sel_var" ] || [ "$_sel_var" = "null" ] && break
|
|
284
|
+
[ -n "$_sel_vars" ] && _sel_vars="$_sel_vars,$_sel_var" || _sel_vars="$_sel_var"
|
|
285
|
+
_sel_var_idx=$((_sel_var_idx + 1))
|
|
286
|
+
done
|
|
287
|
+
[ -n "$_sel_vars" ] && FILE_VARS["files/$file_name"]="$_sel_vars"
|
|
288
|
+
break
|
|
289
|
+
fi
|
|
290
|
+
_sel_idx=$((_sel_idx + 1))
|
|
291
|
+
done
|
|
292
|
+
fi
|
|
245
293
|
else
|
|
246
294
|
echo "${YELLOW}⚠${NC} File not found in $dir/: $file_name"
|
|
247
295
|
SKIPPED_COUNT=$((SKIPPED_COUNT + 1))
|
|
@@ -250,14 +298,54 @@ for dir in "${INSTALL_DIRS[@]}"; do
|
|
|
250
298
|
else
|
|
251
299
|
# Install all files
|
|
252
300
|
if [ "$dir" = "files" ]; then
|
|
253
|
-
#
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
301
|
+
# Check if package.yaml has contents.files metadata
|
|
302
|
+
_first_file=$(yaml_query ".contents.files[0].name" 2>/dev/null || echo "")
|
|
303
|
+
if [ -f "$TEMP_DIR/package.yaml" ] && [ -n "$_first_file" ] && [ "$_first_file" != "null" ]; then
|
|
304
|
+
# Use package.yaml contents.files as source of truth
|
|
305
|
+
HAS_FILE_METADATA=true
|
|
306
|
+
_file_idx=0
|
|
307
|
+
while true; do
|
|
308
|
+
_fname=$(yaml_query ".contents.files[$_file_idx].name" 2>/dev/null || echo "")
|
|
309
|
+
[ -z "$_fname" ] || [ "$_fname" = "null" ] && break
|
|
310
|
+
|
|
311
|
+
if [ -f "$SOURCE_DIR/$_fname" ]; then
|
|
312
|
+
FILES_TO_PROCESS+=("$SOURCE_DIR/$_fname")
|
|
313
|
+
|
|
314
|
+
# Store target metadata
|
|
315
|
+
_target=$(yaml_query ".contents.files[$_file_idx].target" 2>/dev/null || echo "")
|
|
316
|
+
[ -n "$_target" ] && [ "$_target" != "null" ] && FILE_TARGETS["files/$_fname"]="$_target"
|
|
317
|
+
|
|
318
|
+
# Collect variable names
|
|
319
|
+
_var_idx=0
|
|
320
|
+
_vars=""
|
|
321
|
+
while true; do
|
|
322
|
+
_var=$(yaml_query ".contents.files[$_file_idx].variables[$_var_idx]" 2>/dev/null || echo "")
|
|
323
|
+
[ -z "$_var" ] || [ "$_var" = "null" ] && break
|
|
324
|
+
[ -n "$_vars" ] && _vars="$_vars,$_var" || _vars="$_var"
|
|
325
|
+
_var_idx=$((_var_idx + 1))
|
|
326
|
+
done
|
|
327
|
+
[ -n "$_vars" ] && FILE_VARS["files/$_fname"]="$_vars"
|
|
328
|
+
else
|
|
329
|
+
echo " ${YELLOW}⚠${NC} Declared in package.yaml but not found: agent/files/$_fname"
|
|
330
|
+
SKIPPED_COUNT=$((SKIPPED_COUNT + 1))
|
|
331
|
+
fi
|
|
332
|
+
|
|
333
|
+
_file_idx=$((_file_idx + 1))
|
|
334
|
+
done
|
|
335
|
+
else
|
|
336
|
+
# Fallback: recursive scan (backward compat for packages without contents.files)
|
|
337
|
+
while IFS= read -r file; do
|
|
338
|
+
[ -n "$file" ] && FILES_TO_PROCESS+=("$file")
|
|
339
|
+
done < <(find "$SOURCE_DIR" -type f)
|
|
340
|
+
fi
|
|
257
341
|
elif [ "$dir" = "scripts" ]; then
|
|
258
342
|
while IFS= read -r file; do
|
|
259
343
|
[ -n "$file" ] && FILES_TO_PROCESS+=("$file")
|
|
260
344
|
done < <(find "$SOURCE_DIR" -maxdepth 1 -name "*.sh" ! -name "*.template.sh" -type f)
|
|
345
|
+
elif [ "$dir" = "index" ]; then
|
|
346
|
+
while IFS= read -r file; do
|
|
347
|
+
[ -n "$file" ] && FILES_TO_PROCESS+=("$file")
|
|
348
|
+
done < <(find "$SOURCE_DIR" -maxdepth 1 -name "*.yaml" ! -name "*.template.yaml" -type f)
|
|
261
349
|
else
|
|
262
350
|
while IFS= read -r file; do
|
|
263
351
|
[ -n "$file" ] && FILES_TO_PROCESS+=("$file")
|
|
@@ -270,7 +358,7 @@ for dir in "${INSTALL_DIRS[@]}"; do
|
|
|
270
358
|
continue
|
|
271
359
|
fi
|
|
272
360
|
|
|
273
|
-
if [ "$dir" = "files" ]; then
|
|
361
|
+
if [ "$dir" = "files" ] && [ "$HAS_FILE_METADATA" = false ]; then
|
|
274
362
|
echo "${BLUE}📁 $dir/${NC} (${#FILES_TO_PROCESS[@]} file(s)) → installs to ./"
|
|
275
363
|
else
|
|
276
364
|
echo "${BLUE}📁 $dir/${NC} (${#FILES_TO_PROCESS[@]} file(s))"
|
|
@@ -308,10 +396,18 @@ for dir in "${INSTALL_DIRS[@]}"; do
|
|
|
308
396
|
fi
|
|
309
397
|
fi
|
|
310
398
|
|
|
311
|
-
# Check experimental status
|
|
399
|
+
# Check experimental status
|
|
312
400
|
is_experimental=""
|
|
313
|
-
if [
|
|
314
|
-
|
|
401
|
+
if [ -f "$TEMP_DIR/package.yaml" ]; then
|
|
402
|
+
if [ "$dir" = "files" ] && [ "$HAS_FILE_METADATA" = false ]; then
|
|
403
|
+
: # No per-file experimental marking without metadata
|
|
404
|
+
elif [ "$dir" = "files" ]; then
|
|
405
|
+
# Files entries have more fields (name, description, target, required, experimental)
|
|
406
|
+
# so need a wider context window (-A 6) to catch experimental: true
|
|
407
|
+
is_experimental=$(grep -A 1000 "^ ${dir}:" "$TEMP_DIR/package.yaml" 2>/dev/null | grep -A 6 "name: ${filename}" | grep "^ *experimental: true" | grep -v "^[[:space:]]*#" | head -1)
|
|
408
|
+
else
|
|
409
|
+
is_experimental=$(grep -A 1000 "^ ${dir}:" "$TEMP_DIR/package.yaml" 2>/dev/null | grep -A 2 "name: ${filename}" | grep "^ *experimental: true" | grep -v "^[[:space:]]*#" | head -1)
|
|
410
|
+
fi
|
|
315
411
|
fi
|
|
316
412
|
|
|
317
413
|
if [ -n "$is_experimental" ] && [ "$INSTALL_EXPERIMENTAL" = false ]; then
|
|
@@ -329,17 +425,30 @@ for dir in "${INSTALL_DIRS[@]}"; do
|
|
|
329
425
|
# Add to valid files
|
|
330
426
|
VALID_FILES+=("$file")
|
|
331
427
|
|
|
332
|
-
#
|
|
333
|
-
if [ "$dir" = "files" ]; then
|
|
428
|
+
# Determine target path for overwrite check
|
|
429
|
+
if [ "$dir" = "files" ] && [ "$HAS_FILE_METADATA" = true ]; then
|
|
430
|
+
_file_target="${FILE_TARGETS[files/$filename]:-./}"
|
|
431
|
+
_bname=$(basename "$filename")
|
|
432
|
+
_bname="${_bname%.template}"
|
|
433
|
+
target_path="${_file_target}${_bname}"
|
|
434
|
+
elif [ "$dir" = "files" ]; then
|
|
334
435
|
target_path="./$filename"
|
|
335
436
|
else
|
|
336
437
|
target_path="$INSTALL_BASE_DIR/$dir/$filename"
|
|
337
438
|
fi
|
|
338
439
|
|
|
440
|
+
# Build display info for files with metadata
|
|
441
|
+
_display_extra=""
|
|
442
|
+
if [ "$dir" = "files" ] && [ "$HAS_FILE_METADATA" = true ]; then
|
|
443
|
+
_file_vars="${FILE_VARS[files/$filename]:-}"
|
|
444
|
+
_display_extra=" → $target_path"
|
|
445
|
+
[ -n "$_file_vars" ] && _display_extra="$_display_extra (variables: $_file_vars)"
|
|
446
|
+
fi
|
|
447
|
+
|
|
339
448
|
if [ -f "$target_path" ]; then
|
|
340
|
-
echo " ${YELLOW}⚠${NC} $filename (will overwrite)"
|
|
449
|
+
echo " ${YELLOW}⚠${NC} $filename${_display_extra} (will overwrite)"
|
|
341
450
|
else
|
|
342
|
-
echo " ${GREEN}✓${NC} $filename"
|
|
451
|
+
echo " ${GREEN}✓${NC} $filename${_display_extra}"
|
|
343
452
|
fi
|
|
344
453
|
|
|
345
454
|
INSTALLED_COUNT=$((INSTALLED_COUNT + 1))
|
|
@@ -355,7 +464,7 @@ for dir in "${INSTALL_DIRS[@]}"; do
|
|
|
355
464
|
done
|
|
356
465
|
|
|
357
466
|
# Warn about unrecognized directories in the package
|
|
358
|
-
KNOWN_DIRS="patterns commands design scripts files"
|
|
467
|
+
KNOWN_DIRS="patterns commands design scripts files index"
|
|
359
468
|
if [ -d "$TEMP_DIR/agent" ]; then
|
|
360
469
|
UNRECOGNIZED=()
|
|
361
470
|
while IFS= read -r pkg_dir; do
|
|
@@ -386,6 +495,11 @@ echo "Ready to install $INSTALLED_COUNT file(s)"
|
|
|
386
495
|
[ $SKIPPED_COUNT -gt 0 ] && echo "($SKIPPED_COUNT file(s) will be skipped)"
|
|
387
496
|
echo ""
|
|
388
497
|
|
|
498
|
+
if [ "$LIST_ONLY" = true ]; then
|
|
499
|
+
echo "${BLUE}(dry run — no files were installed)${NC}"
|
|
500
|
+
exit 0
|
|
501
|
+
fi
|
|
502
|
+
|
|
389
503
|
if [ "$SKIP_CONFIRM" = false ]; then
|
|
390
504
|
read -p "Proceed with installation? (y/N) " -n 1 -r
|
|
391
505
|
echo
|
|
@@ -398,40 +512,243 @@ else
|
|
|
398
512
|
fi
|
|
399
513
|
|
|
400
514
|
echo ""
|
|
515
|
+
|
|
516
|
+
# Collect template variables from user (if any files have variables declared)
|
|
517
|
+
if [ ${#FILE_VARS[@]} -gt 0 ]; then
|
|
518
|
+
echo "${BLUE}Collecting template variables...${NC}"
|
|
519
|
+
|
|
520
|
+
# Build list of unique variables across all templates
|
|
521
|
+
_all_vars=""
|
|
522
|
+
for _key in "${!FILE_VARS[@]}"; do
|
|
523
|
+
IFS=',' read -ra _var_arr <<< "${FILE_VARS[$_key]}"
|
|
524
|
+
for _var in "${_var_arr[@]}"; do
|
|
525
|
+
if [[ ! ",$_all_vars," =~ ",$_var," ]]; then
|
|
526
|
+
[ -n "$_all_vars" ] && _all_vars="$_all_vars,$_var" || _all_vars="$_var"
|
|
527
|
+
fi
|
|
528
|
+
done
|
|
529
|
+
done
|
|
530
|
+
|
|
531
|
+
# Prompt for each unique variable
|
|
532
|
+
IFS=',' read -ra _unique_vars <<< "$_all_vars"
|
|
533
|
+
for _var in "${_unique_vars[@]}"; do
|
|
534
|
+
read -p " Enter $_var: " _value
|
|
535
|
+
COLLECTED_VARS["$_var"]="$_value"
|
|
536
|
+
done
|
|
537
|
+
|
|
538
|
+
echo "${GREEN}✓${NC} Variables collected"
|
|
539
|
+
echo ""
|
|
540
|
+
fi
|
|
541
|
+
|
|
401
542
|
echo "Installing files..."
|
|
402
543
|
|
|
403
544
|
# ============================================================================
|
|
404
545
|
# OPTIMIZATION: Batch file operations
|
|
405
546
|
# ============================================================================
|
|
406
547
|
|
|
548
|
+
# Check if file should be installed based on experimental status
|
|
549
|
+
should_install_file() {
|
|
550
|
+
local filename="$1"
|
|
551
|
+
local file_type="$2" # commands, patterns, designs, scripts
|
|
552
|
+
|
|
553
|
+
# If no package.yaml, install everything
|
|
554
|
+
if [ ! -f "$TEMP_DIR/package.yaml" ]; then
|
|
555
|
+
return 0
|
|
556
|
+
fi
|
|
557
|
+
|
|
558
|
+
# Check if file is marked experimental in package.yaml
|
|
559
|
+
# Extract only the relevant section, then find the specific entry
|
|
560
|
+
local section=$(grep -A 1000 "^ ${file_type}:" "$TEMP_DIR/package.yaml" 2>/dev/null | grep -B 1000 "^ [a-z]" 2>/dev/null | head -n -1 || true)
|
|
561
|
+
local is_experimental=$(echo "$section" | grep -A 3 "^ - name: ${filename}$" 2>/dev/null | grep "^ *experimental: true" 2>/dev/null | grep -v "^[[:space:]]*#" | head -1 || true)
|
|
562
|
+
|
|
563
|
+
if [ -n "$is_experimental" ]; then
|
|
564
|
+
if [ "$INSTALL_EXPERIMENTAL" = true ]; then
|
|
565
|
+
echo " ${YELLOW}⚠${NC} Installing experimental: ${filename}"
|
|
566
|
+
return 0 # Install it
|
|
567
|
+
else
|
|
568
|
+
echo " ${DIM}⊘${NC} Skipping experimental: ${filename} (use --experimental to install)"
|
|
569
|
+
return 1 # Skip it
|
|
570
|
+
fi
|
|
571
|
+
fi
|
|
572
|
+
|
|
573
|
+
return 0 # Install non-experimental files
|
|
574
|
+
}
|
|
575
|
+
|
|
407
576
|
# Add package to manifest once
|
|
408
577
|
add_package_to_manifest "$PACKAGE_NAME" "$REPO_URL" "$PACKAGE_VERSION" "$COMMIT_HASH"
|
|
409
578
|
|
|
410
|
-
# Batch copy all files
|
|
579
|
+
# Batch copy all files (skip scripts — handled via script-command binding below)
|
|
411
580
|
for dir in "${!ALL_FILES_TO_INSTALL[@]}"; do
|
|
412
581
|
SOURCE_DIR="$TEMP_DIR/agent/$dir"
|
|
413
582
|
|
|
583
|
+
# Skip scripts in first pass — install selectively after commands via script-command binding
|
|
584
|
+
if [ "$dir" = "scripts" ]; then
|
|
585
|
+
continue
|
|
586
|
+
fi
|
|
587
|
+
|
|
414
588
|
# Copy all files
|
|
415
589
|
for file in ${ALL_FILES_TO_INSTALL[$dir]}; do
|
|
416
590
|
if [ "$dir" = "files" ]; then
|
|
417
|
-
# files/ installs to project root, preserving subdirectory structure
|
|
418
591
|
rel_path="${file#$SOURCE_DIR/}"
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
592
|
+
|
|
593
|
+
if [ "$HAS_FILE_METADATA" = true ]; then
|
|
594
|
+
# Metadata-aware installation: use target path and variable substitution
|
|
595
|
+
_file_target="${FILE_TARGETS[files/$rel_path]:-./}"
|
|
596
|
+
_bname=$(basename "$rel_path")
|
|
597
|
+
_bname="${_bname%.template}"
|
|
598
|
+
_dest="${_file_target}${_bname}"
|
|
599
|
+
|
|
600
|
+
# Safety validation: reject paths that escape project root
|
|
601
|
+
if [[ "$_dest" =~ \.\. ]] || [[ "$_dest" =~ ^/ ]]; then
|
|
602
|
+
echo " ${RED}✗${NC} Skipping $rel_path (unsafe target: $_dest)"
|
|
603
|
+
continue
|
|
604
|
+
fi
|
|
605
|
+
|
|
606
|
+
mkdir -p "$(dirname "$_dest")"
|
|
607
|
+
|
|
608
|
+
# Apply variable substitution if template has variables
|
|
609
|
+
_file_vars="${FILE_VARS[files/$rel_path]:-}"
|
|
610
|
+
if [ -n "$_file_vars" ] && [ ${#COLLECTED_VARS[@]} -gt 0 ]; then
|
|
611
|
+
cp "$file" "$_dest"
|
|
612
|
+
IFS=',' read -ra _var_arr <<< "$_file_vars"
|
|
613
|
+
for _var in "${_var_arr[@]}"; do
|
|
614
|
+
_value="${COLLECTED_VARS[$_var]:-}"
|
|
615
|
+
if [ -n "$_value" ]; then
|
|
616
|
+
_escaped=$(printf '%s\n' "$_value" | sed 's/[&/\]/\\&/g')
|
|
617
|
+
_sed_i "s|{{${_var}}}|${_escaped}|g" "$_dest"
|
|
618
|
+
fi
|
|
619
|
+
done
|
|
620
|
+
else
|
|
621
|
+
cp "$file" "$_dest"
|
|
622
|
+
fi
|
|
623
|
+
else
|
|
624
|
+
# Backward compat: install to project root preserving subdirectory structure
|
|
625
|
+
target_dir="$(dirname "./$rel_path")"
|
|
626
|
+
mkdir -p "$target_dir"
|
|
627
|
+
cp "$file" "./$rel_path"
|
|
628
|
+
fi
|
|
422
629
|
else
|
|
423
630
|
mkdir -p "$INSTALL_BASE_DIR/$dir"
|
|
424
631
|
filename=$(basename "$file")
|
|
425
632
|
cp "$file" "$INSTALL_BASE_DIR/$dir/$filename"
|
|
633
|
+
fi
|
|
426
634
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
635
|
+
# Track installed commands for script dependency resolution
|
|
636
|
+
if [ "$dir" = "commands" ]; then
|
|
637
|
+
filename=$(basename "$file")
|
|
638
|
+
INSTALLED_COMMANDS+=("$filename")
|
|
431
639
|
fi
|
|
432
640
|
done
|
|
433
641
|
done
|
|
434
642
|
|
|
643
|
+
# ============================================================================
|
|
644
|
+
# Script-Command Binding: Install scripts based on command dependencies
|
|
645
|
+
# ============================================================================
|
|
646
|
+
|
|
647
|
+
if [ -f "$TEMP_DIR/package.yaml" ] && [ ${#INSTALLED_COMMANDS[@]} -gt 0 ]; then
|
|
648
|
+
echo "Resolving script dependencies..."
|
|
649
|
+
echo " Installed commands: ${INSTALLED_COMMANDS[@]}"
|
|
650
|
+
|
|
651
|
+
# Collect required scripts from installed commands using YAML parser
|
|
652
|
+
REQUIRED_SCRIPTS=()
|
|
653
|
+
for cmd in "${INSTALLED_COMMANDS[@]}"; do
|
|
654
|
+
# Find the command index in the array
|
|
655
|
+
cmd_index=0
|
|
656
|
+
while true; do
|
|
657
|
+
cmd_name=$(yaml_get_nested "$TEMP_DIR/package.yaml" "contents.commands[$cmd_index].name" 2>/dev/null || echo "")
|
|
658
|
+
if [ -z "$cmd_name" ] || [ "$cmd_name" = "null" ]; then
|
|
659
|
+
break
|
|
660
|
+
fi
|
|
661
|
+
|
|
662
|
+
if [ "$cmd_name" = "$cmd" ]; then
|
|
663
|
+
# Found the command, now get its scripts
|
|
664
|
+
script_index=0
|
|
665
|
+
while true; do
|
|
666
|
+
script=$(yaml_get_nested "$TEMP_DIR/package.yaml" "contents.commands[$cmd_index].scripts[$script_index]" 2>/dev/null || echo "")
|
|
667
|
+
if [ -z "$script" ] || [ "$script" = "null" ]; then
|
|
668
|
+
break
|
|
669
|
+
fi
|
|
670
|
+
|
|
671
|
+
# Add to required scripts (with deduplication)
|
|
672
|
+
already_added=false
|
|
673
|
+
for existing in "${REQUIRED_SCRIPTS[@]}"; do
|
|
674
|
+
if [ "$existing" = "$script" ]; then
|
|
675
|
+
already_added=true
|
|
676
|
+
break
|
|
677
|
+
fi
|
|
678
|
+
done
|
|
679
|
+
|
|
680
|
+
if [ "$already_added" = false ]; then
|
|
681
|
+
REQUIRED_SCRIPTS+=("$script")
|
|
682
|
+
fi
|
|
683
|
+
|
|
684
|
+
script_index=$((script_index + 1))
|
|
685
|
+
done
|
|
686
|
+
break
|
|
687
|
+
fi
|
|
688
|
+
|
|
689
|
+
cmd_index=$((cmd_index + 1))
|
|
690
|
+
done
|
|
691
|
+
done
|
|
692
|
+
|
|
693
|
+
echo " Found ${#REQUIRED_SCRIPTS[@]} required script(s): ${REQUIRED_SCRIPTS[@]}"
|
|
694
|
+
|
|
695
|
+
# Install required scripts and add to ALL_FILES_TO_INSTALL for batch manifest update
|
|
696
|
+
SCRIPT_FILES_LIST=""
|
|
697
|
+
if [ ${#REQUIRED_SCRIPTS[@]} -gt 0 ]; then
|
|
698
|
+
mkdir -p "$INSTALL_BASE_DIR/scripts"
|
|
699
|
+
for script in "${REQUIRED_SCRIPTS[@]}"; do
|
|
700
|
+
script_path="$TEMP_DIR/agent/scripts/$script"
|
|
701
|
+
|
|
702
|
+
# Check if script exists
|
|
703
|
+
if [ ! -f "$script_path" ]; then
|
|
704
|
+
echo " ${RED}✗${NC} Script not found: $script (declared in package.yaml)"
|
|
705
|
+
continue
|
|
706
|
+
fi
|
|
707
|
+
|
|
708
|
+
# Check if should install based on experimental status
|
|
709
|
+
if ! should_install_file "$script" "scripts"; then
|
|
710
|
+
continue
|
|
711
|
+
fi
|
|
712
|
+
|
|
713
|
+
# Copy script and make executable
|
|
714
|
+
cp "$script_path" "$INSTALL_BASE_DIR/scripts/$script"
|
|
715
|
+
chmod +x "$INSTALL_BASE_DIR/scripts/$script"
|
|
716
|
+
|
|
717
|
+
# Get file version and store metadata
|
|
718
|
+
FILE_VERSION=$(get_file_version "$TEMP_DIR/package.yaml" "scripts" "$script")
|
|
719
|
+
|
|
720
|
+
# Check experimental status
|
|
721
|
+
is_experimental=""
|
|
722
|
+
if [ -f "$TEMP_DIR/package.yaml" ]; then
|
|
723
|
+
is_experimental=$(grep -A 1000 "^ scripts:" "$TEMP_DIR/package.yaml" 2>/dev/null | grep -A 2 "name: ${script}" | grep "^ *experimental: true" | grep -v "^[[:space:]]*#" | head -1)
|
|
724
|
+
fi
|
|
725
|
+
FILE_METADATA["scripts/$script"]="$FILE_VERSION|$is_experimental"
|
|
726
|
+
|
|
727
|
+
# Track for batch processing
|
|
728
|
+
if [ -n "$SCRIPT_FILES_LIST" ]; then
|
|
729
|
+
SCRIPT_FILES_LIST="$SCRIPT_FILES_LIST $script_path"
|
|
730
|
+
else
|
|
731
|
+
SCRIPT_FILES_LIST="$script_path"
|
|
732
|
+
fi
|
|
733
|
+
done
|
|
734
|
+
fi
|
|
735
|
+
|
|
736
|
+
# Update ALL_FILES_TO_INSTALL with resolved scripts
|
|
737
|
+
if [ -n "$SCRIPT_FILES_LIST" ]; then
|
|
738
|
+
ALL_FILES_TO_INSTALL["scripts"]="$SCRIPT_FILES_LIST"
|
|
739
|
+
fi
|
|
740
|
+
echo ""
|
|
741
|
+
elif [ -d "$TEMP_DIR/agent/scripts" ] && [ -n "${ALL_FILES_TO_INSTALL[scripts]+x}" ]; then
|
|
742
|
+
# Scripts were collected during scan but no package.yaml script-command binding
|
|
743
|
+
# Install all scripts that passed validation (backward compatibility)
|
|
744
|
+
for file in ${ALL_FILES_TO_INSTALL[scripts]}; do
|
|
745
|
+
filename=$(basename "$file")
|
|
746
|
+
mkdir -p "$INSTALL_BASE_DIR/scripts"
|
|
747
|
+
cp "$file" "$INSTALL_BASE_DIR/scripts/$filename"
|
|
748
|
+
chmod +x "$INSTALL_BASE_DIR/scripts/$filename"
|
|
749
|
+
done
|
|
750
|
+
fi
|
|
751
|
+
|
|
435
752
|
# ============================================================================
|
|
436
753
|
# OPTIMIZATION: Batch checksum calculation
|
|
437
754
|
# ============================================================================
|
|
@@ -445,7 +762,14 @@ for dir in "${!ALL_FILES_TO_INSTALL[@]}"; do
|
|
|
445
762
|
for file in ${ALL_FILES_TO_INSTALL[$dir]}; do
|
|
446
763
|
if [ "$dir" = "files" ]; then
|
|
447
764
|
rel_path="${file#$SOURCE_DIR/}"
|
|
448
|
-
|
|
765
|
+
if [ "$HAS_FILE_METADATA" = true ]; then
|
|
766
|
+
_file_target="${FILE_TARGETS[files/$rel_path]:-./}"
|
|
767
|
+
_bname=$(basename "$rel_path")
|
|
768
|
+
_bname="${_bname%.template}"
|
|
769
|
+
ALL_INSTALLED_FILES+=("${_file_target}${_bname}")
|
|
770
|
+
else
|
|
771
|
+
ALL_INSTALLED_FILES+=("./$rel_path")
|
|
772
|
+
fi
|
|
449
773
|
else
|
|
450
774
|
filename=$(basename "$file")
|
|
451
775
|
ALL_INSTALLED_FILES+=("$INSTALL_BASE_DIR/$dir/$filename")
|
|
@@ -460,7 +784,7 @@ if [ ${#ALL_INSTALLED_FILES[@]} -gt 0 ]; then
|
|
|
460
784
|
checksum=$(echo "$line" | awk '{print $1}')
|
|
461
785
|
filepath=$(echo "$line" | awk '{$1=""; print substr($0,2)}')
|
|
462
786
|
CHECKSUMS["$filepath"]="$checksum"
|
|
463
|
-
done < <(sha256sum "${ALL_INSTALLED_FILES[@]}" 2>/dev/null)
|
|
787
|
+
done < <(if command -v sha256sum >/dev/null 2>&1; then sha256sum "${ALL_INSTALLED_FILES[@]}" 2>/dev/null; elif command -v shasum >/dev/null 2>&1; then shasum -a 256 "${ALL_INSTALLED_FILES[@]}" 2>/dev/null; fi)
|
|
464
788
|
fi
|
|
465
789
|
|
|
466
790
|
# ============================================================================
|
|
@@ -482,7 +806,14 @@ for dir in "${!ALL_FILES_TO_INSTALL[@]}"; do
|
|
|
482
806
|
# Determine filename and installed filepath based on dir type
|
|
483
807
|
if [ "$dir" = "files" ]; then
|
|
484
808
|
filename="${file#$SOURCE_DIR/}"
|
|
485
|
-
|
|
809
|
+
if [ "$HAS_FILE_METADATA" = true ]; then
|
|
810
|
+
_file_target="${FILE_TARGETS[files/$filename]:-./}"
|
|
811
|
+
_bname=$(basename "$filename")
|
|
812
|
+
_bname="${_bname%.template}"
|
|
813
|
+
filepath="${_file_target}${_bname}"
|
|
814
|
+
else
|
|
815
|
+
filepath="./$filename"
|
|
816
|
+
fi
|
|
486
817
|
else
|
|
487
818
|
filename=$(basename "$file")
|
|
488
819
|
filepath="$INSTALL_BASE_DIR/$dir/$filename"
|
|
@@ -506,10 +837,29 @@ for dir in "${!ALL_FILES_TO_INSTALL[@]}"; do
|
|
|
506
837
|
yaml_object_set "$obj_node" "experimental" "true" >/dev/null
|
|
507
838
|
fi
|
|
508
839
|
|
|
840
|
+
# For files with metadata: store target path and variables
|
|
841
|
+
if [ "$dir" = "files" ] && [ "$HAS_FILE_METADATA" = true ]; then
|
|
842
|
+
yaml_object_set "$obj_node" "target" "$filepath" >/dev/null
|
|
843
|
+
# Store variable values if this file had variables
|
|
844
|
+
_file_vars_manifest="${FILE_VARS[files/$filename]:-}"
|
|
845
|
+
if [ -n "$_file_vars_manifest" ]; then
|
|
846
|
+
# Create nested map node for variables
|
|
847
|
+
_vars_node=$(create_node "map" "variables" "" "$obj_node")
|
|
848
|
+
add_child "$obj_node" "$_vars_node"
|
|
849
|
+
IFS=',' read -ra _var_names <<< "$_file_vars_manifest"
|
|
850
|
+
for _vname in "${_var_names[@]}"; do
|
|
851
|
+
_vval="${COLLECTED_VARS[$_vname]:-}"
|
|
852
|
+
if [ -n "$_vval" ]; then
|
|
853
|
+
yaml_object_set "$_vars_node" "$_vname" "$_vval" >/dev/null
|
|
854
|
+
fi
|
|
855
|
+
done
|
|
856
|
+
fi
|
|
857
|
+
fi
|
|
858
|
+
|
|
509
859
|
if [ "$dir" = "scripts" ]; then
|
|
510
860
|
echo " ${GREEN}✓${NC} Installed $dir/$filename (v$file_version) [executable]"
|
|
511
861
|
elif [ "$dir" = "files" ]; then
|
|
512
|
-
echo " ${GREEN}✓${NC} Installed $filename →
|
|
862
|
+
echo " ${GREEN}✓${NC} Installed $filename → $filepath"
|
|
513
863
|
else
|
|
514
864
|
echo " ${GREEN}✓${NC} Installed $dir/$filename (v$file_version)"
|
|
515
865
|
fi
|