Skip to content

Commit 0e306ff

Browse files
[sync] Package agents payloads and relative links (#188) (#194)
* [sync] Package agents payloads and relative links (#188) * Update wiki submodule pointer for PR #194 --------- Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 0fe9938 commit 0e306ff

15 files changed

Lines changed: 143 additions & 32 deletions

.gitattributes

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
* text=auto
2-
/.github/ export-ignore
3-
/.vscode/ export-ignore
4-
/docs/ export-ignore
5-
/tests/ export-ignore
6-
/.agents/agents/ export-ignore
7-
/.gitattributes export-ignore
8-
/.gitmodules export-ignore
9-
/AGENTS.md export-ignore
10-
/context7.json export-ignore
11-
/README.md export-ignore
1+
* text=auto
2+
/.github/ export-ignore
3+
/.vscode/ export-ignore
4+
/docs/ export-ignore
5+
/tests/ export-ignore
6+
/.gitattributes export-ignore
7+
/.gitmodules export-ignore
8+
/.phpunit.result.cache export-ignore
9+
/AGENTS.md export-ignore
10+
/CODE_OF_CONDUCT.md export-ignore
11+
/context7.json export-ignore
12+
/CONTRIBUTING.md export-ignore
13+
/README.md export-ignore
14+
/SECURITY.md export-ignore
15+
/SUPPORT.md export-ignore

.github/wiki

Submodule wiki updated from 79fb0c2 to 0e04846

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515
- Auto-create and push minimal changelog entries for same-repository Dependabot pull requests before changelog validation reruns (#186)
1616
- Resolve Dependabot changelog fallback state from the actual PR head branch and report `already-present`, `auto-created`, or `missing` in the workflow summary so rebased PRs cannot pass on inherited `Unreleased` entries alone (#191)
1717

18+
### Fixed
19+
20+
- Keep packaged `.agents` payloads exportable and synchronize packaged skills and agents with repository-relative symlink targets so consumer repositories no longer receive broken absolute machine paths (#188)
21+
1822
## [1.20.0] - 2026-04-23
1923

2024
### Changed

docs/commands/agents.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ Description
77
-----------
88

99
The ``agents`` command synchronizes packaged project-agent prompts into the
10-
consumer repository's ``.agents/agents`` directory using symlinks.
10+
consumer repository's ``.agents/agents`` directory using repository-relative
11+
symlinks.
1112

1213
Usage
1314
-----
@@ -54,7 +55,7 @@ Behavior
5455

5556
- Verifies the packaged ``.agents/agents`` directory before doing any work.
5657
- Creates the consumer ``.agents/agents`` directory when missing.
57-
- Creates missing symlinks to packaged project agents.
58+
- Creates missing repository-relative symlinks to packaged project agents.
5859
- Repairs broken symlinks.
5960
- Preserves an existing non-symlink directory instead of overwriting it.
6061
- Reuses the same generic packaged-directory synchronizer as ``skills`` so

docs/commands/skills.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Description
77
-----------
88

99
The ``skills`` command synchronizes packaged agent skills into the consumer
10-
repository's ``.agents/skills`` directory using symlinks.
10+
repository's ``.agents/skills`` directory using repository-relative symlinks.
1111

1212
Usage
1313
-----
@@ -54,6 +54,6 @@ Behavior
5454

5555
- Verifies the packaged ``.agents/skills`` directory before doing any work.
5656
- Creates the consumer ``.agents/skills`` directory when missing.
57-
- Creates missing symlinks to packaged skills.
57+
- Creates missing repository-relative symlinks to packaged skills.
5858
- Repairs broken symlinks.
5959
- Preserves an existing non-symlink directory instead of overwriting it.

docs/usage/syncing-packaged-agents.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Why This Command Exists
1111
Fast Forward libraries can share role-based project agents without copying
1212
prompt files into every consumer repository. The packaged agent directories
1313
live in this repository, while consumer repositories receive lightweight
14-
symlinks that point back to the packaged source.
14+
repository-relative symlinks that point back to the packaged source.
1515

1616
That approach keeps upgrades simple:
1717

@@ -38,7 +38,8 @@ What the Command Does
3838
* - ``.agents/agents`` is missing
3939
- Creates the directory in the consumer repository.
4040
* - A packaged agent is missing locally
41-
- Creates a symlink that points to the packaged agent directory.
41+
- Creates a repository-relative symlink that points to the packaged
42+
agent directory.
4243
* - A valid symlink already exists
4344
- Leaves the link unchanged.
4445
* - A symlink is broken

docs/usage/syncing-packaged-skills.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ Why This Command Exists
1010

1111
Fast Forward libraries can share agent skills without copying them into every
1212
consumer repository. The packaged skill directories live in this repository,
13-
while consumer repositories receive lightweight symlinks that point back to the
14-
packaged source.
13+
while consumer repositories receive lightweight repository-relative symlinks
14+
that point back to the packaged source.
1515

1616
That approach keeps upgrades simple:
1717

@@ -38,7 +38,8 @@ What the Command Does
3838
* - ``.agents/skills`` is missing
3939
- Creates the directory in the consumer repository.
4040
* - A packaged skill is missing locally
41-
- Creates a symlink that points to the packaged skill directory.
41+
- Creates a repository-relative symlink that points to the packaged skill
42+
directory.
4243
* - A valid symlink already exists
4344
- Leaves the link unchanged.
4445
* - A symlink is broken

src/GitAttributes/ExportIgnoreFilter.php

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ final class ExportIgnoreFilter implements ExportIgnoreFilterInterface
4040
*/
4141
public function filter(array $candidates, array $keepInExportPaths): array
4242
{
43-
$keptPathLookup = [];
43+
$keptPaths = [];
4444

4545
foreach ($keepInExportPaths as $path) {
4646
$normalizedPath = $this->normalizePath($path);
@@ -49,15 +49,30 @@ public function filter(array $candidates, array $keepInExportPaths): array
4949
continue;
5050
}
5151

52-
$keptPathLookup[$normalizedPath] = true;
52+
$keptPaths[] = $normalizedPath;
5353
}
5454

5555
return array_values(array_filter(
5656
$candidates,
57-
fn(string $candidate): bool => ! isset($keptPathLookup[$this->normalizePath($candidate)])
57+
fn(string $candidate): bool => ! $this->isKeptPath($this->normalizePath($candidate), $keptPaths)
5858
));
5959
}
6060

61+
/**
62+
* @param string $candidate
63+
* @param list<string> $keptPaths
64+
*/
65+
private function isKeptPath(string $candidate, array $keptPaths): bool
66+
{
67+
foreach ($keptPaths as $keptPath) {
68+
if ($candidate === $keptPath || str_starts_with($candidate . '/', $keptPath . '/')) {
69+
return true;
70+
}
71+
}
72+
73+
return false;
74+
}
75+
6176
/**
6277
* Normalizes a configured path for stable matching.
6378
*

src/GitAttributes/Merger.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public function merge(string $existingContent, array $exportIgnoreEntries, array
7777
}
7878

7979
$pathKey = $this->normalizePathKey($pathSpec);
80-
if (isset($keptExportLookup[$pathKey])) {
80+
if ($this->isKeptPath($pathKey, $keptExportLookup)) {
8181
continue;
8282
}
8383

@@ -96,7 +96,7 @@ public function merge(string $existingContent, array $exportIgnoreEntries, array
9696
$trimmedEntry = trim($entry);
9797
$pathKey = $this->normalizePathKey($trimmedEntry);
9898

99-
if (isset($keptExportLookup[$pathKey])) {
99+
if ($this->isKeptPath($pathKey, $keptExportLookup)) {
100100
continue;
101101
}
102102

@@ -188,6 +188,21 @@ private function keepInExportLookup(array $keepInExportPaths): array
188188
return $lookup;
189189
}
190190

191+
/**
192+
* @param string $pathKey
193+
* @param array<string, true> $keptExportLookup
194+
*/
195+
private function isKeptPath(string $pathKey, array $keptExportLookup): bool
196+
{
197+
foreach ($keptExportLookup as $keptPath => $_) {
198+
if ($pathKey === $keptPath || str_starts_with($pathKey . '/', $keptPath . '/')) {
199+
return true;
200+
}
201+
}
202+
203+
return false;
204+
}
205+
191206
/**
192207
* Builds a lookup table of generated directory candidates.
193208
*

src/GitAttributes/Writer.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ private function format(string $content): string
116116
];
117117
}
118118

119+
if ([] !== $rows && 'raw' === $rows[array_key_last($rows)]['type'] && '' === $rows[array_key_last($rows)]['line']) {
120+
array_pop($rows);
121+
}
122+
119123
$formattedLines = [];
120124

121125
foreach ($rows as $row) {

0 commit comments

Comments
 (0)