@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.
- package/README.md +68 -0
- package/agent/commands/acp.clarification-address.md +417 -0
- package/agent/commands/acp.clarification-capture.md +386 -0
- package/agent/commands/acp.clarification-create.md +437 -0
- package/agent/commands/acp.clarifications-research.md +326 -0
- package/agent/commands/acp.command-create.md +432 -0
- package/agent/commands/acp.design-create.md +286 -0
- package/agent/commands/acp.design-reference.md +355 -0
- package/agent/commands/acp.handoff.md +270 -0
- package/agent/commands/acp.index.md +423 -0
- package/agent/commands/acp.init.md +546 -0
- package/agent/commands/acp.package-create.md +895 -0
- package/agent/commands/acp.package-info.md +212 -0
- package/agent/commands/acp.package-install.md +539 -0
- package/agent/commands/acp.package-list.md +280 -0
- package/agent/commands/acp.package-publish.md +541 -0
- package/agent/commands/acp.package-remove.md +293 -0
- package/agent/commands/acp.package-search.md +307 -0
- package/agent/commands/acp.package-update.md +361 -0
- package/agent/commands/acp.package-validate.md +540 -0
- package/agent/commands/acp.pattern-create.md +386 -0
- package/agent/commands/acp.plan.md +587 -0
- package/agent/commands/acp.proceed.md +882 -0
- package/agent/commands/acp.project-create.md +675 -0
- package/agent/commands/acp.project-info.md +312 -0
- package/agent/commands/acp.project-list.md +226 -0
- package/agent/commands/acp.project-remove.md +379 -0
- package/agent/commands/acp.project-set.md +227 -0
- package/agent/commands/acp.project-update.md +307 -0
- package/agent/commands/acp.projects-restore.md +228 -0
- package/agent/commands/acp.projects-sync.md +347 -0
- package/agent/commands/acp.report.md +407 -0
- package/agent/commands/acp.resume.md +239 -0
- package/agent/commands/acp.sessions.md +301 -0
- package/agent/commands/acp.status.md +293 -0
- package/agent/commands/acp.sync.md +364 -0
- package/agent/commands/acp.task-create.md +500 -0
- package/agent/commands/acp.update.md +302 -0
- package/agent/commands/acp.validate.md +466 -0
- package/agent/commands/acp.version-check-for-updates.md +276 -0
- package/agent/commands/acp.version-check.md +191 -0
- package/agent/commands/acp.version-update.md +289 -0
- package/agent/commands/command.template.md +339 -0
- package/agent/commands/git.commit.md +526 -0
- package/agent/commands/git.init.md +514 -0
- package/agent/commands/tanstack-cloudflare.deploy.md +272 -0
- package/agent/commands/tanstack-cloudflare.tail.md +275 -0
- package/agent/design/.gitkeep +0 -0
- package/agent/design/design.template.md +154 -0
- package/agent/design/local.dashboard-layout-routing.md +288 -0
- package/agent/design/local.data-model-yaml-parsing.md +310 -0
- package/agent/design/local.search-filtering.md +331 -0
- package/agent/design/local.server-api-auto-refresh.md +235 -0
- package/agent/design/local.table-tree-views.md +299 -0
- package/agent/design/local.visualizer-requirements.md +349 -0
- package/agent/design/requirements.template.md +387 -0
- package/agent/index/.gitkeep +0 -0
- package/agent/index/acp.core.yaml +137 -0
- package/agent/index/local.main.template.yaml +37 -0
- package/agent/manifest.template.yaml +13 -0
- package/agent/manifest.yaml +302 -0
- package/agent/milestones/.gitkeep +0 -0
- package/agent/milestones/milestone-1-project-scaffold-data-pipeline.md +67 -0
- package/agent/milestones/milestone-1-{title}.template.md +206 -0
- package/agent/milestones/milestone-2-dashboard-views-interaction.md +79 -0
- package/agent/package.template.yaml +86 -0
- package/agent/patterns/.gitkeep +0 -0
- package/agent/patterns/bootstrap.template.md +1237 -0
- package/agent/patterns/pattern.template.md +382 -0
- package/agent/patterns/tanstack-cloudflare.acl-permissions.md +332 -0
- package/agent/patterns/tanstack-cloudflare.action-bar-item.md +416 -0
- package/agent/patterns/tanstack-cloudflare.api-route-handlers.md +401 -0
- package/agent/patterns/tanstack-cloudflare.auth-session-management.md +387 -0
- package/agent/patterns/tanstack-cloudflare.card-and-list.md +271 -0
- package/agent/patterns/tanstack-cloudflare.chat-engine.md +353 -0
- package/agent/patterns/tanstack-cloudflare.confirmation-tokens.md +346 -0
- package/agent/patterns/tanstack-cloudflare.durable-objects-websocket.md +516 -0
- package/agent/patterns/tanstack-cloudflare.email-service.md +431 -0
- package/agent/patterns/tanstack-cloudflare.expander.md +98 -0
- package/agent/patterns/tanstack-cloudflare.fcm-push.md +115 -0
- package/agent/patterns/tanstack-cloudflare.firebase-anonymous-sessions.md +441 -0
- package/agent/patterns/tanstack-cloudflare.firebase-auth.md +348 -0
- package/agent/patterns/tanstack-cloudflare.firebase-firestore.md +550 -0
- package/agent/patterns/tanstack-cloudflare.firebase-storage.md +369 -0
- package/agent/patterns/tanstack-cloudflare.form-controls.md +145 -0
- package/agent/patterns/tanstack-cloudflare.global-search-context.md +93 -0
- package/agent/patterns/tanstack-cloudflare.image-carousel.md +126 -0
- package/agent/patterns/tanstack-cloudflare.library-services.md +553 -0
- package/agent/patterns/tanstack-cloudflare.lightbox.md +169 -0
- package/agent/patterns/tanstack-cloudflare.markdown-content.md +115 -0
- package/agent/patterns/tanstack-cloudflare.mention-suggestions.md +98 -0
- package/agent/patterns/tanstack-cloudflare.modal.md +156 -0
- package/agent/patterns/tanstack-cloudflare.nextjs-to-tanstack-routing.md +461 -0
- package/agent/patterns/tanstack-cloudflare.notifications-engine.md +151 -0
- package/agent/patterns/tanstack-cloudflare.oauth-token-refresh.md +90 -0
- package/agent/patterns/tanstack-cloudflare.og-metadata.md +296 -0
- package/agent/patterns/tanstack-cloudflare.pagination.md +442 -0
- package/agent/patterns/tanstack-cloudflare.pill-input.md +220 -0
- package/agent/patterns/tanstack-cloudflare.provider-adapter.md +401 -0
- package/agent/patterns/tanstack-cloudflare.rate-limiting.md +323 -0
- package/agent/patterns/tanstack-cloudflare.scheduled-tasks.md +338 -0
- package/agent/patterns/tanstack-cloudflare.searchable-settings.md +375 -0
- package/agent/patterns/tanstack-cloudflare.slide-over.md +129 -0
- package/agent/patterns/tanstack-cloudflare.ssr-preload.md +571 -0
- package/agent/patterns/tanstack-cloudflare.third-party-api-integration.md +508 -0
- package/agent/patterns/tanstack-cloudflare.toast-system.md +142 -0
- package/agent/patterns/tanstack-cloudflare.unified-header.md +280 -0
- package/agent/patterns/tanstack-cloudflare.user-scoped-collections.md +628 -0
- package/agent/patterns/tanstack-cloudflare.websocket-manager.md +237 -0
- package/agent/patterns/tanstack-cloudflare.wrangler-configuration.md +358 -0
- package/agent/patterns/tanstack-cloudflare.zod-schema-validation.md +336 -0
- package/agent/progress.template.yaml +161 -0
- package/agent/progress.yaml +145 -0
- package/agent/schemas/package.schema.yaml +276 -0
- package/agent/scripts/acp.common.sh +1781 -0
- package/agent/scripts/acp.install.sh +333 -0
- package/agent/scripts/acp.package-create.sh +924 -0
- package/agent/scripts/acp.package-info.sh +288 -0
- package/agent/scripts/acp.package-install.sh +893 -0
- package/agent/scripts/acp.package-list.sh +311 -0
- package/agent/scripts/acp.package-publish.sh +420 -0
- package/agent/scripts/acp.package-remove.sh +348 -0
- package/agent/scripts/acp.package-search.sh +156 -0
- package/agent/scripts/acp.package-update.sh +517 -0
- package/agent/scripts/acp.package-validate.sh +1018 -0
- package/agent/scripts/acp.uninstall.sh +85 -0
- package/agent/scripts/acp.version-check-for-updates.sh +98 -0
- package/agent/scripts/acp.version-check.sh +47 -0
- package/agent/scripts/acp.version-update.sh +176 -0
- package/agent/scripts/acp.yaml-parser.sh +985 -0
- package/agent/scripts/acp.yaml-validate.sh +205 -0
- package/agent/tasks/.gitkeep +0 -0
- package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-1-initialize-tanstack-start-project.md +210 -0
- package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-2-implement-data-model-yaml-parser.md +294 -0
- package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-3-build-server-api-data-loading.md +193 -0
- package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-4-add-auto-refresh-sse.md +262 -0
- package/agent/tasks/milestone-2-dashboard-views-interaction/task-10-polish-integration-testing.md +156 -0
- package/agent/tasks/milestone-2-dashboard-views-interaction/task-5-build-dashboard-layout-routing.md +178 -0
- package/agent/tasks/milestone-2-dashboard-views-interaction/task-6-build-overview-page.md +141 -0
- package/agent/tasks/milestone-2-dashboard-views-interaction/task-7-implement-milestone-table-view.md +153 -0
- package/agent/tasks/milestone-2-dashboard-views-interaction/task-8-implement-milestone-tree-view.md +174 -0
- package/agent/tasks/milestone-2-dashboard-views-interaction/task-9-implement-search-filtering.md +233 -0
- package/agent/tasks/task-1-{title}.template.md +244 -0
- package/bin/visualize.mjs +84 -0
- package/package.json +48 -0
- package/src/components/ExtraFieldsBadge.tsx +15 -0
- package/src/components/FilterBar.tsx +33 -0
- package/src/components/Header.tsx +23 -0
- package/src/components/MilestoneTable.tsx +167 -0
- package/src/components/MilestoneTree.tsx +84 -0
- package/src/components/ProgressBar.tsx +20 -0
- package/src/components/SearchInput.tsx +22 -0
- package/src/components/Sidebar.tsx +54 -0
- package/src/components/StatusBadge.tsx +23 -0
- package/src/components/StatusDot.tsx +12 -0
- package/src/components/TaskList.tsx +36 -0
- package/src/components/ViewToggle.tsx +31 -0
- package/src/lib/config.ts +8 -0
- package/src/lib/file-watcher.ts +43 -0
- package/src/lib/search.ts +48 -0
- package/src/lib/types.ts +73 -0
- package/src/lib/useAutoRefresh.ts +31 -0
- package/src/lib/useCollapse.ts +31 -0
- package/src/lib/useFilteredData.ts +55 -0
- package/src/lib/yaml-loader-real.spec.ts +47 -0
- package/src/lib/yaml-loader.spec.ts +201 -0
- package/src/lib/yaml-loader.ts +265 -0
- package/src/routeTree.gen.ts +140 -0
- package/src/router.tsx +10 -0
- package/src/routes/__root.tsx +75 -0
- package/src/routes/api/watch.ts +29 -0
- package/src/routes/index.tsx +115 -0
- package/src/routes/milestones.tsx +50 -0
- package/src/routes/search.tsx +84 -0
- package/src/routes/tasks.tsx +63 -0
- package/src/services/progress-database.service.ts +46 -0
- package/src/styles.css +25 -0
- package/tsconfig.json +24 -0
- package/vite.config.ts +16 -0
- 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 "$@"
|