agent-context 0.3.0 → 0.4.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.
data/specification.md CHANGED
@@ -15,7 +15,7 @@ AI agents and automated tools working with software projects often lack access t
15
15
  - **Standardization**: Define a consistent structure for contextual information across different programming languages and ecosystems.
16
16
  - **Discoverability**: Enable automated tools to programmatically find and access contextual information.
17
17
  - **Separation of Concerns**: Clearly separate provider context from consumer context.
18
- - **Extensibility**: Allow for future enhancements while maintaining backward compatibility.
18
+ - **Extensibility**: Preserve additional provider-authored metadata alongside the fields defined by this specification.
19
19
 
20
20
  ## 2. Core Concepts
21
21
 
@@ -32,9 +32,10 @@ A **Context Provider** is any software package, library, or module that includes
32
32
 
33
33
  A **Context Consumer** is any project or tool that utilizes contextual information from its dependencies. Context consumers:
34
34
 
35
- - Install context from their dependencies into a `.context/` directory.
35
+ - Install context from their dependencies into a `.agents/context/` directory.
36
+ - May install skill-marked context documents into a `.agents/skills/` directory.
36
37
  - Use tools to discover and access available context.
37
- - Apply context based on file patterns and metadata.
38
+ - Read and apply guidance relevant to the task.
38
39
 
39
40
  ### 2.3 Context Files
40
41
 
@@ -47,6 +48,10 @@ A **Context Consumer** is any project or tool that utilizes contextual informati
47
48
  - Security considerations.
48
49
  - Troubleshooting guides.
49
50
 
51
+ A **Definition** is one installable unit loaded from a provider: an ordinary file, or a skill document together with its companion resources. A parsed **Document** represents the Markdown source and front matter of a definition. Files such as images and examples remain opaque.
52
+
53
+ A definition's **path** is its filename relative to the provider's `context/` directory, including any subdirectories and extension. Its **source path** locates the authored file in the installed package. A skill's **installed name** is its authored or derived `name`, used for its destination directory. These identifiers serve different purposes.
54
+
50
55
  ### 2.4 Context Installation
51
56
 
52
57
  **Context Installation** is the process of copying context files from dependencies into a consumer's local context directory, making them available for use by tools and AI agents.
@@ -63,6 +68,7 @@ Context providers MUST include a `context/` directory in their package root. Thi
63
68
  - **Versioning**: Must be versioned alongside the package code.
64
69
 
65
70
  Example structure:
71
+
66
72
  ```
67
73
  package-root/
68
74
  ├── context/
@@ -75,20 +81,23 @@ package-root/
75
81
  └── package.json
76
82
  ```
77
83
 
78
- ### 3.2 Consumer Directory: `.context/`
84
+ ### 3.2 Consumer Directory: `.agents/context/`
79
85
 
80
- Context consumers SHOULD create a `.context/` directory in their project root to store installed context. This directory:
86
+ Context consumers SHOULD create a `.agents/context/` directory in their project root to store installed context. This directory:
81
87
 
82
88
  - **Location**: Must be at the project root (typically where package manifests are located).
83
89
  - **Purpose**: Contains context files copied from dependencies.
84
- - **Organization**: Must organize context by package name in subdirectories.
85
- - **Exclusion**: SHOULD be excluded from version control (e.g., in `.gitignore`).
90
+ - **Organization**: Must organize context by resolved provider in subdirectories named by a package selector.
91
+ - **Exclusion**: The generated `.agents/context/` directory SHOULD be excluded from version control. A Git integration SHOULD add local exclusions to `.git/info/exclude` so projects do not need to commit rules for generated files. Other project-owned files may live directly under `.agents/`.
86
92
  - **Transient Nature**: Should contain only reproducible content that can be regenerated from installed packages and MUST NOT contain unique or modified files.
87
93
 
