@prmichaelsen/acp-visualizer 0.1.0

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.
Files changed (180) hide show
  1. package/README.md +68 -0
  2. package/agent/commands/acp.clarification-address.md +417 -0
  3. package/agent/commands/acp.clarification-capture.md +386 -0
  4. package/agent/commands/acp.clarification-create.md +437 -0
  5. package/agent/commands/acp.clarifications-research.md +326 -0
  6. package/agent/commands/acp.command-create.md +432 -0
  7. package/agent/commands/acp.design-create.md +286 -0
  8. package/agent/commands/acp.design-reference.md +355 -0
  9. package/agent/commands/acp.handoff.md +270 -0
  10. package/agent/commands/acp.index.md +423 -0
  11. package/agent/commands/acp.init.md +546 -0
  12. package/agent/commands/acp.package-create.md +895 -0
  13. package/agent/commands/acp.package-info.md +212 -0
  14. package/agent/commands/acp.package-install.md +539 -0
  15. package/agent/commands/acp.package-list.md +280 -0
  16. package/agent/commands/acp.package-publish.md +541 -0
  17. package/agent/commands/acp.package-remove.md +293 -0
  18. package/agent/commands/acp.package-search.md +307 -0
  19. package/agent/commands/acp.package-update.md +361 -0
  20. package/agent/commands/acp.package-validate.md +540 -0
  21. package/agent/commands/acp.pattern-create.md +386 -0
  22. package/agent/commands/acp.plan.md +587 -0
  23. package/agent/commands/acp.proceed.md +882 -0
  24. package/agent/commands/acp.project-create.md +675 -0
  25. package/agent/commands/acp.project-info.md +312 -0
  26. package/agent/commands/acp.project-list.md +226 -0
  27. package/agent/commands/acp.project-remove.md +379 -0
  28. package/agent/commands/acp.project-set.md +227 -0
  29. package/agent/commands/acp.project-update.md +307 -0
  30. package/agent/commands/acp.projects-restore.md +228 -0
  31. package/agent/commands/acp.projects-sync.md +347 -0
  32. package/agent/commands/acp.report.md +407 -0
  33. package/agent/commands/acp.resume.md +239 -0
  34. package/agent/commands/acp.sessions.md +301 -0
  35. package/agent/commands/acp.status.md +293 -0
  36. package/agent/commands/acp.sync.md +364 -0
  37. package/agent/commands/acp.task-create.md +500 -0
  38. package/agent/commands/acp.update.md +302 -0
  39. package/agent/commands/acp.validate.md +466 -0
  40. package/agent/commands/acp.version-check-for-updates.md +276 -0
  41. package/agent/commands/acp.version-check.md +191 -0
  42. package/agent/commands/acp.version-update.md +289 -0
  43. package/agent/commands/command.template.md +339 -0
  44. package/agent/commands/git.commit.md +526 -0
  45. package/agent/commands/git.init.md +514 -0
  46. package/agent/commands/tanstack-cloudflare.deploy.md +272 -0
  47. package/agent/commands/tanstack-cloudflare.tail.md +275 -0
  48. package/agent/design/.gitkeep +0 -0
  49. package/agent/design/design.template.md +154 -0
  50. package/agent/design/local.dashboard-layout-routing.md +288 -0
  51. package/agent/design/local.data-model-yaml-parsing.md +310 -0
  52. package/agent/design/local.search-filtering.md +331 -0
  53. package/agent/design/local.server-api-auto-refresh.md +235 -0
  54. package/agent/design/local.table-tree-views.md +299 -0
  55. package/agent/design/local.visualizer-requirements.md +349 -0
  56. package/agent/design/requirements.template.md +387 -0
  57. package/agent/index/.gitkeep +0 -0
  58. package/agent/index/acp.core.yaml +137 -0
  59. package/agent/index/local.main.template.yaml +37 -0
  60. package/agent/manifest.template.yaml +13 -0
  61. package/agent/manifest.yaml +302 -0
  62. package/agent/milestones/.gitkeep +0 -0
  63. package/agent/milestones/milestone-1-project-scaffold-data-pipeline.md +67 -0
  64. package/agent/milestones/milestone-1-{title}.template.md +206 -0
  65. package/agent/milestones/milestone-2-dashboard-views-interaction.md +79 -0
  66. package/agent/package.template.yaml +86 -0
  67. package/agent/patterns/.gitkeep +0 -0
  68. package/agent/patterns/bootstrap.template.md +1237 -0
  69. package/agent/patterns/pattern.template.md +382 -0
  70. package/agent/patterns/tanstack-cloudflare.acl-permissions.md +332 -0
  71. package/agent/patterns/tanstack-cloudflare.action-bar-item.md +416 -0
  72. package/agent/patterns/tanstack-cloudflare.api-route-handlers.md +401 -0
  73. package/agent/patterns/tanstack-cloudflare.auth-session-management.md +387 -0
  74. package/agent/patterns/tanstack-cloudflare.card-and-list.md +271 -0
  75. package/agent/patterns/tanstack-cloudflare.chat-engine.md +353 -0
  76. package/agent/patterns/tanstack-cloudflare.confirmation-tokens.md +346 -0
  77. package/agent/patterns/tanstack-cloudflare.durable-objects-websocket.md +516 -0
  78. package/agent/patterns/tanstack-cloudflare.email-service.md +431 -0
  79. package/agent/patterns/tanstack-cloudflare.expander.md +98 -0
  80. package/agent/patterns/tanstack-cloudflare.fcm-push.md +115 -0
  81. package/agent/patterns/tanstack-cloudflare.firebase-anonymous-sessions.md +441 -0
  82. package/agent/patterns/tanstack-cloudflare.firebase-auth.md +348 -0
  83. package/agent/patterns/tanstack-cloudflare.firebase-firestore.md +550 -0
  84. package/agent/patterns/tanstack-cloudflare.firebase-storage.md +369 -0
  85. package/agent/patterns/tanstack-cloudflare.form-controls.md +145 -0
  86. package/agent/patterns/tanstack-cloudflare.global-search-context.md +93 -0
  87. package/agent/patterns/tanstack-cloudflare.image-carousel.md +126 -0
  88. package/agent/patterns/tanstack-cloudflare.library-services.md +553 -0
  89. package/agent/patterns/tanstack-cloudflare.lightbox.md +169 -0
  90. package/agent/patterns/tanstack-cloudflare.markdown-content.md +115 -0
  91. package/agent/patterns/tanstack-cloudflare.mention-suggestions.md +98 -0
  92. package/agent/patterns/tanstack-cloudflare.modal.md +156 -0
  93. package/agent/patterns/tanstack-cloudflare.nextjs-to-tanstack-routing.md +461 -0
  94. package/agent/patterns/tanstack-cloudflare.notifications-engine.md +151 -0
  95. package/agent/patterns/tanstack-cloudflare.oauth-token-refresh.md +90 -0
  96. package/agent/patterns/tanstack-cloudflare.og-metadata.md +296 -0
  97. package/agent/patterns/tanstack-cloudflare.pagination.md +442 -0
  98. package/agent/patterns/tanstack-cloudflare.pill-input.md +220 -0
  99. package/agent/patterns/tanstack-cloudflare.provider-adapter.md +401 -0
  100. package/agent/patterns/tanstack-cloudflare.rate-limiting.md +323 -0
  101. package/agent/patterns/tanstack-cloudflare.scheduled-tasks.md +338 -0
  102. package/agent/patterns/tanstack-cloudflare.searchable-settings.md +375 -0
  103. package/agent/patterns/tanstack-cloudflare.slide-over.md +129 -0
  104. package/agent/patterns/tanstack-cloudflare.ssr-preload.md +571 -0
  105. package/agent/patterns/tanstack-cloudflare.third-party-api-integration.md +508 -0
  106. package/agent/patterns/tanstack-cloudflare.toast-system.md +142 -0
  107. package/agent/patterns/tanstack-cloudflare.unified-header.md +280 -0
  108. package/agent/patterns/tanstack-cloudflare.user-scoped-collections.md +628 -0
  109. package/agent/patterns/tanstack-cloudflare.websocket-manager.md +237 -0
  110. package/agent/patterns/tanstack-cloudflare.wrangler-configuration.md +358 -0
  111. package/agent/patterns/tanstack-cloudflare.zod-schema-validation.md +336 -0
  112. package/agent/progress.template.yaml +161 -0
  113. package/agent/progress.yaml +145 -0
  114. package/agent/schemas/package.schema.yaml +276 -0
  115. package/agent/scripts/acp.common.sh +1781 -0
  116. package/agent/scripts/acp.install.sh +333 -0
  117. package/agent/scripts/acp.package-create.sh +924 -0
  118. package/agent/scripts/acp.package-info.sh +288 -0
  119. package/agent/scripts/acp.package-install.sh +893 -0
  120. package/agent/scripts/acp.package-list.sh +311 -0
  121. package/agent/scripts/acp.package-publish.sh +420 -0
  122. package/agent/scripts/acp.package-remove.sh +348 -0
  123. package/agent/scripts/acp.package-search.sh +156 -0
  124. package/agent/scripts/acp.package-update.sh +517 -0
  125. package/agent/scripts/acp.package-validate.sh +1018 -0
  126. package/agent/scripts/acp.uninstall.sh +85 -0
  127. package/agent/scripts/acp.version-check-for-updates.sh +98 -0
  128. package/agent/scripts/acp.version-check.sh +47 -0
  129. package/agent/scripts/acp.version-update.sh +176 -0
  130. package/agent/scripts/acp.yaml-parser.sh +985 -0
  131. package/agent/scripts/acp.yaml-validate.sh +205 -0
  132. package/agent/tasks/.gitkeep +0 -0
  133. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-1-initialize-tanstack-start-project.md +210 -0
  134. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-2-implement-data-model-yaml-parser.md +294 -0
  135. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-3-build-server-api-data-loading.md +193 -0
  136. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-4-add-auto-refresh-sse.md +262 -0
  137. package/agent/tasks/milestone-2-dashboard-views-interaction/task-10-polish-integration-testing.md +156 -0
  138. package/agent/tasks/milestone-2-dashboard-views-interaction/task-5-build-dashboard-layout-routing.md +178 -0
  139. package/agent/tasks/milestone-2-dashboard-views-interaction/task-6-build-overview-page.md +141 -0
  140. package/agent/tasks/milestone-2-dashboard-views-interaction/task-7-implement-milestone-table-view.md +153 -0
  141. package/agent/tasks/milestone-2-dashboard-views-interaction/task-8-implement-milestone-tree-view.md +174 -0
  142. package/agent/tasks/milestone-2-dashboard-views-interaction/task-9-implement-search-filtering.md +233 -0
  143. package/agent/tasks/task-1-{title}.template.md +244 -0
  144. package/bin/visualize.mjs +84 -0
  145. package/package.json +48 -0
  146. package/src/components/ExtraFieldsBadge.tsx +15 -0
  147. package/src/components/FilterBar.tsx +33 -0
  148. package/src/components/Header.tsx +23 -0
  149. package/src/components/MilestoneTable.tsx +167 -0
  150. package/src/components/MilestoneTree.tsx +84 -0
  151. package/src/components/ProgressBar.tsx +20 -0
  152. package/src/components/SearchInput.tsx +22 -0
  153. package/src/components/Sidebar.tsx +54 -0
  154. package/src/components/StatusBadge.tsx +23 -0
  155. package/src/components/StatusDot.tsx +12 -0
  156. package/src/components/TaskList.tsx +36 -0
  157. package/src/components/ViewToggle.tsx +31 -0
  158. package/src/lib/config.ts +8 -0
  159. package/src/lib/file-watcher.ts +43 -0
  160. package/src/lib/search.ts +48 -0
  161. package/src/lib/types.ts +73 -0
  162. package/src/lib/useAutoRefresh.ts +31 -0
  163. package/src/lib/useCollapse.ts +31 -0
  164. package/src/lib/useFilteredData.ts +55 -0
  165. package/src/lib/yaml-loader-real.spec.ts +47 -0
  166. package/src/lib/yaml-loader.spec.ts +201 -0
  167. package/src/lib/yaml-loader.ts +265 -0
  168. package/src/routeTree.gen.ts +140 -0
  169. package/src/router.tsx +10 -0
  170. package/src/routes/__root.tsx +75 -0
  171. package/src/routes/api/watch.ts +29 -0
  172. package/src/routes/index.tsx +115 -0
  173. package/src/routes/milestones.tsx +50 -0
  174. package/src/routes/search.tsx +84 -0
  175. package/src/routes/tasks.tsx +63 -0
  176. package/src/services/progress-database.service.ts +46 -0
  177. package/src/styles.css +25 -0
  178. package/tsconfig.json +24 -0
  179. package/vite.config.ts +16 -0
  180. package/vitest.config.ts +27 -0
