gentle-agent-extensions 1.0.1 → 1.2.1

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.
@@ -1,206 +0,0 @@
1
- #!/usr/bin/env bash
2
- # install.sh - Install gentle-agent-extensions
3
- #
4
- # This script sets up the project and configures the Pi extension.
5
- # It supports multiple installation profiles:
6
- # - pi (default): Standard Pi installation at ~/.pi/agent
7
- # - gentle-shell: Isolated Gentle Shell at ~/.local/share/gentle-shell/agent
8
- # - gentle-shell-linked: Gentle Shell with --link at ~/.pi/agent
9
-
10
- set -euo pipefail
11
-
12
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
- PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
14
-
15
- # Colors for output
16
- RED='\033[0;31m'
17
- GREEN='\033[0;32m'
18
- YELLOW='\033[1;33m'
19
- BLUE='\033[0;34m'
20
- NC='\033[0m' # No Color
21
-
22
- log_info() { echo -e "${BLUE}[INFO]${NC} $*"; }
23
- log_success() { echo -e "${GREEN}[SUCCESS]${NC} $*"; }
24
- log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
25
- log_error() { echo -e "${RED}[ERROR]${NC} $*"; }
26
-
27
- usage() {
28
- cat <<EOF
29
- Usage: $0 [OPTIONS]
30
-
31
- Install gentle-agent-extensions for Pi / Gentle Pi.
32
-
33
- Options:
34
- --profile PROFILE Installation profile: pi, gentle-shell, gentle-shell-linked (default: pi)
35
- --agent-home PATH Explicit agent home directory (overrides profile)
36
- --dry-run Show what would be done without making changes
37
- --force Overwrite existing extension file
38
- -h, --help Show this help
39
-
40
- Examples:
41
- $0 # Install for standard Pi
42
- $0 --profile gentle-shell # Install for isolated Gentle Shell
43
- $0 --agent-home ~/.pi/agent # Explicit agent home
44
- $0 --dry-run # Preview changes
45
- EOF
46
- }
47
-
48
- PROFILE="pi"
49
- AGENT_HOME=""
50
- DRY_RUN=false
51
- FORCE=false
52
-
53
- while [[ $# -gt 0 ]]; do
54
- case $1 in
55
- --profile)
56
- PROFILE="$2"
57
- shift 2
58
- ;;
59
- --agent-home)
60
- AGENT_HOME="$2"
61
- shift 2
62
- ;;
63
- --dry-run)
64
- DRY_RUN=true
65
- shift
66
- ;;
67
- --force)
68
- FORCE=true
69
- shift
70
- ;;
71
- -h|--help)
72
- usage
73
- exit 0
74
- ;;
75
- *)
76
- log_error "Unknown option: $1"
77
- usage
78
- exit 1
79
- ;;
80
- esac
81
- done
82
-
83
- # Determine agent home based on profile
84
- if [[ -z "$AGENT_HOME" ]]; then
85
- case "$PROFILE" in
86
- pi)
87
- AGENT_HOME="${HOME}/.pi/agent"
88
- ;;
89
- gentle-shell)
90
- AGENT_HOME="${HOME}/.local/share/gentle-shell/agent"
91
- ;;
92
- gentle-shell-linked)
93
- AGENT_HOME="${HOME}/.pi/agent"
94
- ;;
95
- *)
96
- log_error "Unknown profile: $PROFILE"
97
- exit 1
98
- ;;
99
- esac
100
- fi
101
-
102
- EXTENSION_SOURCE="${PROJECT_ROOT}/extensions/gentle-agent-extensions.ts"
103
- EXTENSION_TARGET="${AGENT_HOME}/extensions/gentle-agent-extensions.ts"
104
-
105
- log_info "Installing gentle-agent-extensions"
106
- log_info "Profile: $PROFILE"
107
- log_info "Agent home: $AGENT_HOME"
108
- log_info "Project root: $PROJECT_ROOT"
109
-
110
- if [[ "$DRY_RUN" == "true" ]]; then
111
- log_warn "DRY RUN - no changes will be made"
112
- fi
113
-
114
- # Check source extension exists
115
- if [[ ! -f "$EXTENSION_SOURCE" ]]; then
116
- log_error "Extension source not found: $EXTENSION_SOURCE"
117
- exit 1
118
- fi
119
-
120
- # Create agent home extensions directory
121
- if [[ "$DRY_RUN" == "false" ]]; then
122
- mkdir -p "$(dirname "$EXTENSION_TARGET")"
123
- fi
124
-
125
- # Check if extension already exists
126
- if [[ -f "$EXTENSION_TARGET" && "$FORCE" == "false" && "$DRY_RUN" == "false" ]]; then
127
- log_warn "Extension already exists at $EXTENSION_TARGET"
128
- log_warn "Use --force to overwrite or remove it first"
129
- exit 1
130
- fi
131
-
132
- # Copy extension
133
- if [[ "$DRY_RUN" == "true" ]]; then
134
- log_info "Would copy: $EXTENSION_SOURCE -> $EXTENSION_TARGET"
135
- else
136
- cp "$EXTENSION_SOURCE" "$EXTENSION_TARGET"
137
- log_success "Extension installed to $EXTENSION_TARGET"
138
- fi
139
-
140
- # Create project agent directories
141
- PROJECT_AGENTS_DIR="${PROJECT_ROOT}/.pi/agents"
142
- PROJECT_SUBAGENTS_DIR="${PROJECT_ROOT}/.pi/subagents"
143
-
144
- if [[ "$DRY_RUN" == "true" ]]; then
145
- log_info "Would create directories: $PROJECT_AGENTS_DIR, $PROJECT_SUBAGENTS_DIR"
146
- else
147
- mkdir -p "$PROJECT_AGENTS_DIR" "$PROJECT_SUBAGENTS_DIR"
148
- log_success "Created project agent directories"
149
- fi
150
-
151
- # Initialize manifest if not exists
152
- MANIFEST="${PROJECT_ROOT}/.manifest.json"
153
- if [[ ! -f "$MANIFEST" ]]; then
154
- if [[ "$DRY_RUN" == "true" ]]; then
155
- log_info "Would create manifest: $MANIFEST"
156
- else
157
- cat > "$MANIFEST" <<MANIFEST_EOF
158
- {
159
- "version": "1.0",
160
- "description": "Manifest of files managed by gentle-agent-extensions",
161
- "managedPaths": {
162
- "extensions": ["extensions/gentle-agent-extensions.ts"],
163
- "agents": [],
164
- "routing": [],
165
- "overlays": [],
166
- "skills": [],
167
- "scripts": [],
168
- "assets": []
169
- },
170
- "installProfiles": {
171
- "$PROFILE": { "agentHome": "$AGENT_HOME" }
172
- }
173
- }
174
- MANIFEST_EOF
175
- log_success "Created manifest: $MANIFEST"
176
- fi
177
- else
178
- log_info "Manifest already exists: $MANIFEST"
179
- fi
180
-
181
- # Add extension to Pi settings if not already present
182
- SETTINGS_FILE="${AGENT_HOME}/settings.json"
183
- if [[ "$DRY_RUN" == "false" ]]; then
184
- if [[ -f "$SETTINGS_FILE" ]]; then
185
- # Check if extension is already in settings
186
- if ! grep -q "gentle-agent-extensions" "$SETTINGS_FILE"; then
187
- log_warn "Extension not in Pi settings. Add it manually or run:"
188
- log_warn " pi install file:$PROJECT_ROOT"
189
- log_warn "Or add to $SETTINGS_FILE:"
190
- log_warn ' { "packages": [{ "source": "file:'"$PROJECT_ROOT"'" }] }'
191
- else
192
- log_success "Extension already configured in Pi settings"
193
- fi
194
- else
195
- log_warn "Pi settings not found at $SETTINGS_FILE"
196
- log_warn "Run 'pi install file:$PROJECT_ROOT' to register the extension"
197
- fi
198
- fi
199
-
200
- log_success "Installation complete!"
201
- log_info ""
202
- log_info "Next steps:"
203
- log_info " 1. Register the extension with Pi: pi install file:$PROJECT_ROOT"
204
- log_info " 2. Run sync: $PROJECT_ROOT/scripts/sync.sh"
205
- log_info " 3. Verify: $PROJECT_ROOT/scripts/doctor.sh"
206
- log_info " 4. Start Pi and run /gentle-extensions:status"
package/scripts/sync.sh DELETED
@@ -1,513 +0,0 @@
1
- #!/usr/bin/env bash
2
- # sync.sh - Synchronize gentle-agent-extensions with active Pi profile
3
- #
4
- # This script synchronizes custom agents, overlays, routing, skills, and MCP servers
5
- # with the active Pi installation. It is idempotent and supports dry-run/check modes.
6
-
7
- set -euo pipefail
8
-
9
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10
- PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
11
-
12
- # Colors
13
- RED='\033[0;31m'
14
- GREEN='\033[0;32m'
15
- YELLOW='\033[1;33m'
16
- BLUE='\033[0;34m'
17
- NC='\033[0m'
18
-
19
- log_info() { echo -e "${BLUE}[INFO]${NC} $*"; }
20
- log_success() { echo -e "${GREEN}[SUCCESS]${NC} $*"; }
21
- log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
22
- log_error() { echo -e "${RED}[ERROR]${NC} $*"; }
23
-
24
- usage() {
25
- cat <<EOF
26
- Usage: $0 [OPTIONS]
27
-
28
- Synchronize gentle-agent-extensions with the active Pi profile.
29
-
30
- Options:
31
- --profile PROFILE Installation profile: pi, gentle-shell, gentle-shell-linked (default: pi)
32
- --agent-home PATH Explicit agent home directory (overrides profile)
33
- --dry-run Show what would be done without making changes
34
- --check Validate configuration and report issues (exit code 0 if ok, 1 if issues)
35
- -h, --help Show this help
36
-
37
- Examples:
38
- $0 # Full sync
39
- $0 --dry-run # Preview changes
40
- $0 --check # Validate only
41
- $0 --profile gentle-shell
42
- EOF
43
- }
44
-
45
- PROFILE="pi"
46
- AGENT_HOME=""
47
- DRY_RUN=false
48
- CHECK_MODE=false
49
-
50
- while [[ $# -gt 0 ]]; do
51
- case $1 in
52
- --profile)
53
- PROFILE="$2"
54
- shift 2
55
- ;;
56
- --agent-home)
57
- AGENT_HOME="$2"
58
- shift 2
59
- ;;
60
- --dry-run)
61
- DRY_RUN=true
62
- shift
63
- ;;
64
- --check)
65
- CHECK_MODE=true
66
- shift
67
- ;;
68
- -h|--help)
69
- usage
70
- exit 0
71
- ;;
72
- *)
73
- log_error "Unknown option: $1"
74
- usage
75
- exit 1
76
- ;;
77
- esac
78
- done
79
-
80
- # Determine agent home
81
- if [[ -z "$AGENT_HOME" ]]; then
82
- case "$PROFILE" in
83
- pi) AGENT_HOME="${HOME}/.pi/agent" ;;
84
- gentle-shell) AGENT_HOME="${HOME}/.local/share/gentle-shell/agent" ;;
85
- gentle-shell-linked) AGENT_HOME="${HOME}/.pi/agent" ;;
86
- *) log_error "Unknown profile: $PROFILE"; exit 1 ;;
87
- esac
88
- fi
89
-
90
- log_info "Syncing gentle-agent-extensions"
91
- log_info "Profile: $PROFILE"
92
- log_info "Agent home: $AGENT_HOME"
93
- log_info "Project root: $PROJECT_ROOT"
94
-
95
- if [[ "$DRY_RUN" == "true" ]]; then
96
- log_warn "DRY RUN mode - no changes will be made"
97
- fi
98
-
99
- if [[ "$CHECK_MODE" == "true" ]]; then
100
- log_info "CHECK mode - validation only"
101
- fi
102
-
103
- # Track changes and issues
104
- CHANGES=0
105
- ISSUES=0
106
- WARNINGS=0
107
-
108
- # Source directories
109
- AGENTS_SRC="${PROJECT_ROOT}/agents"
110
- OVERLAYS_SRC="${PROJECT_ROOT}/overlays"
111
- ROUTING_SRC="${PROJECT_ROOT}/routing"
112
- SKILLS_SRC="${PROJECT_ROOT}/skills"
113
- MCP_SRC="${PROJECT_ROOT}/mcp"
114
-
115
- # Target directories
116
- AGENT_HOME_EXTENSIONS="${AGENT_HOME}/extensions"
117
- PROJECT_AGENTS_DIR="${PROJECT_ROOT}/.pi/agents"
118
- PROJECT_SUBAGENTS_DIR="${PROJECT_ROOT}/.pi/subagents"
119
-
120
- # Manifest
121
- MANIFEST="${PROJECT_ROOT}/.manifest.json"
122
-
123
- # Helper: read manifest
124
- read_manifest() {
125
- if [[ -f "$MANIFEST" ]]; then
126
- cat "$MANIFEST"
127
- else
128
- echo '{"version":"1.0","managedPaths":{}}'
129
- fi
130
- }
131
-
132
- # Helper: write manifest
133
- write_manifest() {
134
- if [[ "$DRY_RUN" == "false" && "$CHECK_MODE" == "false" ]]; then
135
- echo "$1" > "$MANIFEST"
136
- fi
137
- }
138
-
139
- # Helper: update manifest path list
140
- update_manifest_paths() {
141
- local key="$1"
142
- local paths_json="$2"
143
- local manifest
144
- manifest=$(read_manifest)
145
- if command -v jq &> /dev/null; then
146
- echo "$manifest" | jq --arg key "$key" --argjson paths "$paths_json" '.managedPaths[$key] = $paths'
147
- else
148
- log_warn "jq not available, manifest not updated (install jq for full manifest support)"
149
- echo "$manifest"
150
- fi
151
- }
152
-
153
- # 1. Validate project structure
154
- log_info "Validating project structure..."
155
-
156
- for dir in "$AGENTS_SRC" "$OVERLAYS_SRC" "$ROUTING_SRC" "$SKILLS_SRC" "$MCP_SRC"; do
157
- if [[ ! -d "$dir" ]]; then
158
- log_warn "Directory missing: $dir"
159
- ((WARNINGS++))
160
- fi
161
- done
162
-
163
- # 2. Sync agents
164
- log_info "Syncing agents..."
165
-
166
- if [[ -d "$AGENTS_SRC" ]]; then
167
- if [[ "$DRY_RUN" == "false" && "$CHECK_MODE" == "false" ]]; then
168
- mkdir -p "$PROJECT_AGENTS_DIR"
169
- fi
170
-
171
- MANAGED_AGENTS=()
172
-
173
- for agent_file in "$AGENTS_SRC"/*.md; do
174
- [[ -f "$agent_file" ]] || continue
175
-
176
- agent_name=$(basename "$agent_file" .md)
177
- target_file="${PROJECT_AGENTS_DIR}/${agent_name}.md"
178
-
179
- if ! head -20 "$agent_file" | grep -q "^---$"; then
180
- log_warn "Agent $agent_name: missing frontmatter delimiter"
181
- ((WARNINGS++))
182
- fi
183
-
184
- if ! grep -q "^name:" "$agent_file"; then
185
- log_warn "Agent $agent_name: missing 'name' in frontmatter"
186
- ((WARNINGS++))
187
- fi
188
-
189
- if [[ "$DRY_RUN" == "true" ]]; then
190
- if [[ -f "$target_file" ]]; then
191
- if ! cmp -s "$agent_file" "$target_file"; then
192
- log_info "Would update: $agent_name -> $target_file"
193
- ((CHANGES++))
194
- else
195
- log_info "Unchanged: $agent_name"
196
- fi
197
- else
198
- log_info "Would create: $agent_name -> $target_file"
199
- ((CHANGES++))
200
- fi
201
- elif [[ "$CHECK_MODE" == "false" ]]; then
202
- if [[ -f "$target_file" ]]; then
203
- if ! cmp -s "$agent_file" "$target_file"; then
204
- cp "$agent_file" "$target_file"
205
- log_success "Updated agent: $agent_name"
206
- ((CHANGES++))
207
- else
208
- log_info "Unchanged: $agent_name"
209
- fi
210
- else
211
- cp "$agent_file" "$target_file"
212
- log_success "Created agent: $agent_name"
213
- ((CHANGES++))
214
- fi
215
- fi
216
-
217
- MANAGED_AGENTS+=("$target_file")
218
- done
219
-
220
- if [[ "$DRY_RUN" == "false" && "$CHECK_MODE" == "false" ]]; then
221
- paths_json=$(printf '"%s",' "${MANAGED_AGENTS[@]}" | sed 's/,$//')
222
- paths_json="[$paths_json]"
223
- new_manifest=$(update_manifest_paths "agents" "$paths_json")
224
- write_manifest "$new_manifest"
225
- fi
226
- else
227
- log_warn "Agents source directory not found: $AGENTS_SRC"
228
- ((WARNINGS++))
229
- fi
230
-
231
- # 3. Validate overlays
232
- log_info "Validating overlays..."
233
-
234
- if [[ -d "$OVERLAYS_SRC" ]]; then
235
- for overlay_file in "$OVERLAYS_SRC"/*.overlay.md; do
236
- [[ -f "$overlay_file" ]] || continue
237
-
238
- overlay_name=$(basename "$overlay_file" .overlay.md)
239
-
240
- if ! head -20 "$overlay_file" | grep -q "^---$"; then
241
- log_warn "Overlay $overlay_name: missing frontmatter delimiter"
242
- ((WARNINGS++))
243
- fi
244
-
245
- if ! grep -q "^target:" "$overlay_file"; then
246
- log_error "Overlay $overlay_name: missing 'target' in frontmatter"
247
- ((ISSUES++))
248
- fi
249
-
250
- target=$(grep "^target:" "$overlay_file" | head -1 | sed 's/^target: *//')
251
- log_info "Overlay validated: $overlay_name -> target: $target"
252
- done
253
- else
254
- log_warn "Overlays source directory not found: $OVERLAYS_SRC"
255
- ((WARNINGS++))
256
- fi
257
-
258
- # 4. Validate routing
259
- log_info "Validating routing..."
260
-
261
- if [[ -d "$ROUTING_SRC" ]]; then
262
- for routing_file in "$ROUTING_SRC"/*.md; do
263
- [[ -f "$routing_file" ]] || continue
264
-
265
- routing_name=$(basename "$routing_file" .md)
266
-
267
- if ! grep -q "^agent:" "$routing_file"; then
268
- log_warn "Routing $routing_name: missing 'agent' in frontmatter"
269
- ((WARNINGS++))
270
- fi
271
-
272
- agent=$(grep "^agent:" "$routing_file" | head -1 | sed 's/^agent: *//')
273
- log_info "Routing validated: $routing_name -> agent: $agent"
274
- done
275
- else
276
- log_warn "Routing source directory not found: $ROUTING_SRC"
277
- ((WARNINGS++))
278
- fi
279
-
280
- # 5. Validate skills
281
- log_info "Validating skills..."
282
-
283
- if [[ -d "$SKILLS_SRC" ]]; then
284
- for skill_dir in "$SKILLS_SRC"/*/; do
285
- [[ -d "$skill_dir" ]] || continue
286
-
287
- skill_name=$(basename "$skill_dir")
288
- skill_file="${skill_dir}SKILL.md"
289
-
290
- if [[ ! -f "$skill_file" ]]; then
291
- log_warn "Skill $skill_name: missing SKILL.md"
292
- ((WARNINGS++))
293
- continue
294
- fi
295
-
296
- for section in "Activation Contract" "Hard Rules" "Decision Gates" "Execution Steps" "Output Contract" "References"; do
297
- if ! grep -q "^## $section" "$skill_file"; then
298
- log_warn "Skill $skill_name: missing section '$section'"
299
- ((WARNINGS++))
300
- fi
301
- done
302
-
303
- if ! head -10 "$skill_file" | grep -q "^---$"; then
304
- log_warn "Skill $skill_name: missing frontmatter"
305
- ((WARNINGS++))
306
- fi
307
-
308
- log_info "Skill validated: $skill_name"
309
- done
310
- else
311
- log_warn "Skills source directory not found: $SKILLS_SRC"
312
- ((WARNINGS++))
313
- fi
314
-
315
- # 6. Validate MCP server definitions
316
- log_info "Validating MCP servers..."
317
-
318
- if [[ -d "$MCP_SRC" ]]; then
319
- for mcp_file in "$MCP_SRC"/*.mcp.json; do
320
- [[ -f "$mcp_file" ]] || continue
321
-
322
- mcp_name=$(basename "$mcp_file" .mcp.json)
323
-
324
- if ! command -v jq &> /dev/null; then
325
- log_warn "MCP $mcp_name: jq not available, skipping JSON validation"
326
- else
327
- if ! jq empty "$mcp_file" 2>/dev/null; then
328
- log_error "MCP $mcp_name: invalid JSON syntax"
329
- ((ISSUES++))
330
- continue
331
- fi
332
-
333
- name=$(jq -r '.name // empty' "$mcp_file")
334
- description=$(jq -r '.description // empty' "$mcp_file")
335
- transport=$(jq -r '.transport // empty' "$mcp_file")
336
-
337
- if [[ -z "$name" ]]; then
338
- log_error "MCP $mcp_name: missing 'name' field"
339
- ((ISSUES++))
340
- fi
341
- if [[ -z "$description" ]]; then
342
- log_error "MCP $mcp_name: missing 'description' field"
343
- ((ISSUES++))
344
- fi
345
- if [[ -z "$transport" ]]; then
346
- log_error "MCP $mcp_name: missing 'transport' field"
347
- ((ISSUES++))
348
- fi
349
-
350
- if [[ "$transport" == "stdio" ]]; then
351
- command=$(jq -r '.command // empty' "$mcp_file")
352
- if [[ -z "$command" ]]; then
353
- log_error "MCP $mcp_name: stdio transport requires 'command' field"
354
- ((ISSUES++))
355
- fi
356
- elif [[ "$transport" == "http" ]]; then
357
- url=$(jq -r '.url // empty' "$mcp_file")
358
- if [[ -z "$url" ]]; then
359
- log_error "MCP $mcp_name: http transport requires 'url' field"
360
- ((ISSUES++))
361
- fi
362
- else
363
- log_error "MCP $mcp_name: transport must be 'stdio' or 'http'"
364
- ((ISSUES++))
365
- fi
366
-
367
- if [[ -n "$name" ]] && ! [[ "$name" =~ ^[A-Za-z0-9_-]+$ ]]; then
368
- log_error "MCP $mcp_name: name must contain only letters, digits, _, and -"
369
- ((ISSUES++))
370
- fi
371
-
372
- if command -v jq &> /dev/null; then
373
- env_keys=$(jq -r '.env | keys[]' "$mcp_file" 2>/dev/null || true)
374
- for key in $env_keys; do
375
- value=$(jq -r ".env[\"$key\"]" "$mcp_file")
376
- if [[ -n "$value" ]] && ! [[ "$value" =~ ^\$\{ ]]; then
377
- key_lower=$(echo "$key" | tr '[:upper:]' '[:lower:]')
378
- if [[ "$key_lower" =~ (secret|token|key|password) ]]; then
379
- log_warn "MCP $mcp_name: env '$key' may contain hardcoded secret (use \${VAR} syntax)"
380
- ((WARNINGS++))
381
- fi
382
- fi
383
- done
384
- fi
385
-
386
- log_info "MCP validated: $mcp_name ($transport)"
387
- fi
388
- done
389
- else
390
- log_warn "MCP source directory not found: $MCP_SRC"
391
- ((WARNINGS++))
392
- fi
393
-
394
- # 7. Check for duplicate agent names
395
- log_info "Checking for conflicts..."
396
-
397
- GLOBAL_AGENTS_DIRS=("$AGENT_HOME/agents" "$AGENT_HOME/subagents")
398
- declare -A GLOBAL_AGENTS
399
-
400
- for dir in "${GLOBAL_AGENTS_DIRS[@]}"; do
401
- if [[ -d "$dir" ]]; then
402
- for file in "$dir"/*.md; do
403
- [[ -f "$file" ]] || continue
404
- name=$(basename "$file" .md)
405
- GLOBAL_AGENTS["$name"]="$dir"
406
- done
407
- fi
408
- done
409
-
410
- if [[ -d "$AGENTS_SRC" ]]; then
411
- for agent_file in "$AGENTS_SRC"/*.md; do
412
- [[ -f "$agent_file" ]] || continue
413
- agent_name=$(basename "$agent_file" .md)
414
- if [[ -n "${GLOBAL_AGENTS[$agent_name]:-}" ]]; then
415
- log_warn "Project agent '$agent_name' shadows global agent in ${GLOBAL_AGENTS[$agent_name]}"
416
- ((WARNINGS++))
417
- fi
418
- done
419
- fi
420
-
421
- # 8. Check overlay targets exist
422
- log_info "Checking overlay targets..."
423
- if [[ -d "$OVERLAYS_SRC" ]]; then
424
- for overlay_file in "$OVERLAYS_SRC"/*.overlay.md; do
425
- [[ -f "$overlay_file" ]] || continue
426
- target=$(grep "^target:" "$overlay_file" | head -1 | sed 's/^target: *//')
427
- target=$(echo "$target" | xargs)
428
-
429
- if [[ "$target" != "orchestrator" ]]; then
430
- target_exists=false
431
- if [[ -n "${GLOBAL_AGENTS[$target]:-}" ]]; then
432
- target_exists=true
433
- fi
434
- if [[ -f "$AGENTS_SRC/${target}.md" ]]; then
435
- target_exists=true
436
- fi
437
-
438
- if [[ "$target_exists" == "false" ]]; then
439
- log_warn "Overlay targets unknown agent: $target (from $(basename "$overlay_file"))"
440
- ((WARNINGS++))
441
- fi
442
- fi
443
- done
444
- fi
445
-
446
- # 9. Check MCP server name conflicts with mcp.json
447
- log_info "Checking MCP server name conflicts..."
448
- if [[ -d "$MCP_SRC" ]]; then
449
- # Check user-level mcp.json
450
- USER_MCP="${AGENT_HOME}/mcp.json"
451
- if [[ -f "$USER_MCP" ]] && command -v jq &> /dev/null; then
452
- for mcp_file in "$MCP_SRC"/*.mcp.json; do
453
- [[ -f "$mcp_file" ]] || continue
454
- name=$(jq -r '.name // empty' "$mcp_file")
455
- if [[ -n "$name" ]] && jq -e ".mcpServers[\"$name\"]" "$USER_MCP" >/dev/null 2>&1; then
456
- log_warn "MCP server '$name' also defined in user mcp.json (user config takes precedence)"
457
- ((WARNINGS++))
458
- fi
459
- done
460
- fi
461
-
462
- # Check project-level mcp.json
463
- PROJECT_MCP="${PROJECT_ROOT}/.pi/mcp.json"
464
- if [[ -f "$PROJECT_MCP" ]] && command -v jq &> /dev/null; then
465
- for mcp_file in "$MCP_SRC"/*.mcp.json; do
466
- [[ -f "$mcp_file" ]] || continue
467
- name=$(jq -r '.name // empty' "$mcp_file")
468
- if [[ -n "$name" ]] && jq -e ".mcpServers[\"$name\"]" "$PROJECT_MCP" >/dev/null 2>&1; then
469
- log_warn "MCP server '$name' also defined in project .pi/mcp.json (project config takes precedence)"
470
- ((WARNINGS++))
471
- fi
472
- done
473
- fi
474
- fi
475
-
476
- # 10. Verify extension is installed
477
- log_info "Verifying extension installation..."
478
- EXTENSION_TARGET="${AGENT_HOME_EXTENSIONS}/gentle-agent-extensions.ts"
479
- if [[ -f "$EXTENSION_TARGET" ]]; then
480
- log_success "Extension found at $EXTENSION_TARGET"
481
- else
482
- log_error "Extension not installed at $EXTENSION_TARGET"
483
- log_error "Run install.sh first"
484
- ((ISSUES++))
485
- fi
486
-
487
- # Summary
488
- echo ""
489
- log_info "=== Sync Summary ==="
490
- log_info "Changes made: $CHANGES"
491
- log_info "Issues found: $ISSUES"
492
- log_info "Warnings: $WARNINGS"
493
-
494
- if [[ "$DRY_RUN" == "true" ]]; then
495
- log_warn "DRY RUN - no actual changes made"
496
- fi
497
-
498
- if [[ "$CHECK_MODE" == "true" ]]; then
499
- if [[ $ISSUES -gt 0 ]]; then
500
- log_error "Check failed: $ISSUES issue(s) found"
501
- exit 1
502
- else
503
- log_success "Check passed"
504
- exit 0
505
- fi
506
- fi
507
-
508
- if [[ $ISSUES -gt 0 ]]; then
509
- log_error "Sync completed with $ISSUES issue(s)"
510
- exit 1
511
- fi
512
-
513
- log_success "Sync completed successfully"