94
+ A package selector identifies one resolved provider. It is normally the package name. Consumers that support multiple resolved versions MUST distinguish them, for example with `package-a@1.0.0` and `package-a@2.0.0`. Tools SHOULD display accepted selectors when listing providers and use those selectors consistently in commands and installed directory names.
95
+
88
96
  Example structure:
97
+
89
98
  ```
90
99
  project-root/
91
- ├── .context/
100
+ ├── .agents/context/
92
101
  │ ├── package-a/
93
102
  │ │ ├── getting-started.md
94
103
  │ │ └── configuration.md
@@ -100,9 +109,9 @@ project-root/
100
109
 
101
110
  ### 3.3 Directory Separation Rationale
102
111
 
103
- The separation between `context/` and `.context/` serves several purposes:
112
+ The separation between `context/` and `.agents/context/` serves several purposes:
104
113
 
105
- - **Ownership**: `context/` is controlled by the project itself, `.context/` contains external dependencies.
114
+ - **Ownership**: `context/` is controlled by the project itself, `.agents/context/` contains external dependencies.
106
115
  - **Isolation**: Prevents conflicts between different packages' context files.
107
116
  - **Discoverability**: Makes it easy to find context for specific packages.
108
117
  - **Maintenance**: Allows independent management of provided vs. consumed context.
@@ -135,6 +144,7 @@ Context files SHOULD follow these naming conventions:
135
144
  - Group related files in subdirectories when appropriate.
136
145
 
137
146
  Common file names:
147
+
138
148
  - `getting-started.md`
139
149
  - `configuration.md`
140
150
  - `troubleshooting.md`
@@ -142,6 +152,29 @@ Common file names:
142
152
  - `security.md`
143
153
  - `migration-guide.md`
144
154
 
155
+ ### 4.4 Skill Documents
156
+
157
+ A context provider may distribute an Agent Skill as a Markdown document directly inside `context/`. The document MUST use YAML front matter with `metadata.type: skill` and a non-empty top-level `description`:
158
+
159
+ ```yaml
160
+ ---
161
+ name: provider-workflow
162
+ description: Run the provider workflow when preparing a project.
163
+ metadata:
164
+ type: skill
165
+ ---
166
+ ```
167
+
168
+ Within a context document's YAML `metadata` mapping, the string `skill` declares a skill. Consumers MUST treat all other `metadata.type` values, including absent, null, and unfamiliar values, as ordinary context. This allows providers to introduce new types while existing consumers continue installing their documents. Consumers MUST interpret only mappings as context metadata; other values of `metadata` are unrelated authored data and MUST be retained as ordinary context.
169
+
170
+ An authored top-level `name` MUST be preserved and used as the installed directory name. When `name` is absent, consumers MUST derive it from the lowercase provider package name (normalizing underscores to hyphens), a hyphen, and the source filename without its `.md` extension. Installed names MUST use lowercase ASCII letters, digits, and single hyphens, contain 1–64 characters, and begin and end with a letter or digit. Descriptions MUST contain 1–1,024 characters after trimming whitespace for validation; consumers MUST retain the authored description value.
171
+
172
+ Consumers MUST install the document as `.agents/skills/<name>/SKILL.md`. A companion directory named after the source filename without its extension MAY provide resources, independently of the installed name. Its files MUST be copied into the installed skill directory. Consumers MUST retain additional top-level fields and nested metadata, except for the resolved installation provenance defined in section 7. Skill documents and their resources belong exclusively to the installed skill.
173
+
174
+ Consumers MUST preserve the original Markdown body bytes following the front matter. Front matter formatting MAY be normalized during serialization.
175
+
176
+ Dependency-installed skill directories SHOULD be excluded from version control, while project-owned skills in `.agents/skills/` SHOULD remain trackable. Git integrations SHOULD add exact dependency-installed skill paths to `.git/info/exclude` rather than ignore the entire `.agents/skills/` directory. They SHOULD mark generated entries with comments and preserve user-authored rules outside that marked section.
177
+
145
178
  ## 5. Discovery and Installation
146
179
 
147
180
  ### 5.1 Discovery Process
@@ -163,14 +196,60 @@ The discovery process SHOULD integrate with the target language's package manage
163
196
  Context installation MUST follow these principles:
164
197
 
165
198
  1. **Copy Strategy**: Context files SHOULD be copied rather than symlinked.
166
- 2. **Namespace Isolation**: Each package's context MUST be installed in its own subdirectory.
167
- 3. **Preserve Structure**: The internal structure of the `context/` directory MUST be preserved.
199
+ 2. **Namespace Isolation**: Each resolved provider's ordinary context MUST be installed in its own subdirectory, named by its package selector.
200
+ 3. **Preserve Structure**: The internal structure of ordinary context files MUST be preserved.
201
+ 4. **Skill Separation**: Skill documents and their resources MUST be installed as skills only, not duplicated as ordinary context.
168
202
 
169
- ### 5.3 Installation Algorithm
203
+ Consumers SHOULD validate document data as part of loading or parsing it and use that validated representation when applying changes. Installation MAY use direct file writes and copies. Consumers MUST report failures; completed changes and partially written output MAY remain after an error. After resolving the reported failure, consumers SHOULD support refreshing generated output by rerunning installation.
170
204
 
205
+ ### 5.3 Installation Steps
206
+
207
+ For each selected provider:
208
+
209
+ 1. Classify its context documents and identify companion skill resource directories, keeping their contents opaque.
210
+ 2. If skills are supported, install each declared skill once as `.agents/skills/<name>/SKILL.md` and copy its companion resources into that skill directory.
211
+ 3. Copy the remaining ordinary files into `.agents/context/<selector>/`, preserving their relative paths.
212
+
213
+ Skill documents and their resources are excluded from ordinary context copying even when the consumer does not support skill installation.
214
+
215
+ ## 6. Discovering Installed Context
216
+
217
+ Consumers SHOULD provide commands to list providers, list their definitions, and show a selected definition. Agents discover installed guidance by enumerating Markdown files under `.agents/context/<selector>/` and reading the files relevant to their task. A packaged usage skill SHOULD explain this workflow and how to install missing guidance.
218
+
219
+ Providers SHOULD use descriptive filenames, keep guides focused on one topic, and link related documents. Ordinary documents need no front matter. Unrelated ordinary-document metadata MUST be tolerated. Skill resource files are opaque assets and MUST NOT be parsed as context documents.
220
+
221
+ Provider lookup identifies dependencies with a `context/` directory, including empty directories. An empty provider has no definitions; listing commands MAY omit it from the available guidance list. Refreshing an empty provider still reconciles its installed output.
222
+
223
+ Showing a definition MUST return its authored content. Lookup MUST prefer an exact provider-relative path, then that path with `.md` appended when no extension was supplied. Consumers MAY also accept installed skill names as a fallback after source path lookup. Definition paths retain their filename case and extension. Generated skill instructions add installation provenance when installed.
224
+
225
+ The installed directory layout is the discovery interface.
226
+
227
+ ## 7. Skill Installation Ownership
228
+
229
+ Consumers MUST record resolved installation provenance inside `SKILL.md` front matter:
230
+
231
+ ```yaml
232
+ ---
233
+ name: provider-workflow
234
+ description: Run the provider workflow when preparing a project.
235
+ metadata:
236
+ type: skill
237
+ ecosystem: cargo
238
+ package: provider
239
+ version: "1.0.0"
240
+ ---
171
241
  ```
172
- FOR each package with context:
173
- CREATE directory .context/package-name/
174
- COPY all files recursively from package/context/ to .context/package-name/
175
- END
176
- ```
242
+
243
+ The installer supplies `metadata.ecosystem`, `metadata.package`, and `metadata.version` from its resolved provider, overriding source values for these fields. Ruby gems use `gem`; Cargo crates use `cargo`. These three fields MUST be non-empty strings, including a quoted version when YAML would otherwise decode it as a number. Additional metadata MUST be retained.
244
+
245
+ Consumers MUST discover ownership by scanning direct child directories of `.agents/skills/` and parsing their `SKILL.md` files. The skills root and managed skill directories MUST be regular directories. Symbolic links and non-directory children are skipped. Instruction files MUST be regular files. Managed directory names MUST satisfy section 4.4.
246
+
247
+ `metadata.type: skill` together with an explicit `metadata.ecosystem` identifies installation provenance. Consumers MUST validate the complete provenance tuple after recognizing that discriminator, and report malformed or unreadable metadata. Other directories are project-owned; an authored `metadata.version` alone is ordinary skill metadata.
248
+
249
+ A full refresh reconciles the installer's ecosystem; a package refresh reconciles that ecosystem and package. Full reconciliation includes providers removed from the dependency graph and providers that become empty. Consumers MUST retain skills belonging to other ecosystems and packages outside the requested scope, and MUST reject conflicting destinations.
250
+
251
+ Installers SHOULD write `SKILL.md` before copying companion resources, establishing ownership for subsequent refreshes. If writing the instructions fails, installers SHOULD remove that incomplete destination. Resource-copy failures leave completed instructions in place. The incremental failure behavior in section 5.2 applies to skills and Git exclusion updates.
252
+
253
+ The top-level resource name `SKILL.md` is reserved case-insensitively for generated instructions. Consumers MUST reject a resource file or directory with that name. Nested files with that name and other resource names are copied as opaque assets.
254
+
255
+ Git integrations SHOULD maintain one marked exclusion block per consuming project, covering generated context and exact dependency-owned skill directories from all ecosystems. Exclusion paths MUST be relative to the Git repository root. Nested projects SHOULD identify their block by appending the repository-relative project path, with a trailing slash, to the `# BEGIN bake-agent-context` and `# END bake-agent-context` markers. They MUST retain user-authored rules and blocks belonging to other projects. Installed instructions and resources are excluded with their containing skill directory.
data.tar.gz.sig CHANGED
@@ -1,3 +1,4 @@
1
- i>J9k���7�TZ�V�{� c���t_7$38�#��iz����fǦ�M�׀�
2
- �m
3
- �&���,U_q�c4�U_��� wH����O.d)��8�8�T9�s�eQř����q@��V�3e��0Cf����ל_c��]��������/Ь[��:ӧ �Y+�'Z�&v�~?�<�sL�x���az�$�$��'�s�:��L��Jy����y��q���_ڣ�6s���m���;�g���E\��l*�U�eq�����{�L^Y�ʅ�\�_�N ƌ<��宂�\�z �O� Ip��F� ץ���"
1
+ g���
2
+ p�˺Xc�%m�~�8�
3
+ ��(��p��`�B���ƫ���N�����:���,fdd�sD]�iL�r�S�'��1eT���<��LB�Ww�����Z�+��A�A7�##k4�7�x*���\��౅ ����k�&�x����`:��P��6����!Q�#^!
4
+ �5i6��"{���_r�v"����BN�"X���%��H�΅�S�*���Z���u G��-{����� Ń�����NrV����ف>Ʀ�=����=�ʾJtr+��MםV=��2q�,��"���?�t��ݖ�X��>�R\o�I����|(��a���*ےN�45S��O͋sX��./$�N�
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: agent-context
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -10,32 +10,28 @@ bindir: bin
10
10
  cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
- MIIE2DCCA0CgAwIBAgIBATANBgkqhkiG9w0BAQsFADBhMRgwFgYDVQQDDA9zYW11
14
- ZWwud2lsbGlhbXMxHTAbBgoJkiaJk/IsZAEZFg1vcmlvbnRyYW5zZmVyMRIwEAYK
15
- CZImiZPyLGQBGRYCY28xEjAQBgoJkiaJk/IsZAEZFgJuejAeFw0yMjA4MDYwNDUz
16
- MjRaFw0zMjA4MDMwNDUzMjRaMGExGDAWBgNVBAMMD3NhbXVlbC53aWxsaWFtczEd
17
- MBsGCgmSJomT8ixkARkWDW9yaW9udHJhbnNmZXIxEjAQBgoJkiaJk/IsZAEZFgJj
18
- bzESMBAGCgmSJomT8ixkARkWAm56MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIB
19
- igKCAYEAomvSopQXQ24+9DBB6I6jxRI2auu3VVb4nOjmmHq7XWM4u3HL+pni63X2
20
- 9qZdoq9xt7H+RPbwL28LDpDNflYQXoOhoVhQ37Pjn9YDjl8/4/9xa9+NUpl9XDIW
21
- sGkaOY0eqsQm1pEWkHJr3zn/fxoKPZPfaJOglovdxf7dgsHz67Xgd/ka+Wo1YqoE
22
- e5AUKRwUuvaUaumAKgPH+4E4oiLXI4T1Ff5Q7xxv6yXvHuYtlMHhYfgNn8iiW8WN
23
- XibYXPNP7NtieSQqwR/xM6IRSoyXKuS+ZNGDPUUGk8RoiV/xvVN4LrVm9upSc0ss
24
- RZ6qwOQmXCo/lLcDUxJAgG95cPw//sI00tZan75VgsGzSWAOdjQpFM0l4dxvKwHn
25
- tUeT3ZsAgt0JnGqNm2Bkz81kG4A2hSyFZTFA8vZGhp+hz+8Q573tAR89y9YJBdYM
26
- zp0FM4zwMNEUwgfRzv1tEVVUEXmoFCyhzonUUw4nE4CFu/sE3ffhjKcXcY//qiSW
27
- xm4erY3XAgMBAAGjgZowgZcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0O
28
- BBYEFO9t7XWuFf2SKLmuijgqR4sGDlRsMC4GA1UdEQQnMCWBI3NhbXVlbC53aWxs
29
- aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MC4GA1UdEgQnMCWBI3NhbXVlbC53aWxs
30
- aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MA0GCSqGSIb3DQEBCwUAA4IBgQB5sxkE
31
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
39
35
  -----END CERTIFICATE-----
40
36
  date: 1980-01-02 00:00:00.000000000 Z
41
37
  dependencies:
@@ -53,6 +49,20 @@ dependencies:
53
49
  - - ">="
54
50
  - !ruby/object:Gem::Version
55
51
  version: '0.23'
52
+ - !ruby/object:Gem::Dependency
53
+ name: markly
54
+ requirement: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - "~>"
57
+ - !ruby/object:Gem::Version
58
+ version: '0.16'
59
+ type: :runtime
60
+ prerelease: false
61
+ version_requirements: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - "~>"
64
+ - !ruby/object:Gem::Version
65
+ version: '0.16'
56
66
  executables: []
57
67
  extensions: []
58
68
  extra_rdoc_files: []
@@ -60,9 +70,19 @@ files:
60
70
  - bake/agent/context.rb
61
71
  - context/getting-started.md
62
72
  - context/index.yaml
73
+ - context/usage.md
74
+ - design.md
63
75
  - lib/agent/context.rb
64
- - lib/agent/context/index.rb
76
+ - lib/agent/context/definition.rb
77
+ - lib/agent/context/document.rb
78
+ - lib/agent/context/errors.rb
79
+ - lib/agent/context/exclusion.rb
65
80
  - lib/agent/context/installer.rb
81
+ - lib/agent/context/package.rb
82
+ - lib/agent/context/paths.rb
83
+ - lib/agent/context/skills.rb
84
+ - lib/agent/context/skills/definition.rb
85
+ - lib/agent/context/skills/ownership.rb
66
86
  - lib/agent/context/version.rb
67
87
  - license.md
68
88
  - post.md
@@ -73,6 +93,8 @@ homepage: https://github.com/ioquatix/agent-context
73
93
  licenses:
74
94
  - MIT
75
95
  metadata:
96
+ bug_tracker_uri: https://github.com/ioquatix/agent-context/issues
97
+ changelog_uri: https://github.com/ioquatix/agent-context/blob/main/releases.md
76
98
  documentation_uri: https://ioquatix.github.io/agent-context/
77
99
  funding_uri: https://github.com/sponsors/ioquatix/
78
100
  source_code_uri: https://github.com/ioquatix/agent-context.git
@@ -83,14 +105,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
83
105
  requirements:
84
106
  - - ">="
85
107
  - !ruby/object:Gem::Version
86
- version: '3.2'
108
+ version: '3.3'
87
109
  required_rubygems_version: !ruby/object:Gem::Requirement
88
110
  requirements:
89
111
  - - ">="
90
112
  - !ruby/object:Gem::Version
91
113
  version: '0'
92
114
  requirements: []
93
- rubygems_version: 3.6.9
115
+ rubygems_version: 4.0.21
94
116
  specification_version: 4
95
- summary: Install and manage context files from Ruby gems.
117
+ summary: Install and manage context files and skills from Ruby gems.
96
118
  test_files: []
metadata.gz.sig CHANGED
Binary file
@@ -1,325 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2025, by Samuel Williams.
5
- # Copyright, 2025, by Shopify Inc.
6
-
7
- require_relative "version"
8
- require "fileutils"
9
- require "yaml"
10
-
11
- # @namespace
12
- module Agent
13
- # @namespace
14
- module Context
15
- # Represents an index for managing and generating agents.md files from context files.
16
- #
17
- # This class provides functionality to update or create AGENTS.md files following
18
- # the AGENTS.md specification for agentic coding tools. It can parse existing
19
- # agents.md files, update the context section, and generate new files when needed.
20
- class Index
21
- # Initialize a new index instance.
22
- # @parameter context_path [String] The path to the context directory (default: ".context").
23
- def initialize(context_path = ".context")
24
- @context_path = context_path
25
- end
26
-
27
- attr :context_path
28
-
29
- # Update or create an AGENTS.md file in the project root with context section
30
- # This follows the AGENTS.md specification for agentic coding tools
31
- def update_agents_md(agents_md_path = "agents.md")
32
- context_content = generate_context_section
33
-
34
- if File.exist?(agents_md_path)
35
- update_existing_agents_md(agents_md_path, context_content)
36
- else
37
- create_new_agents_md(agents_md_path, context_content)
38
- end
39
-
40
- Console.debug("Updated agents.md: #{agents_md_path}")
41
- end
42
-
43
- # Generate just the context section content (without top-level headers)
44
- def generate_context_section
45
- sections = []
46
-
47
- sections << "This section provides links to documentation from installed packages. It is automatically generated and may be updated by running `bake agent:context:install`."
48
- sections << ""
49
- sections << "**Important:** Before performing any code, documentation, or analysis tasks, always read and apply the full content of any relevant documentation referenced in the following sections. These context files contain authoritative standards and best practices for documentation, code style, and project-specific workflows. **Do not proceed with any actions until you have read and incorporated the guidance from relevant context files.**"
50
- sections << ""
51
- sections << "**Setup Instructions:** If the referenced files are not present or if dependencies have been updated, run `bake agent:context:install` to install the latest context files."
52
- sections << ""
53
-
54
- gem_contexts = collect_gem_contexts
55
-
56
- if gem_contexts.empty?
57
- sections << "No context files found. Run `bake agent:context:install` to install context from gems."
58
- sections << ""
59
- else
60
- gem_contexts.each do |gem_name, files|
61
- sections << "### #{gem_name}"
62
- sections << ""
63
-
64
- # Get gem directory and load index
65
- gem_directory = File.join(@context_path, gem_name)
66
- index = load_gem_index(gem_name, gem_directory)
67
-
68
- # Add gem description from index
69
- if index["description"]
70
- sections << index["description"]
71
- sections << ""
72
- end
73
-
74
- # Use files from index if available, otherwise fall back to parsing
75
- if index["files"] && !index["files"].empty?
76
- index["files"].each do |file_info|
77
- sections << "#### [#{file_info['title']}](.context/#{gem_name}/#{file_info['path']})"
78
- sections << ""
79
- sections << file_info["description"] if file_info["description"] && !file_info["description"].empty?
80
- sections << ""
81
- end
82
- else
83
- # Fallback to parsing files directly
84
- files.each do |file_path|
85
- if File.exist?(file_path)
86
- title, description = extract_content(file_path)
87
- relative_path = file_path.sub("#{@context_path}/", "")
88
- sections << "#### [#{title}](.context/#{relative_path})"
89
- sections << ""
90
- sections << description if description && !description.empty?
91
- sections << ""
92
- end
93
- end
94
- end
95
- end
96
- end
97
-
98
- sections.join("\n")
99
- end
100
-
101
- private
102
-
103
- def update_existing_agents_md(agents_md_path, context_content)
104
- content = File.read(agents_md_path)
105
-
106
- # Find the # Agent heading
107
- agent_heading_line = find_agent_heading_line(content)
108
-
109
- if agent_heading_line
110
- # Find or create the ## Context section
111
- context_section = find_context_section_under_agent(content, agent_heading_line)
112
-
113
- if context_section
114
- # Replace existing context section
115
- updated_content = replace_context_section(content, context_section, context_content)
116
- else
117
- # Insert new context section after agent heading
118
- updated_content = insert_context_section_after_agent(content, agent_heading_line, context_content)
119
- end
120
- else
121
- # No # Agent heading found, prepend it with context
122
- updated_content = prepend_agent_with_context(content, context_content)
123
- end
124
-
125
- # Write the updated content back to file
126
- File.write(agents_md_path, updated_content)
127
- end
128
-
129
- def create_new_agents_md(agents_md_path, context_content)
130
- content = [
131
- "# Agent",
132
- "",
133
- "## Context",
134
- "",
135
- context_content,
136
- ].join("\n")
137
- File.write(agents_md_path, content)
138
- end
139
-
140
- def find_agent_heading_line(content)
141
- lines = content.lines
142
- lines.each_with_index do |line, index|
143
- if line.strip.start_with?("# ") && line.strip.downcase == "# agent"
144
- return index
145
- end
146
- end
147
- nil
148
- end
149
-
150
- def find_context_section_under_agent(content, agent_line_index)
151
- lines = content.lines
152
-
153
- # Look for ## Context after the agent heading
154
- (agent_line_index + 1).upto(lines.length - 1) do |index|
155
- line = lines[index]
156
- if line.strip == "## Context"
157
- return index
158
- elsif line.strip.start_with?("# ") && line.strip != "# Agent"
159
- # We've hit another top-level heading, stop searching
160
- break
161
- end
162
- end
163
-
164
- nil
165
- end
166
-
167
- def replace_context_section(content, context_line_index, context_content)
168
- lines = content.lines
169
-
170
- # Find the end of the context section
171
- end_index = find_section_end(lines, context_line_index, 2)
172
-
173
- # Build the new content
174
- new_lines = []
175
- new_lines.concat(lines[0...context_line_index])
176
- new_lines << "## Context\n"
177
- new_lines << "\n"
178
- new_lines.concat(context_content.lines)
179
- new_lines.concat(lines[end_index..-1])
180
-
181
- new_lines.join
182
- end
183
-
184
- def insert_context_section_after_agent(content, agent_line_index, context_content)
185
- lines = content.lines
186
-
187
- # Build the new content
188
- new_lines = []
189
- new_lines.concat(lines[0..agent_line_index])
190
- new_lines << "\n"
191
- new_lines << "## Context\n"
192
- new_lines << "\n"
193
- new_lines.concat(context_content.lines)
194
- new_lines.concat(lines[agent_line_index + 1..-1])
195
-
196
- new_lines.join
197
- end
198
-
199
- def prepend_agent_with_context(content, context_content)
200
- agent_context = [
201
- "# Agent",
202
- "",
203
- "## Context",
204
- "",
205
- context_content,
206
- ""
207
- ].join("\n")
208
- agent_context + content
209
- end
210
-
211
- def find_section_end(lines, start_index, heading_level)
212
- index = start_index + 1
213
-
214
- while index < lines.length
215
- line = lines[index]
216
-
217
- if line.strip.start_with?("#")
218
- level = line.strip.match(/^(#+)/)[1].length
219
- if level <= heading_level
220
- break
221
- end
222
- end
223
-
224
- index += 1
225
- end
226
-
227
- index
228
- end
229
-
230
- def collect_gem_contexts
231
- gem_contexts = {}
232
-
233
- return gem_contexts unless Dir.exist?(@context_path)
234
-
235
- Dir.glob(File.join(@context_path, "*")).each do |gem_directory|
236
- next unless File.directory?(gem_directory)
237
- gem_name = File.basename(gem_directory)
238
-
239
- markdown_files = Dir.glob(File.join(gem_directory, "**", "*.md")).sort
240
- gem_contexts[gem_name] = markdown_files if markdown_files.any?
241
- end
242
-
243
- gem_contexts
244
- end
245
-
246
- # Load a gem's index file
247
- def load_gem_index(gem_name, gem_directory)
248
- index_path = File.join(gem_directory, "index.yaml")
249
-
250
- if File.exist?(index_path)
251
- YAML.load_file(index_path)
252
- else
253
- # Return a fallback index if no index.yaml exists
254
- {
255
- "description" => "Context files for #{gem_name}",
256
- "files" => []
257
- }
258
- end
259
- rescue => error
260
- Console.debug("Error loading index for #{gem_name}: #{error.message}")
261
- # Return a fallback index
262
- {
263
- "description" => "Context files for #{gem_name}",
264
- "files" => []
265
- }
266
- end
267
-
268
- def extract_content(file_path)
269
- content = File.read(file_path)
270
- lines = content.lines.map(&:strip)
271
-
272
- title = extract_title(lines)
273
- description = extract_description(lines)
274
-
275
- [title, description]
276
- end
277
-
278
- def extract_title(lines)
279
- # Look for the first markdown header
280
- header_line = lines.find {|line| line.start_with?("#")}
281
- if header_line
282
- # Remove markdown header syntax and clean up
283
- header_line.sub(/^#+\s*/, "").strip
284
- else
285
- # If no header found, use a default
286
- "Documentation"
287
- end
288
- end
289
-
290
- def extract_description(lines)
291
- # Skip empty lines and headers to find the first paragraph
292
- content_start = false
293
- description_lines = []
294
-
295
- lines.each do |line|
296
- # Skip headers
297
- next if line.start_with?("#")
298
-
299
- # Skip empty lines until we find content
300
- if !content_start && line.empty?
301
- next
302
- end
303
-
304
- # Mark that we've found content
305
- content_start = true
306
-
307
- # If we hit an empty line after finding content, we've reached the end of the first paragraph
308
- if line.empty?
309
- break
310
- end
311
-
312
- description_lines << line
313
- end
314
-
315
- # Join the lines and truncate if too long
316
- description = description_lines.join(" ").strip
317
- if description.length > 197
318
- description = description[0..196] + "..."
319
- end
320
-
321
- description
322
- end
323
- end
324
- end
325
- end