create-mercato-app 0.6.7-develop.6553.1.2ec7246e04 → 0.6.7-develop.6565.1.1026d85fff
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/agentic/shared/AGENTS.md.template +1 -1
- package/agentic/shared/ai/skills/tiers.schema.json +15 -0
- package/agentic/shared/scripts/install-skills.sh +244 -37
- package/dist/agentic/guides/module-facts.json +53 -53
- package/dist/agentic/guides/modules/ai_assistant.md +1 -1
- package/dist/agentic/guides/modules/api_docs.md +1 -1
- package/dist/agentic/guides/modules/api_keys.md +1 -1
- package/dist/agentic/guides/modules/attachments.md +1 -1
- package/dist/agentic/guides/modules/audit_logs.md +1 -1
- package/dist/agentic/guides/modules/auth.md +1 -1
- package/dist/agentic/guides/modules/business_rules.md +1 -1
- package/dist/agentic/guides/modules/catalog.md +1 -1
- package/dist/agentic/guides/modules/channel_gmail.md +1 -1
- package/dist/agentic/guides/modules/channel_imap.md +1 -1
- package/dist/agentic/guides/modules/checkout.md +1 -1
- package/dist/agentic/guides/modules/communication_channels.md +1 -1
- package/dist/agentic/guides/modules/configs.md +1 -1
- package/dist/agentic/guides/modules/content.md +1 -1
- package/dist/agentic/guides/modules/currencies.md +1 -1
- package/dist/agentic/guides/modules/customer_accounts.md +1 -1
- package/dist/agentic/guides/modules/customers.md +1 -1
- package/dist/agentic/guides/modules/dashboards.md +1 -1
- package/dist/agentic/guides/modules/data_sync.md +1 -1
- package/dist/agentic/guides/modules/dictionaries.md +1 -1
- package/dist/agentic/guides/modules/directory.md +1 -1
- package/dist/agentic/guides/modules/entities.md +1 -1
- package/dist/agentic/guides/modules/events.md +1 -1
- package/dist/agentic/guides/modules/feature_toggles.md +1 -1
- package/dist/agentic/guides/modules/gateway_stripe.md +1 -1
- package/dist/agentic/guides/modules/generators.md +1 -1
- package/dist/agentic/guides/modules/inbox_ops.md +1 -1
- package/dist/agentic/guides/modules/integrations.md +1 -1
- package/dist/agentic/guides/modules/messages.md +1 -1
- package/dist/agentic/guides/modules/notifications.md +1 -1
- package/dist/agentic/guides/modules/onboarding.md +1 -1
- package/dist/agentic/guides/modules/payment_gateways.md +1 -1
- package/dist/agentic/guides/modules/perspectives.md +1 -1
- package/dist/agentic/guides/modules/planner.md +1 -1
- package/dist/agentic/guides/modules/portal.md +1 -1
- package/dist/agentic/guides/modules/progress.md +1 -1
- package/dist/agentic/guides/modules/query_index.md +1 -1
- package/dist/agentic/guides/modules/record_locks.md +1 -1
- package/dist/agentic/guides/modules/resources.md +1 -1
- package/dist/agentic/guides/modules/sales.md +1 -1
- package/dist/agentic/guides/modules/scheduler.md +1 -1
- package/dist/agentic/guides/modules/search.md +1 -1
- package/dist/agentic/guides/modules/security.md +1 -1
- package/dist/agentic/guides/modules/shipping_carriers.md +1 -1
- package/dist/agentic/guides/modules/sso.md +1 -1
- package/dist/agentic/guides/modules/staff.md +1 -1
- package/dist/agentic/guides/modules/storage_s3.md +1 -1
- package/dist/agentic/guides/modules/sync_akeneo.md +1 -1
- package/dist/agentic/guides/modules/sync_excel.md +1 -1
- package/dist/agentic/guides/modules/system_status_overlays.md +1 -1
- package/dist/agentic/guides/modules/translations.md +1 -1
- package/dist/agentic/guides/modules/webhooks.md +1 -1
- package/dist/agentic/guides/modules/workflows.md +1 -1
- package/dist/agentic/shared/AGENTS.md.template +1 -1
- package/dist/agentic/shared/ai/skills/tiers.schema.json +15 -0
- package/dist/agentic/shared/scripts/install-skills.sh +244 -37
- package/dist/index.js +22 -30
- package/package.json +3 -3
- package/template/AGENTS.md +1 -1
- package/template/scripts/dev-orchestration-log-policy.mjs +1 -0
- package/template/scripts/dev-runtime-log-policy.mjs +29 -10
- package/template/src/i18n/de.json +1 -0
- package/template/src/i18n/en.json +1 -0
- package/template/src/i18n/es.json +1 -0
- package/template/src/i18n/pl.json +1 -0
|
@@ -68,7 +68,7 @@ These per-module fact-sheets are **generated from source** and bundled for the m
|
|
|
68
68
|
|
|
69
69
|
### Skills: local + shared collection
|
|
70
70
|
|
|
71
|
-
Skills come from two places. Repo-local skills (module scaffolding, UI design, troubleshooting, etc.) ship inside `.ai/skills/` and are installed
|
|
71
|
+
Skills come from two places. Repo-local skills (module scaffolding, UI design, troubleshooting, etc.) ship inside `.ai/skills/` and are installed by tier (see `.ai/skills/tiers.json`). The PR-automation and review skills below are maintained in the shared [open-mercato/skills](https://github.com/open-mercato/skills) collection — run **`yarn install-skills`** once to install the subset this app ships (`npx skills add`, then `npx skills update` on re-runs to refresh). Both sources install into the canonical cross-agent directory **`.agents/skills/`**; Codex and Cursor read it natively, while Claude Code — which cannot — additionally gets per-skill symlinks under `.claude/skills/`. The tables below therefore **reference external skills by name, not by a hard-coded harness path**: the directory depends on which agent you scaffolded, and pointing every reader at `.claude/skills/…` would mislead a Codex or Cursor scaffold. A folder under `.ai/skills/<name>/` matching an external skill is a repo-local **override** that the external skill reads on top of its built-in workflow (default-branch discovery, opt-in labels, `src/modules/…` layout). Repo-specific settings live in `.ai/agentic.config.json` and the tracker descriptor `.ai/trackers/github.md`.
|
|
72
72
|
|
|
73
73
|
### Quality & Process
|
|
74
74
|
|
|
@@ -19,6 +19,21 @@
|
|
|
19
19
|
},
|
|
20
20
|
"description": "Tier names installed when install-skills.sh is invoked with no flags."
|
|
21
21
|
},
|
|
22
|
+
"agents": {
|
|
23
|
+
"type": "object",
|
|
24
|
+
"additionalProperties": false,
|
|
25
|
+
"description": "Agent harness settings for install-skills.sh. Skills always install into the canonical .agents/skills/ directory; per-agent symlinks are created only for agents that cannot read it.",
|
|
26
|
+
"properties": {
|
|
27
|
+
"ignore": {
|
|
28
|
+
"type": "array",
|
|
29
|
+
"description": "Agents whose directories install-skills.sh must never write. Overridden by --ignore-agents.",
|
|
30
|
+
"items": {
|
|
31
|
+
"type": "string",
|
|
32
|
+
"enum": ["claude-code", "codex", "cursor"]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
22
37
|
"external": {
|
|
23
38
|
"type": "object",
|
|
24
39
|
"additionalProperties": false,
|
|
@@ -1,21 +1,34 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
set -eu
|
|
3
3
|
|
|
4
|
-
# Skill installer for a standalone Open Mercato app
|
|
5
|
-
#
|
|
4
|
+
# Skill installer for a standalone Open Mercato app. Skills live in ONE
|
|
5
|
+
# canonical place — the cross-agent directory .agents/skills/ — and two sources
|
|
6
|
+
# are mixed into it:
|
|
6
7
|
#
|
|
7
|
-
# 1. Local tiered skills: reads .ai/skills/tiers.json and
|
|
8
|
-
#
|
|
9
|
-
# directory-level
|
|
10
|
-
#
|
|
8
|
+
# 1. Local tiered skills: reads .ai/skills/tiers.json and symlinks each
|
|
9
|
+
# selected skill into .agents/skills/<name> -> ../../.ai/skills/<name>.
|
|
10
|
+
# Legacy directory-level symlinks (e.g. .claude/skills -> ../.ai/skills)
|
|
11
|
+
# left by an older scaffold are cleaned up.
|
|
11
12
|
# 2. External shared skills: installs the subset this app ships from the
|
|
12
|
-
# open-mercato/skills collection via `npx skills add` into
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# skill
|
|
18
|
-
#
|
|
13
|
+
# open-mercato/skills collection via `npx skills add` into the same
|
|
14
|
+
# .agents/skills/ directory, then `npx skills update` so a re-run refreshes
|
|
15
|
+
# them to the latest published versions. The external source + explicit
|
|
16
|
+
# skill list live under `external` in tiers.json. A folder under .ai/skills/
|
|
17
|
+
# matching an external skill name is a repo-local override the external
|
|
18
|
+
# skill reads in place; it is never symlinked into the canonical or
|
|
19
|
+
# per-agent directories.
|
|
20
|
+
#
|
|
21
|
+
# Agent support matrix. Per-agent symlinks are created ONLY for agents that
|
|
22
|
+
# cannot read the canonical project-level .agents/skills/ directory:
|
|
23
|
+
#
|
|
24
|
+
# agent id project directory reads .agents/skills/ per-agent symlinks
|
|
25
|
+
# claude-code .claude/skills no yes (written by this script)
|
|
26
|
+
# codex .codex/skills yes no
|
|
27
|
+
# cursor .cursor/skills yes no
|
|
28
|
+
#
|
|
29
|
+
# The "reads .agents/skills/" column follows the universal-agent list of the
|
|
30
|
+
# `skills` CLI (vercel-labs/skills). An agent that cannot read the canonical
|
|
31
|
+
# directory MUST keep its symlinks, or its skills silently disappear.
|
|
19
32
|
#
|
|
20
33
|
# The scaffold is offline: `npx skills add`/`update` only run when you invoke
|
|
21
34
|
# this script (yarn install-skills). Pass --no-external (or set
|
|
@@ -26,6 +39,8 @@ set -eu
|
|
|
26
39
|
# install-skills.sh --with <csv> # default + extra tiers (additive)
|
|
27
40
|
# install-skills.sh --tiers <csv> # exactly the listed tiers (replaces default)
|
|
28
41
|
# install-skills.sh --all # every tier
|
|
42
|
+
# install-skills.sh --legacy-links # also symlink every skill into .claude/skills/ and .codex/skills/
|
|
43
|
+
# install-skills.sh --ignore-agents <csv> # never write these agents' directories
|
|
29
44
|
# install-skills.sh --no-external # skip the npx external-skills install/update step (offline)
|
|
30
45
|
# install-skills.sh --list # print tier table and exit
|
|
31
46
|
# install-skills.sh --clean # remove all skill symlinks and exit
|
|
@@ -37,10 +52,19 @@ Usage: install-skills.sh [options]
|
|
|
37
52
|
|
|
38
53
|
Options:
|
|
39
54
|
(no options) Install the default tier set from .ai/skills/tiers.json
|
|
40
|
-
plus the external open-mercato/skills subset this app ships
|
|
55
|
+
plus the external open-mercato/skills subset this app ships
|
|
56
|
+
into the canonical .agents/skills/ directory. Agents that
|
|
57
|
+
cannot read it (Claude Code) also get per-skill symlinks.
|
|
41
58
|
--with <csv> Install default tiers plus the given tier names (additive).
|
|
42
59
|
--tiers <csv> Install exactly the given tier names (replaces default).
|
|
43
60
|
--all Install every tier defined in tiers.json.
|
|
61
|
+
--legacy-links Restore the pre-canonical layout: symlink every skill into
|
|
62
|
+
.claude/skills/ AND .codex/skills/, even for agents that
|
|
63
|
+
read .agents/skills/ natively.
|
|
64
|
+
--ignore-agents <csv>
|
|
65
|
+
Never write these agents' directories (claude-code, codex,
|
|
66
|
+
cursor). Defaults to `agents.ignore` in tiers.json; this
|
|
67
|
+
flag overrides it.
|
|
44
68
|
--no-external Skip the external-collection step — `npx skills add` on
|
|
45
69
|
first run and `npx skills update` on re-runs (also:
|
|
46
70
|
OM_SKIP_EXTERNAL_SKILLS=1). Use when offline.
|
|
@@ -91,6 +115,9 @@ with_csv=""
|
|
|
91
115
|
tiers_csv=""
|
|
92
116
|
list_only=0
|
|
93
117
|
clean_only=0
|
|
118
|
+
legacy_links=0
|
|
119
|
+
ignore_agents_csv=""
|
|
120
|
+
ignore_agents_set=0
|
|
94
121
|
# Any non-empty value other than "0" skips the external npx step.
|
|
95
122
|
case "${OM_SKIP_EXTERNAL_SKILLS:-0}" in
|
|
96
123
|
""|0) no_external=0 ;;
|
|
@@ -125,6 +152,24 @@ while [ $# -gt 0 ]; do
|
|
|
125
152
|
no_external=1
|
|
126
153
|
shift
|
|
127
154
|
;;
|
|
155
|
+
--legacy-links)
|
|
156
|
+
legacy_links=1
|
|
157
|
+
shift
|
|
158
|
+
;;
|
|
159
|
+
--ignore-agents)
|
|
160
|
+
if [ $# -lt 2 ]; then
|
|
161
|
+
echo "install-skills: --ignore-agents requires a comma-separated list of agent ids." >&2
|
|
162
|
+
exit 1
|
|
163
|
+
fi
|
|
164
|
+
ignore_agents_csv="$2"
|
|
165
|
+
ignore_agents_set=1
|
|
166
|
+
shift 2
|
|
167
|
+
;;
|
|
168
|
+
--ignore-agents=*)
|
|
169
|
+
ignore_agents_csv="${1#--ignore-agents=}"
|
|
170
|
+
ignore_agents_set=1
|
|
171
|
+
shift
|
|
172
|
+
;;
|
|
128
173
|
--all)
|
|
129
174
|
set_mode all
|
|
130
175
|
shift
|
|
@@ -206,6 +251,96 @@ dedup_lines() {
|
|
|
206
251
|
|
|
207
252
|
agents_dir="${repo_root}/.agents/skills"
|
|
208
253
|
|
|
254
|
+
# See the agent support matrix in the header comment.
|
|
255
|
+
known_agents="claude-code codex cursor"
|
|
256
|
+
legacy_agents="claude-code codex"
|
|
257
|
+
|
|
258
|
+
agent_dir() {
|
|
259
|
+
case "$1" in
|
|
260
|
+
claude-code) printf '%s' "${repo_root}/.claude/skills" ;;
|
|
261
|
+
codex) printf '%s' "${repo_root}/.codex/skills" ;;
|
|
262
|
+
cursor) printf '%s' "${repo_root}/.cursor/skills" ;;
|
|
263
|
+
esac
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
agent_reads_canonical() {
|
|
267
|
+
case "$1" in
|
|
268
|
+
codex|cursor) return 0 ;;
|
|
269
|
+
*) return 1 ;;
|
|
270
|
+
esac
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
agent_known() {
|
|
274
|
+
needle="$1"
|
|
275
|
+
for candidate in ${known_agents}; do
|
|
276
|
+
if [ "${candidate}" = "${needle}" ]; then
|
|
277
|
+
return 0
|
|
278
|
+
fi
|
|
279
|
+
done
|
|
280
|
+
return 1
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
is_legacy_agent() {
|
|
284
|
+
needle="$1"
|
|
285
|
+
for candidate in ${legacy_agents}; do
|
|
286
|
+
if [ "${candidate}" = "${needle}" ]; then
|
|
287
|
+
return 0
|
|
288
|
+
fi
|
|
289
|
+
done
|
|
290
|
+
return 1
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
# The CLI flag overrides `agents.ignore` in tiers.json.
|
|
294
|
+
if [ "${ignore_agents_set}" -eq 1 ]; then
|
|
295
|
+
ignored_agents=$(split_csv "${ignore_agents_csv}")
|
|
296
|
+
else
|
|
297
|
+
ignored_agents=$(jq -r '.agents.ignore[]?' "${manifest}")
|
|
298
|
+
fi
|
|
299
|
+
|
|
300
|
+
for agent in ${ignored_agents}; do
|
|
301
|
+
if ! agent_known "${agent}"; then
|
|
302
|
+
echo "install-skills: unknown agent '${agent}'." >&2
|
|
303
|
+
echo " Valid agents: $(printf '%s' "${known_agents}")" >&2
|
|
304
|
+
exit 1
|
|
305
|
+
fi
|
|
306
|
+
done
|
|
307
|
+
|
|
308
|
+
is_ignored_agent() {
|
|
309
|
+
needle="$1"
|
|
310
|
+
for candidate in ${ignored_agents}; do
|
|
311
|
+
if [ "${candidate}" = "${needle}" ]; then
|
|
312
|
+
return 0
|
|
313
|
+
fi
|
|
314
|
+
done
|
|
315
|
+
return 1
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
# Agents that get their own per-skill symlinks: in the default layout only the
|
|
319
|
+
# ones that cannot read .agents/skills/; with --legacy-links the historical pair.
|
|
320
|
+
link_agents=""
|
|
321
|
+
for agent in ${known_agents}; do
|
|
322
|
+
if is_ignored_agent "${agent}"; then
|
|
323
|
+
continue
|
|
324
|
+
fi
|
|
325
|
+
if [ "${legacy_links}" -eq 1 ]; then
|
|
326
|
+
if is_legacy_agent "${agent}"; then
|
|
327
|
+
link_agents="${link_agents} ${agent}"
|
|
328
|
+
fi
|
|
329
|
+
elif ! agent_reads_canonical "${agent}"; then
|
|
330
|
+
link_agents="${link_agents} ${agent}"
|
|
331
|
+
fi
|
|
332
|
+
done
|
|
333
|
+
|
|
334
|
+
is_link_agent() {
|
|
335
|
+
needle="$1"
|
|
336
|
+
for candidate in ${link_agents}; do
|
|
337
|
+
if [ "${candidate}" = "${needle}" ]; then
|
|
338
|
+
return 0
|
|
339
|
+
fi
|
|
340
|
+
done
|
|
341
|
+
return 1
|
|
342
|
+
}
|
|
343
|
+
|
|
209
344
|
resolves_into_skills_dir() {
|
|
210
345
|
link_path="$1"
|
|
211
346
|
resolved=$(readlink -f -- "${link_path}" 2>/dev/null || true)
|
|
@@ -288,6 +423,18 @@ sweep_harness() {
|
|
|
288
423
|
done
|
|
289
424
|
}
|
|
290
425
|
|
|
426
|
+
# Drop links to skills the external collection no longer ships: their target
|
|
427
|
+
# under .agents/skills/ is gone, so the link dangles.
|
|
428
|
+
prune_broken_links() {
|
|
429
|
+
harness_dir="$1"
|
|
430
|
+
[ -d "${harness_dir}" ] || return 0
|
|
431
|
+
for entry in "${harness_dir}"/*; do
|
|
432
|
+
[ -L "${entry}" ] || continue
|
|
433
|
+
[ -e "${entry}" ] && continue
|
|
434
|
+
rm -f "${entry}"
|
|
435
|
+
done
|
|
436
|
+
}
|
|
437
|
+
|
|
291
438
|
print_list() {
|
|
292
439
|
for tier in ${all_tier_names}; do
|
|
293
440
|
count=$(tier_skill_count "${tier}")
|
|
@@ -316,13 +463,16 @@ if [ "${list_only}" -eq 1 ]; then
|
|
|
316
463
|
fi
|
|
317
464
|
|
|
318
465
|
if [ "${clean_only}" -eq 1 ]; then
|
|
319
|
-
|
|
320
|
-
|
|
466
|
+
# Sweep every known agent directory (both the canonical link layer and any
|
|
467
|
+
# leftovers from the legacy per-agent layout), then the canonical directory.
|
|
468
|
+
for agent in ${known_agents}; do
|
|
469
|
+
clean_harness "$(agent_dir "${agent}")"
|
|
470
|
+
done
|
|
321
471
|
if [ -d "${agents_dir}" ]; then
|
|
322
472
|
rm -rf "${agents_dir}"
|
|
323
|
-
echo "info: removed
|
|
473
|
+
echo "info: removed skills under .agents/skills/."
|
|
324
474
|
fi
|
|
325
|
-
echo "info: removed all skill symlinks under .claude/skills/ and .
|
|
475
|
+
echo "info: removed all skill symlinks under .claude/skills/, .codex/skills/ and .cursor/skills/."
|
|
326
476
|
exit 0
|
|
327
477
|
fi
|
|
328
478
|
|
|
@@ -403,9 +553,9 @@ is_external_skill() {
|
|
|
403
553
|
return 1
|
|
404
554
|
}
|
|
405
555
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
prepare_harness_dir "${
|
|
556
|
+
# Local tier skills live once, in the canonical cross-agent directory.
|
|
557
|
+
install_canonical() {
|
|
558
|
+
prepare_harness_dir "${agents_dir}"
|
|
409
559
|
for skill in ${selected_skills}; do
|
|
410
560
|
if is_external_skill "${skill}"; then
|
|
411
561
|
# Owned by the external collection; a same-named .ai/skills/ folder is a
|
|
@@ -418,19 +568,59 @@ install_into_harness() {
|
|
|
418
568
|
echo "install-skills: skill folder '${skill_target}' is missing on disk." >&2
|
|
419
569
|
exit 1
|
|
420
570
|
fi
|
|
421
|
-
|
|
422
|
-
ln -sfn "../../.ai/skills/${skill}" "${link_path}"
|
|
571
|
+
ln -sfn "../../.ai/skills/${skill}" "${agents_dir}/${skill}"
|
|
423
572
|
done
|
|
573
|
+
sweep_harness "${agents_dir}" "${selected_skills}"
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
# Link layer for agents that cannot read the canonical directory. External
|
|
577
|
+
# skills are linked by the skills CLI itself (via the --agent args below), so
|
|
578
|
+
# only the local tier skills are linked here.
|
|
579
|
+
install_agent_links() {
|
|
580
|
+
agent="$1"
|
|
581
|
+
harness_dir=$(agent_dir "${agent}")
|
|
582
|
+
prepare_harness_dir "${harness_dir}"
|
|
583
|
+
for skill in ${selected_skills}; do
|
|
584
|
+
if is_external_skill "${skill}"; then
|
|
585
|
+
continue
|
|
586
|
+
fi
|
|
587
|
+
if [ "${legacy_links}" -eq 1 ]; then
|
|
588
|
+
ln -sfn "../../.ai/skills/${skill}" "${harness_dir}/${skill}"
|
|
589
|
+
else
|
|
590
|
+
ln -sfn "../../.agents/skills/${skill}" "${harness_dir}/${skill}"
|
|
591
|
+
fi
|
|
592
|
+
done
|
|
593
|
+
link_external_skills "${harness_dir}"
|
|
424
594
|
sweep_harness "${harness_dir}" "${selected_skills}"
|
|
595
|
+
prune_broken_links "${harness_dir}"
|
|
425
596
|
}
|
|
426
597
|
|
|
427
|
-
|
|
428
|
-
|
|
598
|
+
# Mirror every external skill (a real directory under the canonical dir) into an
|
|
599
|
+
# agent's own directory. Local tier skills are symlinks and are skipped here.
|
|
600
|
+
#
|
|
601
|
+
# `npx skills add --agent <id>` is supposed to write these links itself, but it
|
|
602
|
+
# only does so reliably for an agent directory that already exists (see
|
|
603
|
+
# vercel-labs/skills#744) and the canonical layout no longer pre-creates one. So
|
|
604
|
+
# the script owns this layer end to end: an agent that cannot read
|
|
605
|
+
# .agents/skills/ would otherwise silently lose the whole shared collection.
|
|
606
|
+
link_external_skills() {
|
|
607
|
+
harness_dir="$1"
|
|
608
|
+
[ -d "${agents_dir}" ] || return 0
|
|
609
|
+
for entry in "${agents_dir}"/*; do
|
|
610
|
+
[ -L "${entry}" ] && continue
|
|
611
|
+
[ -d "${entry}" ] || continue
|
|
612
|
+
external_name=$(basename "${entry}")
|
|
613
|
+
ln -sfn "../../.agents/skills/${external_name}" "${harness_dir}/${external_name}"
|
|
614
|
+
done
|
|
615
|
+
}
|
|
429
616
|
|
|
430
617
|
# Mix in the external shared collection (open-mercato/skills). Only the explicit
|
|
431
618
|
# subset this app ships (external.skills) is installed — never the whole
|
|
432
|
-
# collection. The npx CLI copies each skill into .agents/skills
|
|
433
|
-
#
|
|
619
|
+
# collection. The npx CLI copies each skill into .agents/skills/. This runs BEFORE
|
|
620
|
+
# the link layer is written: `skills update --project` owns .agents/skills/ and
|
|
621
|
+
# would otherwise prune entries it does not know about. The agent directories are
|
|
622
|
+
# written afterwards by install_agent_links, which does not rely on the CLI's own
|
|
623
|
+
# symlinking.
|
|
434
624
|
external_source=$(jq -r '.external.source // empty' "${manifest}")
|
|
435
625
|
external_status="none"
|
|
436
626
|
# The skills CLI matches each --skill value against skill names verbatim (no
|
|
@@ -439,13 +629,21 @@ external_skill_args=""
|
|
|
439
629
|
for external_skill in $(printf '%s\n' "${external_skills_list}" | dedup_lines); do
|
|
440
630
|
external_skill_args="${external_skill_args} --skill ${external_skill}"
|
|
441
631
|
done
|
|
632
|
+
external_agent_args=""
|
|
633
|
+
for agent in ${link_agents}; do
|
|
634
|
+
external_agent_args="${external_agent_args} --agent ${agent}"
|
|
635
|
+
done
|
|
636
|
+
if [ -z "${external_agent_args}" ]; then
|
|
637
|
+
# No agent needs its own directory — install into .agents/skills/ only.
|
|
638
|
+
external_agent_args=" --agent universal"
|
|
639
|
+
fi
|
|
442
640
|
if [ -n "${external_source}" ] && [ -n "${external_skill_args}" ]; then
|
|
443
641
|
if [ "${no_external}" = "1" ]; then
|
|
444
642
|
external_status="skipped (--no-external)"
|
|
445
643
|
elif ! command -v npx >/dev/null 2>&1; then
|
|
446
644
|
external_status="skipped (npx not found)"
|
|
447
645
|
echo "install-skills: warning: npx not found; skipping external skills from ${external_source}." >&2
|
|
448
|
-
elif (cd "${repo_root}" && npx -y skills add "${external_source}" ${external_skill_args}
|
|
646
|
+
elif (cd "${repo_root}" && npx -y skills add "${external_source}" ${external_skill_args} ${external_agent_args} -y); then
|
|
449
647
|
external_status="installed from ${external_source}"
|
|
450
648
|
# `add` seeds the subset; a follow-up `update` bumps already-installed skills
|
|
451
649
|
# to the latest published versions on a re-run. Non-fatal when offline mid-run.
|
|
@@ -455,15 +653,6 @@ if [ -n "${external_source}" ] && [ -n "${external_skill_args}" ]; then
|
|
|
455
653
|
echo "install-skills: warning: could not update external skills to latest;" >&2
|
|
456
654
|
echo " the installed versions are kept. Re-run when online to refresh." >&2
|
|
457
655
|
fi
|
|
458
|
-
# The npx CLI symlinks .claude/skills/<name> itself and expects Codex to read
|
|
459
|
-
# .agents/skills/ natively; mirror the symlinks into .codex/skills/ too.
|
|
460
|
-
if [ -d "${agents_dir}" ]; then
|
|
461
|
-
mkdir -p "${repo_root}/.codex/skills"
|
|
462
|
-
for external_entry in "${agents_dir}"/*; do
|
|
463
|
-
[ -d "${external_entry}" ] || continue
|
|
464
|
-
ln -sfn "../../.agents/skills/$(basename "${external_entry}")" "${repo_root}/.codex/skills/$(basename "${external_entry}")"
|
|
465
|
-
done
|
|
466
|
-
fi
|
|
467
656
|
else
|
|
468
657
|
external_status="FAILED"
|
|
469
658
|
echo "install-skills: warning: installing external skills from ${external_source} failed;" >&2
|
|
@@ -471,6 +660,18 @@ if [ -n "${external_source}" ] && [ -n "${external_skill_args}" ]; then
|
|
|
471
660
|
fi
|
|
472
661
|
fi
|
|
473
662
|
|
|
663
|
+
install_canonical
|
|
664
|
+
|
|
665
|
+
for agent in ${known_agents}; do
|
|
666
|
+
if is_link_agent "${agent}"; then
|
|
667
|
+
install_agent_links "${agent}"
|
|
668
|
+
else
|
|
669
|
+
# Not a link target (reads the canonical directory, or ignored): drop any
|
|
670
|
+
# stale symlinks left behind by the legacy per-agent layout.
|
|
671
|
+
clean_harness "$(agent_dir "${agent}")"
|
|
672
|
+
fi
|
|
673
|
+
done
|
|
674
|
+
|
|
474
675
|
skill_count=$(printf '%s\n' "${selected_skills}" | grep -c '.' || true)
|
|
475
676
|
tier_count=$(printf '%s\n' "${selected_tiers}" | grep -c '.' || true)
|
|
476
677
|
tier_summary=$(printf '%s\n' "${selected_tiers}" | tr '\n' ',' | sed 's/,$//' | sed 's/,/, /g')
|
|
@@ -479,6 +680,12 @@ printf 'Installed %s local skills across %s tiers: %s.\n' "${skill_count}" "${ti
|
|
|
479
680
|
if [ "${external_status}" != "none" ]; then
|
|
480
681
|
printf 'External skills: %s.\n' "${external_status}"
|
|
481
682
|
fi
|
|
683
|
+
link_summary=$(printf '%s' "${link_agents}" | sed 's/^ *//; s/ /, /g')
|
|
684
|
+
if [ -z "${link_summary}" ]; then
|
|
685
|
+
printf 'Layout: .agents/skills/ (canonical); no per-agent symlinks.\n'
|
|
686
|
+
else
|
|
687
|
+
printf 'Layout: .agents/skills/ (canonical); per-agent symlinks: %s.\n' "${link_summary}"
|
|
688
|
+
fi
|
|
482
689
|
|
|
483
690
|
if [ -z "${mode}" ]; then
|
|
484
691
|
cat <<'EOF'
|