@@ -0,0 +1,1018 @@
1
+ #!/bin/bash
2
+ # ACP Package Validation Script
3
+ # Comprehensive package validation with shell-based checks
4
+ # Version: 1.0.0
5
+
6
+ set -e
7
+
8
+ # Source common utilities
9
+ SCRIPT_DIR="$(dirname "$0")"
10
+ . "${SCRIPT_DIR}/acp.common.sh"
11
+ . "${SCRIPT_DIR}/acp.yaml-parser.sh"
12
+
13
+ # Initialize colors
14
+ init_colors
15
+
16
+ # Validation tracking
17
+ TOTAL_CHECKS=0
18
+ PASSED_CHECKS=0
19
+ ERRORS=()
20
+ WARNINGS=()
21
+ FIXABLE_ISSUES=()
22
+
23
+ # Add check result
24
+ check() {
25
+ TOTAL_CHECKS=$((TOTAL_CHECKS + 1))
26
+ }
27
+
28
+ # Add passed check
29
+ pass() {
30
+ PASSED_CHECKS=$((PASSED_CHECKS + 1))
31
+ echo " ${GREEN}✓${NC} $1"
32
+ }
33
+
34
+ # Add error
35
+ error() {
36
+ echo " ${RED}❌${NC} $1" >&2
37
+ ERRORS+=("$1")
38
+ }
39
+
40
+ # Add warning
41
+ warning() {
42
+ echo " ${YELLOW}⚠️${NC} $1"
43
+ WARNINGS+=("$1")
44
+ }
45
+
46
+ # Add fixable issue
47
+ fixable() {
48
+ FIXABLE_ISSUES+=("$1")
49
+ }
50
+
51
+ # Check if we're in a package directory
52
+ check_package_context() {
53
+ echo "${BLUE}📦 Checking Package Context${NC}"
54
+ echo ""
55
+
56
+ check
57
+ if [ ! -f "package.yaml" ]; then
58
+ error "Not a package directory: package.yaml not found"
59
+ echo ""
60
+ echo "${RED}This command must be run from an ACP package directory.${NC}"
61
+ echo "To create a package, use: @acp.package-create"
62
+ exit 1
63
+ fi
64
+ pass "package.yaml found"
65
+
66
+ # Extract package name and version
67
+ PACKAGE_NAME=$(yaml_get "package.yaml" "name" 2>/dev/null || echo "unknown")
68
+ PACKAGE_VERSION=$(yaml_get "package.yaml" "version" 2>/dev/null || echo "unknown")
69
+
70
+ echo ""
71
+ echo "${BOLD}Package: ${PACKAGE_NAME} (v${PACKAGE_VERSION})${NC}"
72
+ echo ""
73
+ }
74
+
75
+ # Validate YAML structure
76
+ validate_yaml_structure() {
77
+ echo "${BLUE}🔧 Shell Validation${NC}"
78
+ echo ""
79
+ echo "${BOLD}YAML Structure${NC}"
80
+
81
+ # Run YAML schema validator
82
+ check
83
+ if "${SCRIPT_DIR}/acp.yaml-validate.sh" "package.yaml" >/dev/null 2>&1; then
84
+ pass "package.yaml is valid YAML"
85
+ pass "All required fields present"
86
+ pass "Version format valid ($PACKAGE_VERSION)"
87
+
88
+ # Check repository URL
89
+ local repo_url=$(yaml_get "package.yaml" "repository" 2>/dev/null)
90
+ if [ -n "$repo_url" ]; then
91
+ pass "Repository URL valid"
92
+ fi
93
+
94
+ # Check reserved names
95
+ case "$PACKAGE_NAME" in
96
+ acp|local|core|system|global)
97
+ error "Package name '$PACKAGE_NAME' is reserved"
98
+ ;;
99
+ *)
100
+ pass "No reserved names used"
101
+ ;;
102
+ esac
103
+ else
104
+ error "package.yaml validation failed"
105
+ echo ""
106
+ echo "Running detailed validation:"
107
+ "${SCRIPT_DIR}/acp.yaml-validate.sh" "package.yaml"
108
+ fixable "Fix package.yaml structure"
109
+ fi
110
+
111
+ echo ""
112
+ }
113
+
114
+ # Validate file existence
115
+ validate_file_existence() {
116
+ echo "${BOLD}File Existence${NC}"
117
+
118
+ local total_files=0
119
+ local missing_files=0
120
+
121
+ # Check patterns
122
+ if yaml_has_key "package.yaml" "contents.patterns"; then
123
+ local pattern_count=$(yaml_get_array "package.yaml" "contents.patterns")
124
+ for i in $(seq 0 $((pattern_count - 1))); do
125
+ local pattern_name=$(yaml_get_nested "package.yaml" "contents.patterns[$i].name")
126
+ if [ -n "$pattern_name" ]; then
127
+ total_files=$((total_files + 1))
128
+ check
129
+ if [ -f "agent/patterns/$pattern_name" ]; then
130
+ pass "agent/patterns/$pattern_name ✓"
131
+ else
132
+ error "Missing file: agent/patterns/$pattern_name"
133
+ missing_files=$((missing_files + 1))
134
+ fi
135
+ fi
136
+ done
137
+ fi
138
+
139
+ # Check commands
140
+ if yaml_has_key "package.yaml" "contents.commands"; then
141
+ local command_count=$(yaml_get_array "package.yaml" "contents.commands")
142
+ for i in $(seq 0 $((command_count - 1))); do
143
+ local command_name=$(yaml_get_nested "package.yaml" "contents.commands[$i].name")
144
+ if [ -n "$command_name" ]; then
145
+ total_files=$((total_files + 1))
146
+ check
147
+ if [ -f "agent/commands/$command_name" ]; then
148
+ pass "agent/commands/$command_name ✓"
149
+ else
150
+ error "Missing file: agent/commands/$command_name"
151
+ missing_files=$((missing_files + 1))
152
+ fi
153
+ fi
154
+ done
155
+ fi
156
+
157
+ # Check designs
158
+ if yaml_has_key "package.yaml" "contents.designs"; then
159
+ local design_count=$(yaml_get_array "package.yaml" "contents.designs")
160
+ for i in $(seq 0 $((design_count - 1))); do
161
+ local design_name=$(yaml_get_nested "package.yaml" "contents.designs[$i].name")
162
+ if [ -n "$design_name" ]; then
163
+ total_files=$((total_files + 1))
164
+ check
165
+ if [ -f "agent/design/$design_name" ]; then
166
+ pass "agent/design/$design_name ✓"
167
+ else
168
+ error "Missing file: agent/design/$design_name"
169
+ missing_files=$((missing_files + 1))
170
+ fi
171
+ fi
172
+ done
173
+ fi
174
+
175
+ # Check indices (key file index files in agent/index/)
176
+ if yaml_has_key "package.yaml" "contents.indices"; then
177
+ local indices_count=$(yaml_get_array "package.yaml" "contents.indices")
178
+ for i in $(seq 0 $((indices_count - 1))); do
179
+ local index_name=$(yaml_get_nested "package.yaml" "contents.indices[$i].name")
180
+ if [ -n "$index_name" ]; then
181
+ total_files=$((total_files + 1))
182
+ check
183
+ if [ -f "agent/index/$index_name" ]; then
184
+ pass "agent/index/$index_name ✓"
185
+ else
186
+ error "Missing file: agent/index/$index_name"
187
+ missing_files=$((missing_files + 1))
188
+ fi
189
+ fi
190
+ done
191
+ fi
192
+
193
+ # Check files (template source files in agent/files/)
194
+ if yaml_has_key "package.yaml" "contents.files"; then
195
+ local files_count=$(yaml_get_array "package.yaml" "contents.files")
196
+ for i in $(seq 0 $((files_count - 1))); do
197
+ local file_name=$(yaml_get_nested "package.yaml" "contents.files[$i].name")
198
+ if [ -n "$file_name" ]; then
199
+ total_files=$((total_files + 1))
200
+ check
201
+ if [ -f "agent/files/$file_name" ]; then
202
+ pass "agent/files/$file_name ✓"
203
+ else
204
+ error "Missing file: agent/files/$file_name"
205
+ missing_files=$((missing_files + 1))
206
+ fi
207
+ fi
208
+ done
209
+ fi
210
+
211
+ if [ "$missing_files" -eq 0 ]; then
212
+ pass "All $total_files files in contents exist"
213
+ else
214
+ error "$missing_files of $total_files files missing"
215
+ fixable "Remove missing files from package.yaml"
216
+ fi
217
+
218
+ echo ""
219
+ }
220
+
221
+ # Check for unlisted files
222
+ check_unlisted_files() {
223
+ echo "${BOLD}Unlisted Files${NC}"
224
+
225
+ local unlisted=0
226
+
227
+ # Get files from manifest (all packages including acp-core)
228
+ # Use simple grep to extract all "- name: filename" entries
229
+ local manifest_files=""
230
+ if [ -f "agent/manifest.yaml" ]; then
231
+ manifest_files=$(grep -E "^[[:space:]]+-[[:space:]]+name:" agent/manifest.yaml | sed 's/.*name:[[:space:]]*//' || echo "")
232
+ fi
233
+
234
+ # Check patterns directory
235
+ if [ -d "agent/patterns" ]; then
236
+ for file in agent/patterns/*.md; do
237
+ [ -f "$file" ] || continue
238
+ local basename=$(basename "$file")
239
+
240
+ # Skip templates
241
+ [[ "$basename" == *.template.md ]] && continue
242
+ [[ "$basename" == ".gitkeep" ]] && continue
243
+
244
+ # Skip if in manifest (installed from another package)
245
+ if echo "$manifest_files" | grep -q "^${basename}$"; then
246
+ continue
247
+ fi
248
+
249
+ # Check if listed in package.yaml
250
+ if ! grep -q "name: $basename" package.yaml 2>/dev/null; then
251
+ warning "Found unlisted file: patterns/$basename"
252
+ fixable "Add patterns/$basename to package.yaml"
253
+ unlisted=$((unlisted + 1))
254
+ fi
255
+ done
256
+ fi
257
+
258
+ # Check commands directory
259
+ if [ -d "agent/commands" ]; then
260
+ for file in agent/commands/*.md; do
261
+ [ -f "$file" ] || continue
262
+ local basename=$(basename "$file")
263
+
264
+ # Skip templates
265
+ [[ "$basename" == *.template.md ]] && continue
266
+
267
+ # Skip if in manifest (installed from another package, including acp-core)
268
+ if echo "$manifest_files" | grep -q "^${basename}$"; then
269
+ continue
270
+ fi
271
+
272
+ # Check if listed in package.yaml
273
+ if ! grep -q "name: $basename" package.yaml 2>/dev/null; then
274
+ warning "Found unlisted file: commands/$basename"
275
+ fixable "Add commands/$basename to package.yaml"
276
+ unlisted=$((unlisted + 1))
277
+ fi
278
+ done
279
+ fi
280
+
281
+ # Check designs directory
282
+ if [ -d "agent/design" ]; then
283
+ for file in agent/design/*.md; do
284
+ [ -f "$file" ] || continue
285
+ local basename=$(basename "$file")
286
+
287
+ # Skip templates and .gitkeep
288
+ [[ "$basename" == *.template.md ]] && continue
289
+ [[ "$basename" == ".gitkeep" ]] && continue
290
+
291
+ # Skip if in manifest (installed from another package)
292
+ if echo "$manifest_files" | grep -q "^${basename}$"; then
293
+ continue
294
+ fi
295
+
296
+ # Check if listed in package.yaml
297
+ if ! grep -q "name: $basename" package.yaml 2>/dev/null; then
298
+ warning "Found unlisted file: design/$basename"
299
+ fixable "Add design/$basename to package.yaml"
300
+ unlisted=$((unlisted + 1))
301
+ fi
302
+ done
303
+ fi
304
+
305
+ # Check scripts directory
306
+ if [ -d "agent/scripts" ]; then
307
+ for file in agent/scripts/*.sh; do
308
+ [ -f "$file" ] || continue
309
+ local basename=$(basename "$file")
310
+
311
+ # Skip templates, acp core scripts, and common utilities
312
+ [[ "$basename" == *.template.sh ]] && continue
313
+ [[ "$basename" == acp.* ]] && continue
314
+ [[ "$basename" == "acp.common.sh" ]] && continue
315
+
316
+ # Skip if in manifest (installed from another package)
317
+ if echo "$manifest_files" | grep -q "^${basename}$"; then
318
+ continue
319
+ fi
320
+
321
+ # Check if listed in package.yaml
322
+ if ! grep -q "name: $basename" package.yaml 2>/dev/null; then
323
+ warning "Found unlisted file: scripts/$basename"
324
+ fixable "Add scripts/$basename to package.yaml"
325
+ unlisted=$((unlisted + 1))
326
+ fi
327
+ done
328
+ fi
329
+
330
+ check
331
+ if [ "$unlisted" -eq 0 ]; then
332
+ pass "No unlisted files found"
333
+ else
334
+ warning "Found $unlisted unlisted file(s)"
335
+ fi
336
+
337
+ echo ""
338
+ }
339
+
340
+ # Validate namespace consistency
341
+ validate_namespace_consistency() {
342
+ echo "${BOLD}Namespace Consistency${NC}"
343
+
344
+ local namespace="$PACKAGE_NAME"
345
+ local inconsistent=0
346
+ local skipped=0
347
+ local skipped_package_files=0
348
+
349
+ # Read package.yaml contents to know which files should be validated
350
+ # Build list of filenames from contents (extract .name from each object)
351
+ # yaml_get_array now handles object arrays and returns count
352
+ local package_commands=""
353
+ if yaml_has_key "package.yaml" "contents.commands"; then
354
+ local command_count=$(yaml_get_array "package.yaml" "contents.commands")
355
+ for i in $(seq 0 $((command_count - 1))); do
356
+ local cmd_name=$(yaml_get_nested "package.yaml" "contents.commands[$i].name")
357
+ [ -n "$cmd_name" ] && package_commands="${package_commands}${cmd_name}"$'\n'
358
+ done
359
+ fi
360
+
361
+ local package_patterns=""
362
+ if yaml_has_key "package.yaml" "contents.patterns"; then
363
+ local pattern_count=$(yaml_get_array "package.yaml" "contents.patterns")
364
+ for i in $(seq 0 $((pattern_count - 1))); do
365
+ local pat_name=$(yaml_get_nested "package.yaml" "contents.patterns[$i].name")
366
+ [ -n "$pat_name" ] && package_patterns="${package_patterns}${pat_name}"$'\n'
367
+ done
368
+ fi
369
+
370
+ local package_designs=""
371
+ if yaml_has_key "package.yaml" "contents.designs"; then
372
+ local design_count=$(yaml_get_array "package.yaml" "contents.designs")
373
+ for i in $(seq 0 $((design_count - 1))); do
374
+ local des_name=$(yaml_get_nested "package.yaml" "contents.designs[$i].name")
375
+ [ -n "$des_name" ] && package_designs="${package_designs}${des_name}"$'\n'
376
+ done
377
+ fi
378
+
379
+ # Track package files that were skipped (for helpful warning)
380
+ local skipped_package_files_list=""
381
+
382
+ # Check command files
383
+ if [ -d "agent/commands" ]; then
384
+ for file in agent/commands/*.md; do
385
+ [ -f "$file" ] || continue
386
+ local basename=$(basename "$file")
387
+
388
+ # Skip templates and core commands
389
+ [[ "$basename" == *.template.md ]] && continue
390
+ [[ "$basename" == acp.* ]] && continue
391
+ [[ "$basename" == local.* ]] && continue
392
+
393
+ # Check if file is in package.yaml contents
394
+ if ! echo "$package_commands" | grep -q "^${basename}$"; then
395
+ # Check if this is a package file (matches namespace)
396
+ if [[ "$basename" =~ ^${namespace}\. ]]; then
397
+ skipped_package_files_list="${skipped_package_files_list}${basename}"$'\n'
398
+ skipped_package_files=$((skipped_package_files + 1))
399
+ fi
400
+ info "Skipping namespace check (not in package contents): $basename"
401
+ skipped=$((skipped + 1))
402
+ continue
403
+ fi
404
+
405
+ # Check if filename starts with namespace
406
+ if [[ ! "$basename" =~ ^${namespace}\. ]]; then
407
+ error "Command file missing namespace: $basename (should be ${namespace}.*.md)"
408
+ fixable "Rename $basename to ${namespace}.${basename}"
409
+ inconsistent=$((inconsistent + 1))
410
+ fi
411
+ done
412
+ fi
413
+
414
+ # Check pattern files (optional namespace for patterns)
415
+ if [ -d "agent/patterns" ]; then
416
+ for file in agent/patterns/*.md; do
417
+ [ -f "$file" ] || continue
418
+ local basename=$(basename "$file")
419
+
420
+ # Skip templates
421
+ [[ "$basename" == *.template.md ]] && continue
422
+
423
+ # Check if file is in package.yaml contents
424
+ if ! echo "$package_patterns" | grep -q "^${basename}$"; then
425
+ # Check if this is a package file (matches namespace)
426
+ if [[ "$basename" =~ ^${namespace}\. ]]; then
427
+ skipped_package_files_list="${skipped_package_files_list}${basename}"$'\n'
428
+ skipped_package_files=$((skipped_package_files + 1))
429
+ fi
430
+ info "Skipping namespace check (not in package contents): $basename"
431
+ skipped=$((skipped + 1))
432
+ continue
433
+ fi
434
+
435
+ # Patterns may or may not use namespace - just warn if inconsistent
436
+ if [[ "$basename" =~ ^${namespace}\. ]]; then
437
+ # Has namespace - good
438
+ :
439
+ else
440
+ # No namespace - warn but don't error
441
+ warning "Pattern file without namespace: $basename (consider ${namespace}.${basename})"
442
+ fi
443
+ done
444
+ fi
445
+
446
+ # Check design files
447
+ if [ -d "agent/design" ]; then
448
+ for file in agent/design/*.md; do
449
+ [ -f "$file" ] || continue
450
+ local basename=$(basename "$file")
451
+
452
+ # Skip templates
453
+ [[ "$basename" == *.template.md ]] && continue
454
+ [[ "$basename" == .gitkeep ]] && continue
455
+
456
+ # Check if file is in package.yaml contents
457
+ if ! echo "$package_designs" | grep -q "^${basename}$"; then
458
+ # Check if this is a package file (matches namespace)
459
+ if [[ "$basename" =~ ^${namespace}\. ]]; then
460
+ skipped_package_files_list="${skipped_package_files_list}${basename}"$'\n'
461
+ skipped_package_files=$((skipped_package_files + 1))
462
+ fi
463
+ info "Skipping namespace check (not in package contents): $basename"
464
+ skipped=$((skipped + 1))
465
+ continue
466
+ fi
467
+ done
468
+ fi
469
+
470
+ check
471
+
472
+ # Error if package files match namespace but aren't in contents
473
+ if [ "$skipped_package_files" -gt 0 ]; then
474
+ echo ""
475
+ error "$skipped_package_files package file(s) match namespace but not in contents:"
476
+ echo "$skipped_package_files_list" | while read -r fname; do
477
+ [ -n "$fname" ] && echo " ${RED}✗${NC} $fname"
478
+ done
479
+ echo ""
480
+ echo " ${RED}Package files matching namespace MUST be in package.yaml contents${NC}"
481
+ echo " Add them with: ${YELLOW}@acp.command-create${NC} or ${YELLOW}@acp.pattern-create${NC}"
482
+ echo " Or remove the namespace prefix if they're dependencies"
483
+ inconsistent=$((inconsistent + skipped_package_files))
484
+ fi
485
+
486
+ if [ "$inconsistent" -eq 0 ]; then
487
+ pass "All package content files use correct namespace"
488
+ if [ "$skipped" -gt 0 ]; then
489
+ info "$skipped file(s) skipped (not in package.yaml contents)"
490
+ info "These files won't be installed to user projects"
491
+ info "This is normal for installed dependencies (tracked in manifest.yaml)"
492
+ fi
493
+ else
494
+ error "$inconsistent file(s) with namespace issues"
495
+ fi
496
+
497
+ echo ""
498
+ }
499
+
500
+ # Validate git repository
501
+ validate_git_repository() {
502
+ echo "${BOLD}Git Repository${NC}"
503
+
504
+ check
505
+ if [ ! -d ".git" ]; then
506
+ error "Git repository not initialized"
507
+ fixable "Run: git init"
508
+ echo ""
509
+ return
510
+ fi
511
+ pass "Git repository initialized"
512
+
513
+ # Check for remote
514
+ check
515
+ local remote_url=$(git remote get-url origin 2>/dev/null || echo "")
516
+ if [ -z "$remote_url" ]; then
517
+ error "Git remote not configured"
518
+ fixable "Add git remote: git remote add origin <url>"
519
+ else
520
+ pass "Remote configured: $remote_url"
521
+
522
+ # Compare with package.yaml
523
+ local package_repo=$(yaml_get "package.yaml" "repository" 2>/dev/null || echo "")
524
+ check
525
+ if [ "$remote_url" = "$package_repo" ] || [ "${remote_url}.git" = "$package_repo" ]; then
526
+ pass "Remote URL matches package.yaml"
527
+ else
528
+ warning "Remote URL mismatch:"
529
+ echo " Git remote: $remote_url"
530
+ echo " package.yaml: $package_repo"
531
+ fixable "Update package.yaml repository field"
532
+ fi
533
+ fi
534
+
535
+ echo ""
536
+ }
537
+
538
+ # Validate README.md
539
+ validate_readme() {
540
+ echo "${BOLD}README.md${NC}"
541
+
542
+ check
543
+ if [ ! -f "README.md" ]; then
544
+ error "README.md not found"
545
+ fixable "Create README.md with package information"
546
+ echo ""
547
+ return
548
+ fi
549
+ pass "README.md exists"
550
+
551
+ # Check for required sections
552
+ local required_sections=("What's Included" "Installation" "License")
553
+ for section in "${required_sections[@]}"; do
554
+ check
555
+ if grep -qi "## $section" README.md || grep -qi "# $section" README.md; then
556
+ pass "Has '$section' section"
557
+ else
558
+ warning "Missing '$section' section in README.md"
559
+ fixable "Add '$section' section to README.md"
560
+ fi
561
+ done
562
+
563
+ echo ""
564
+ }
565
+
566
+ # Test installation
567
+ test_installation() {
568
+ echo "${BLUE}🧪 Test Installation${NC}"
569
+ echo ""
570
+
571
+ local test_dir="/tmp/acp-validate-test-$(date +%s)"
572
+
573
+ check
574
+ echo " Creating test directory: $test_dir"
575
+ mkdir -p "$test_dir/agent/"{patterns,commands,design}
576
+
577
+ # Create minimal manifest
578
+ cat > "$test_dir/agent/manifest.yaml" << 'EOF'
579
+ packages: {}
580
+ manifest_version: 1.0.0
581
+ last_updated: null
582
+ EOF
583
+
584
+ pass "Test directory created"
585
+
586
+ # Try to install package
587
+ check
588
+ echo " Installing package from current directory..."
589
+ local current_dir=$(pwd)
590
+
591
+ if cd "$test_dir" && "${current_dir}/agent/scripts/acp.package-install.sh" "$current_dir" --yes >/dev/null 2>&1; then
592
+ pass "Package installed successfully"
593
+
594
+ # Verify files were copied
595
+ check
596
+ local installed_files=$(find agent/ -name "*.md" -not -name "*.template.md" 2>/dev/null | wc -l)
597
+ if [ "$installed_files" -gt 0 ]; then
598
+ pass "Verified $installed_files file(s) copied"
599
+ else
600
+ error "No files were installed"
601
+ fi
602
+
603
+ # Verify manifest updated
604
+ check
605
+ if grep -q "packages:" agent/manifest.yaml && grep -q "$PACKAGE_NAME:" agent/manifest.yaml; then
606
+ pass "Manifest updated correctly"
607
+ else
608
+ warning "Manifest may not have been updated correctly"
609
+ fi
610
+ else
611
+ error "Package installation failed"
612
+ echo " ${YELLOW}This may indicate issues with package structure or install script${NC}"
613
+ fi
614
+
615
+ # Cleanup
616
+ cd "$current_dir"
617
+ rm -rf "$test_dir"
618
+ pass "Test directory cleaned up"
619
+
620
+ echo ""
621
+ }
622
+
623
+ # Check remote availability
624
+ check_remote_availability() {
625
+ echo "${BLUE}🌐 Remote Availability${NC}"
626
+ echo ""
627
+
628
+ local repo_url=$(yaml_get "package.yaml" "repository" 2>/dev/null || echo "")
629
+
630
+ if [ -z "$repo_url" ]; then
631
+ check
632
+ error "Repository URL not found in package.yaml"
633
+ echo ""
634
+ return
635
+ fi
636
+
637
+ echo " Checking: $repo_url"
638
+
639
+ check
640
+ if git ls-remote "$repo_url" HEAD >/dev/null 2>&1; then
641
+ pass "Remote repository accessible"
642
+
643
+ # Get latest commit
644
+ local latest_commit=$(git ls-remote "$repo_url" HEAD 2>/dev/null | cut -f1 | cut -c1-8)
645
+ if [ -n "$latest_commit" ]; then
646
+ pass "Latest commit: $latest_commit"
647
+ fi
648
+ else
649
+ warning "Remote repository not accessible"
650
+ echo " ${YELLOW}This may be normal if repository is not yet created${NC}"
651
+ echo " ${YELLOW}Ensure repository exists before publishing${NC}"
652
+ fi
653
+
654
+ echo ""
655
+ }
656
+
657
+ # Generate validation report
658
+ generate_report() {
659
+ echo "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
660
+ echo ""
661
+ echo "${BOLD}📊 Validation Summary${NC}"
662
+ echo ""
663
+ echo "Total Checks: $TOTAL_CHECKS"
664
+ echo "Passed: $PASSED_CHECKS"
665
+ echo "Warnings: ${#WARNINGS[@]}"
666
+ echo "Errors: ${#ERRORS[@]}"
667
+ echo ""
668
+
669
+ # Calculate score (clean checks / total * 100)
670
+ # Clean checks = checks that passed without errors or warnings
671
+ local score=0
672
+ if [ "$TOTAL_CHECKS" -gt 0 ]; then
673
+ local clean_checks=$((TOTAL_CHECKS - ${#ERRORS[@]} - ${#WARNINGS[@]}))
674
+ if [ "$clean_checks" -lt 0 ]; then
675
+ clean_checks=0
676
+ fi
677
+ score=$((clean_checks * 100 / TOTAL_CHECKS))
678
+ fi
679
+
680
+ # Determine status
681
+ if [ "${#ERRORS[@]}" -eq 0 ]; then
682
+ if [ "${#WARNINGS[@]}" -eq 0 ]; then
683
+ echo "Overall Status: ${GREEN}✅ PASS${NC}"
684
+ else
685
+ echo "Overall Status: ${YELLOW}✅ PASS WITH WARNINGS${NC}"
686
+ fi
687
+ else
688
+ echo "Overall Status: ${RED}❌ FAIL${NC}"
689
+ fi
690
+
691
+ echo "Validation Score: ${score}%"
692
+ echo ""
693
+ }
694
+
695
+ # Display issues
696
+ display_issues() {
697
+ if [ "${#ERRORS[@]}" -gt 0 ]; then
698
+ echo "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
699
+ echo ""
700
+ echo "${RED}❌ Errors Found (${#ERRORS[@]})${NC}"
701
+ echo ""
702
+ local i=1
703
+ for err in "${ERRORS[@]}"; do
704
+ echo " $i. $err"
705
+ i=$((i + 1))
706
+ done
707
+ echo ""
708
+ fi
709
+
710
+ if [ "${#WARNINGS[@]}" -gt 0 ]; then
711
+ echo "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
712
+ echo ""
713
+ echo "${YELLOW}⚠️ Warnings (${#WARNINGS[@]})${NC}"
714
+ echo ""
715
+ local i=1
716
+ for warn in "${WARNINGS[@]}"; do
717
+ echo " $i. $warn"
718
+ i=$((i + 1))
719
+ done
720
+ echo ""
721
+ fi
722
+ }
723
+
724
+ # Display fixable issues
725
+ display_fixable_issues() {
726
+ if [ "${#FIXABLE_ISSUES[@]}" -gt 0 ]; then
727
+ echo "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
728
+ echo ""
729
+ echo "${BOLD}🔧 Fixable Issues (${#FIXABLE_ISSUES[@]})${NC}"
730
+ echo ""
731
+ echo "The following issues can be fixed automatically:"
732
+ echo ""
733
+ local i=1
734
+ for issue in "${FIXABLE_ISSUES[@]}"; do
735
+ echo " $i. $issue"
736
+ i=$((i + 1))
737
+ done
738
+ echo ""
739
+ echo "${YELLOW}Note: Auto-fix requires LLM agent context.${NC}"
740
+ echo "Run this command via agent (e.g., in chat) to enable auto-fix."
741
+ echo ""
742
+ fi
743
+ }
744
+
745
+ # Validate experimental feature consistency
746
+ validate_experimental_consistency() {
747
+ echo ""
748
+ echo "${BOLD}Experimental Features${NC}"
749
+
750
+ local errors=0
751
+ local checked=0
752
+
753
+ # Check each content type
754
+ for type in commands patterns designs scripts; do
755
+ # Determine directory path
756
+ local dir_path
757
+ case "$type" in
758
+ designs)
759
+ dir_path="agent/design"
760
+ ;;
761
+ *)
762
+ dir_path="agent/${type}"
763
+ ;;
764
+ esac
765
+
766
+ # Skip if directory doesn't exist
767
+ if [ ! -d "$dir_path" ]; then
768
+ continue
769
+ fi
770
+
771
+ # Get all .md or .sh files in directory
772
+ local files
773
+ if [ "$type" = "scripts" ]; then
774
+ files=$(find "$dir_path" -maxdepth 1 -name "*.sh" -type f 2>/dev/null | xargs -r basename -a)
775
+ else
776
+ files=$(find "$dir_path" -maxdepth 1 -name "*.md" -type f 2>/dev/null | xargs -r basename -a)
777
+ fi
778
+
779
+ # Check each file
780
+ for file_name in $files; do
781
+ if [ -z "$file_name" ]; then
782
+ continue
783
+ fi
784
+
785
+ local file_path="${dir_path}/${file_name}"
786
+
787
+ # Check if file is in package.yaml contents
788
+ local in_contents=$(grep -A 1000 "^ ${type}:" package.yaml 2>/dev/null | grep -A 1 "name: ${file_name}" | head -1)
789
+ if [ -z "$in_contents" ]; then
790
+ continue # File not in package.yaml, skip
791
+ fi
792
+
793
+ # Check if marked experimental in package.yaml (exclude comments)
794
+ local is_experimental=$(grep -A 1000 "^ ${type}:" package.yaml 2>/dev/null | grep -A 2 "name: ${file_name}" | grep "^ *experimental: true" | grep -v "^[[:space:]]*#" | head -1)
795
+
796
+ # Check if file has Status: Experimental
797
+ local has_experimental_status=$(grep "^\*\*Status\*\*: Experimental" "$file_path" 2>/dev/null)
798
+
799
+ if [ -n "$is_experimental" ]; then
800
+ # Marked experimental in package.yaml
801
+ checked=$((checked + 1))
802
+ check
803
+ if [ -z "$has_experimental_status" ]; then
804
+ error "${file_path}: Marked experimental in package.yaml but missing 'Status: Experimental' in file"
805
+ fixable "Add '**Status**: Experimental' to ${file_path}"
806
+ errors=$((errors + 1))
807
+ else
808
+ pass "${file_name}: Experimental marking consistent"
809
+ fi
810
+ elif [ -n "$has_experimental_status" ]; then
811
+ # Has Status: Experimental but not marked in package.yaml
812
+ checked=$((checked + 1))
813
+ check
814
+ error "${file_path}: Has 'Status: Experimental' but not marked in package.yaml"
815
+ fixable "Add 'experimental: true' to ${file_name} in package.yaml"
816
+ errors=$((errors + 1))
817
+ fi
818
+ done
819
+ done
820
+
821
+ if [ $checked -eq 0 ]; then
822
+ check
823
+ pass "No experimental features to validate"
824
+ elif [ $errors -eq 0 ] && [ $checked -gt 0 ]; then
825
+ pass "All experimental features marked consistently"
826
+ fi
827
+
828
+ echo ""
829
+
830
+ return $errors
831
+ }
832
+
833
+ # Validate script-command bindings
834
+ validate_script_dependencies() {
835
+ echo ""
836
+ echo "${BOLD}Script-Command Bindings${NC}"
837
+
838
+ local validation_errors=0
839
+
840
+ # Get all commands from package.yaml using numeric index iteration
841
+ local cmd_count=0
842
+ local cmd_index=0
843
+ while true; do
844
+ local cmd=$(yaml_query ".contents.commands[$cmd_index].name" 2>/dev/null || echo "")
845
+ if [ -z "$cmd" ] || [ "$cmd" = "null" ]; then
846
+ break
847
+ fi
848
+
849
+ cmd_count=$((cmd_count + 1))
850
+ local cmd_file="agent/commands/$cmd"
851
+
852
+ if [ ! -f "$cmd_file" ]; then
853
+ cmd_index=$((cmd_index + 1))
854
+ continue # File existence checked elsewhere
855
+ fi
856
+
857
+ # Get scripts from frontmatter
858
+ local frontmatter_line=$(grep "^\*\*Scripts\*\*:" "$cmd_file" 2>/dev/null || echo "")
859
+
860
+ if [ -z "$frontmatter_line" ]; then
861
+ check
862
+ error "$cmd: Missing **Scripts**: field in frontmatter"
863
+ fixable "Add **Scripts**: field to $cmd_file frontmatter"
864
+ validation_errors=$((validation_errors + 1))
865
+ cmd_index=$((cmd_index + 1))
866
+ continue
867
+ fi
868
+
869
+ local frontmatter_scripts=$(echo "$frontmatter_line" | awk -F': ' '{print $2}' | tr ',' '\n' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep -v "^$" | sort)
870
+
871
+ # Handle "None" case
872
+ if echo "$frontmatter_scripts" | grep -qi "^None$"; then
873
+ frontmatter_scripts=""
874
+ fi
875
+
876
+ # Get scripts from package.yaml using numeric index iteration
877
+ local yaml_scripts=""
878
+ local si=0
879
+ while true; do
880
+ local s=$(yaml_query ".contents.commands[$cmd_index].scripts[$si]" 2>/dev/null || echo "")
881
+ if [ -z "$s" ] || [ "$s" = "null" ]; then
882
+ break
883
+ fi
884
+ if [ -n "$yaml_scripts" ]; then
885
+ yaml_scripts="$yaml_scripts
886
+ $s"
887
+ else
888
+ yaml_scripts="$s"
889
+ fi
890
+ si=$((si + 1))
891
+ done
892
+ yaml_scripts=$(echo "$yaml_scripts" | sort)
893
+
894
+ # Compare (both should be empty or both should match)
895
+ if [ "$frontmatter_scripts" != "$yaml_scripts" ]; then
896
+ check
897
+ error "$cmd: Scripts mismatch between frontmatter and package.yaml"
898
+ echo " ${DIM}Frontmatter: $(echo "$frontmatter_scripts" | tr '\n' ', ' | sed 's/, $//')${NC}"
899
+ echo " ${DIM}package.yaml: $(echo "$yaml_scripts" | tr '\n' ', ' | sed 's/, $//')${NC}"
900
+ fixable "Update $cmd to have matching scripts in both locations"
901
+ validation_errors=$((validation_errors + 1))
902
+ cmd_index=$((cmd_index + 1))
903
+ continue
904
+ fi
905
+
906
+ # Verify all scripts exist in scripts section
907
+ local script_errors=0
908
+ while IFS= read -r script; do
909
+ if [ -n "$script" ]; then
910
+ # Search for script in contents.scripts by numeric index
911
+ local script_found=false
912
+ local sci=0
913
+ while true; do
914
+ local s_name=$(yaml_query ".contents.scripts[$sci].name" 2>/dev/null || echo "")
915
+ if [ -z "$s_name" ] || [ "$s_name" = "null" ]; then
916
+ break
917
+ fi
918
+ if [ "$s_name" = "$script" ]; then
919
+ script_found=true
920
+ break
921
+ fi
922
+ sci=$((sci + 1))
923
+ done
924
+
925
+ if [ "$script_found" = false ]; then
926
+ if [ $script_errors -eq 0 ]; then
927
+ check
928
+ error "$cmd: Declares scripts not in scripts section"
929
+ fi
930
+ echo " ${DIM}Missing: $script${NC}"
931
+ fixable "Add $script to contents.scripts section in package.yaml"
932
+ script_errors=$((script_errors + 1))
933
+ fi
934
+ fi
935
+ done <<< "$frontmatter_scripts"
936
+
937
+ if [ $script_errors -gt 0 ]; then
938
+ validation_errors=$((validation_errors + 1))
939
+ else
940
+ check
941
+ local script_count=$(echo "$frontmatter_scripts" | grep -v "^$" | wc -l)
942
+ if [ "$script_count" -eq 0 ]; then
943
+ pass "$cmd: No script dependencies"
944
+ else
945
+ pass "$cmd: Scripts consistent ($script_count script(s))"
946
+ fi
947
+ fi
948
+
949
+ cmd_index=$((cmd_index + 1))
950
+ done
951
+
952
+ if [ $cmd_count -eq 0 ]; then
953
+ pass "No commands to validate"
954
+ fi
955
+
956
+ return $validation_errors
957
+ }
958
+
959
+ # Main validation function
960
+ main() {
961
+ echo "${BLUE}🔍 ACP Package Validation${NC}"
962
+ echo "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
963
+ echo ""
964
+
965
+ # Check package context
966
+ check_package_context
967
+
968
+ # Run shell validations
969
+ validate_yaml_structure
970
+ validate_file_existence
971
+ check_unlisted_files
972
+ validate_namespace_consistency
973
+ validate_script_dependencies
974
+ validate_experimental_consistency
975
+ validate_git_repository
976
+ validate_readme
977
+
978
+ # Test installation
979
+ test_installation
980
+
981
+ # Check remote availability
982
+ check_remote_availability
983
+
984
+ # Generate report
985
+ generate_report
986
+
987
+ # Display issues
988
+ display_issues
989
+
990
+ # Display fixable issues
991
+ display_fixable_issues
992
+
993
+ # Exit with appropriate code
994
+ if [ "${#ERRORS[@]}" -gt 0 ]; then
995
+ echo "${RED}Validation failed. Fix errors and run again.${NC}"
996
+ echo ""
997
+ exit 1
998
+ else
999
+ if [ "${#WARNINGS[@]}" -gt 0 ]; then
1000
+ echo "${GREEN}✅ Package validation passed with warnings.${NC}"
1001
+ echo ""
1002
+ echo "Recommendations:"
1003
+ echo " - Address warnings before publishing"
1004
+ echo " - Run @acp.package-publish when ready"
1005
+ echo ""
1006
+ else
1007
+ echo "${GREEN}✅ Package validation passed!${NC}"
1008
+ echo ""
1009
+ echo "Your package is ready to publish."
1010
+ echo "Run: @acp.package-publish"
1011
+ echo ""
1012
+ fi
1013
+ exit 0
1014
+ fi
1015
+ }
1016
+
1017
+ # Run main function
1018
+ main "$@"