contextos-agents 2.0.0 → 2.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.
Files changed (45) hide show
  1. package/.agents/AGENTS.md +53 -33
  2. package/.agents/adapters/aider/export.js +41 -14
  3. package/.agents/adapters/claude/export.js +1 -1
  4. package/.agents/adapters/copilot/export.js +1 -1
  5. package/.agents/adapters/cursor/export.js +1 -1
  6. package/.agents/adapters/drift-detector.js +80 -7
  7. package/.agents/adapters/gemini/export.js +1 -1
  8. package/.agents/adapters/pure-compiler.js +10 -0
  9. package/.agents/adapters/shared.js +13 -4
  10. package/.agents/adapters/zed/export.js +1 -1
  11. package/.agents/compiled/registry.v2.json +29 -25
  12. package/.agents/compiled/registry.v2.sha256 +1 -1
  13. package/.agents/core/skills/context-os/SKILL.md +34 -37
  14. package/.agents/core/skills/engineering-workflow/SKILL.md +24 -24
  15. package/.agents/core/skills/gemini-precision/EXAMPLES.md +72 -0
  16. package/.agents/core/skills/gemini-precision/SKILL.md +2 -1
  17. package/.agents/core/skills/gemini-precision/TROUBLESHOOTING.md +25 -0
  18. package/.agents/core/skills/gemini-precision/skill.yaml +2 -0
  19. package/.agents/core/skills/gstack-roles/SKILL.md +7 -6
  20. package/.agents/core/skills/security/SKILL.md +44 -16
  21. package/.agents/core/skills/security/skill.yaml +0 -1
  22. package/.agents/ctx.js +16 -10
  23. package/.agents/generated/claude/skills/context-os/SKILL.md +34 -37
  24. package/.agents/generated/claude/skills/engineering-workflow/SKILL.md +24 -24
  25. package/.agents/generated/claude/skills/gemini-precision/SKILL.md +102 -1
  26. package/.agents/generated/claude/skills/gstack-roles/SKILL.md +7 -6
  27. package/.agents/generated/claude/skills/security/SKILL.md +44 -16
  28. package/.agents/generated/gemini/skills/context-os/SKILL.md +34 -37
  29. package/.agents/generated/gemini/skills/engineering-workflow/SKILL.md +24 -24
  30. package/.agents/generated/gemini/skills/gemini-precision/SKILL.md +105 -1
  31. package/.agents/generated/gemini/skills/gstack-roles/SKILL.md +7 -6
  32. package/.agents/generated/gemini/skills/security/SKILL.md +44 -125
  33. package/.agents/plugins.js +5 -4
  34. package/.agents/resolver/canonical-resolver.js +7 -7
  35. package/.agents/validate.js +69 -1
  36. package/README.md +80 -23
  37. package/bin/commands/hook.js +129 -0
  38. package/bin/commands/scan.js +70 -0
  39. package/bin/commands.js +39 -1
  40. package/bin/index.js +144 -33
  41. package/bin/lib/gate.js +171 -0
  42. package/bin/lib/git-snapshot.js +187 -0
  43. package/bin/lib/scan.js +380 -0
  44. package/package.json +4 -2
  45. package/.agents/core/skills/security/security.md +0 -106
package/.agents/AGENTS.md CHANGED
@@ -1,4 +1,4 @@
1
- # ContextOS — Deterministic context compiler and policy engine for AI coding agents.
1
+ # ContextOS - Deterministic context compiler and policy engine for AI coding agents.
2
2
 
3
3
  You are working inside a project managed by **ContextOS**. This file is the **single source of truth** for how you must behave, think, and which skills to activate for every task.
4
4
 
@@ -6,7 +6,7 @@ You are working inside a project managed by **ContextOS**. This file is the **si
6
6
 
7
7
  ---
8
8
 
9
- ## Step 0 — Identify Before Acting
9
+ ## Step 0 - Identify Before Acting
10
10
 
11
11
  Before writing a single line of code or plan, stop and answer three questions:
12
12
 
@@ -28,12 +28,12 @@ Skills loaded: react, typescript, ui-ux-pro, ponytail-mindset
28
28
 
29
29
  ---
30
30
 
31
- ## Skill Architecture (Context Efficiency)
31
+ ## Skill Architecture (High Fidelity & Progressive Disclosure)
32
32
 
33
- Skills are loaded on-demand. To keep the agent context window efficient:
34
- 1. **Keep `SKILL.md` under 500 lines**: Put detailed reference material in separate files.
35
- 2. **Use progressive disclosure**: Use a `references/` directory for deep context and load those files only when specifically needed by the task.
36
- 3. **Use `scripts/`**: Place executable scripts in a `scripts/` directory alongside the skill.
33
+ Skills provide deep, production-ready engineering standards. To maximize instruction adherence:
34
+ 1. **High-Fidelity Guidance**: Skills must be complete, self-contained, and comprehensive. Never truncate essential rules, edge cases, or code examples for artificial brevity.
35
+ 2. **Progressive Disclosure**: Use a `references/` directory for deep domain specifications, detailed schemas, and specialized manuals, loading them when the task explicitly targets those areas.
36
+ 3. **Executable Scripts**: Place verification and automation scripts in a `scripts/` directory alongside the skill.
37
37
 
38
38
  ## Skill Registry
39
39
 
@@ -43,10 +43,10 @@ These 7 skills are always present in ContextOS Core:
43
43
 
44
44
  | Skill | File | Activate When |
45
45
  |-------|------|--------------|
46
- | **engineering-workflow** | `engineering-workflow/SKILL.md` | **Every task** — defines the DEFINE→PLAN→BUILD→VERIFY→REVIEW→SHIP pipeline |
47
- | **gstack-roles** | `gstack-roles/SKILL.md` | **Every task** — declare your specialist role before each phase |
48
- | **ponytail-mindset** | `ponytail-mindset/SKILL.md` | **Every BUILD phase** — run the 7-rung ladder before writing any code |
49
- | **gemini-precision** | `gemini-precision/SKILL.md` | **All Gemini tasks** — zero assumptions, zero placeholders, surgical blast radius, test proof |
46
+ | **engineering-workflow** | `engineering-workflow/SKILL.md` | **Every task** - defines the DEFINE→PLAN→BUILD→VERIFY→REVIEW→SHIP pipeline |
47
+ | **gstack-roles** | `gstack-roles/SKILL.md` | **Every task** - declare your specialist role before each phase |
48
+ | **ponytail-mindset** | `ponytail-mindset/SKILL.md` | **Every BUILD phase** - run the 7-rung ladder before writing any code |
49
+ | **gemini-precision** | `gemini-precision/SKILL.md` | **All Gemini tasks** - zero assumptions, zero placeholders, surgical blast radius, test proof |
50
50
  | **security** | `security/SKILL.md` | Any feature with auth, data access, user input, external integration |
51
51
  | **context-os** | `context-os/SKILL.md` | Managing context rules, compiler pipelines, project policies |
52
52
  | **context-manager** | `context-manager/SKILL.md` | Context selection, dynamic skill resolution, project graph traversal |
@@ -58,14 +58,14 @@ The following domain skills are available in the extended catalog and can be add
58
58
  | Domain | Skills | Install Command |
59
59
  |--------|--------|-----------------|
60
60
  | **Frontend** | `react`, `react-best-practices`, `nextjs`, `typescript`, `ui-ux-pro`, `impeccable-design`, `state-management`, `ui-design`, `ux-design`, `web-accessibility`, `brutalist-design`, `minimalist-design`, `soft-design`, `redesign-audit` | `contextos skill add <name>` |
61
- | **Backend** | `system-design`, `node`, `fastapi`, `nestjs`, `microservices`, `ddd`, `database` | `contextos skill add <name>` |
62
- | **Cross-Cutting** | `testing`, `docker`, `decisions`, `architecture-diagrams`, `adapters`, `generators`, `graphify`, `performance`, `vercel-optimize` | `contextos skill add <name>` |
61
+ | **Backend** | `system-design`, `api-design`, `node`, `fastapi`, `nestjs`, `microservices`, `ddd`, `database` | `contextos skill add <name>` |
62
+ | **Cross-Cutting** | `testing`, `docker`, `ci-cd`, `terraform`, `security-audit`, `decisions`, `architecture-diagrams`, `adapters`, `generators`, `graphify`, `performance`, `vercel-optimize` | `contextos skill add <name>` |
63
63
 
64
64
  ---
65
65
 
66
66
  ## Automatic Skill Activation Rules (Proactive Routing)
67
67
 
68
- The following rules are **deterministic** — no judgment needed. If the condition is true, the skill is loaded.
68
+ The following rules are **deterministic** - no judgment needed. If the condition is true, the skill is loaded.
69
69
 
70
70
  > **Availability Guard**: Load only skills that are physically installed in `.agents/core/skills/`. For uninstalled catalog skills, rely on core skills (`engineering-workflow`, `ponytail-mindset`, `gemini-precision`, `security`) and recommend `contextos skill add <name>` when deep domain checklists are needed.
71
71
 
@@ -159,6 +159,22 @@ role: Staff Engineer (Orchestrator)
159
159
  trigger: "graphify" OR "codebase graph" OR "project graph" OR "map codebase" OR "knowledge graph" OR "построй граф проекта"
160
160
  load: [graphify, system-design, context-manager]
161
161
  role: Architect
162
+
163
+ trigger: "security audit" OR "vulnerability" OR "pentest"
164
+ load: [security-audit, security, engineering-workflow]
165
+ role: Chief Security Officer (audit) -> Senior Developer (build)
166
+
167
+ trigger: "api design" OR "REST API" OR "contract" OR "openapi"
168
+ load: [api-design, system-design, engineering-workflow]
169
+ role: Architect (plan) -> Senior Developer (build)
170
+
171
+ trigger: "terraform" OR "opentofu" OR "iac" OR "infrastructure"
172
+ load: [terraform, decisions, engineering-workflow]
173
+ role: DevOps Engineer
174
+
175
+ trigger: "ci/cd" OR "github actions" OR "pipeline" OR "quality gates"
176
+ load: [ci-cd, engineering-workflow]
177
+ role: DevOps Engineer
162
178
  ```
163
179
 
164
180
  ### By Technology Detected in Codebase
@@ -178,7 +194,7 @@ files: "components/ui/*" present → shadcn detected, apply K9-K11 rules from im
178
194
 
179
195
  ---
180
196
 
181
- ## Pipeline — Phase-by-Phase Rules
197
+ ## Pipeline - Phase-by-Phase Rules
182
198
 
183
199
  Every task MUST follow these phases in order. No skipping.
184
200
 
@@ -191,7 +207,7 @@ Required output before proceeding:
191
207
  - Explicit in-scope / out-of-scope
192
208
  - List of files that will change
193
209
  - Acceptance criteria as testable statements
194
- - **STOP — do not write code until spec is reviewed**
210
+ - **STOP - do not write code until spec is reviewed**
195
211
 
196
212
  ---
197
213
 
@@ -205,7 +221,7 @@ Required output before proceeding:
205
221
  - Test requirement per task
206
222
  - Risk assessment
207
223
  - **If UI domain, read and incorporate `.interface-design/system.md` design memory**
208
- - **STOP — do not write code until plan is approved**
224
+ - **STOP - do not write code until plan is approved**
209
225
 
210
226
  ---
211
227
 
@@ -236,12 +252,12 @@ Rules:
236
252
  **Role**: `[ROLE: Staff Engineer]` + `[ROLE: Senior Designer]` if UI
237
253
  **Load**: `engineering-workflow` (code review checklist) + `impeccable-design` (if UI)
238
254
 
239
- For UI tasks — run the full impeccable-design audit:
240
- - Typography rules T1–T10
241
- - Color rules C1–C12
242
- - Layout rules L1–L11 (including z-index check)
243
- - Component rules K1–K11 (shadcn-first)
244
- - Animation rules A1–A8 (Framer Motion exception noted)
255
+ For UI tasks - run the full impeccable-design audit:
256
+ - Typography rules T1-T10
257
+ - Color rules C1-C12
258
+ - Layout rules L1-L11 (including z-index check)
259
+ - Component rules K1-K11 (shadcn-first)
260
+ - Animation rules A1-A8 (Framer Motion exception noted)
245
261
 
246
262
  ---
247
263
 
@@ -276,6 +292,10 @@ Use this table to instantly determine which skills to load:
276
292
  | Architecture visualization | `architecture-diagrams` + `system-design` | Architect |
277
293
  | Multi-agent parallel tasks | `subagent-orchestrator` + `engineering-workflow` | Staff Engineer (Orchestrator) |
278
294
  | Codebase graph / repo mapping | `graphify` + `context-manager` + `system-design` | Architect |
295
+ | Security audit / pen-test | `security-audit` + `security` + `engineering-workflow` | Chief Security Officer |
296
+ | API contract / interface design | `api-design` + `system-design` + `engineering-workflow` | Architect |
297
+ | Terraform / IaC | `terraform` + `decisions` + `engineering-workflow` | DevOps Engineer |
298
+ | CI/CD pipeline automation | `ci-cd` + `engineering-workflow` | DevOps Engineer |
279
299
 
280
300
  ---
281
301
 
@@ -326,18 +346,18 @@ These rules apply regardless of which skills are loaded:
326
346
 
327
347
  ### Code Quality
328
348
  - Business logic NEVER lives in API route handlers → always in `services/` or `use-cases/`
329
- - No `// TODO` in committed code — create a tracked issue instead
349
+ - No `// TODO` in committed code - create a tracked issue instead
330
350
  - All async operations have explicit error handling
331
- - No secrets hardcoded — use environment variables
351
+ - No secrets hardcoded - use environment variables
332
352
 
333
353
  ### Security
334
- - Auth check BEFORE any data access — no exceptions
354
+ - Auth check BEFORE any data access - no exceptions
335
355
  - All user input validated and sanitized before processing
336
- - SQL queries use parameterized form — no string concatenation
356
+ - SQL queries use parameterized form - no string concatenation
337
357
 
338
358
  ### Design
339
- - No arbitrary Tailwind values (`gap-[17px]`) — use scale utilities
340
- - No hardcoded z-indexes (`z-[999]`) — use Radix/shadcn Portals
359
+ - No arbitrary Tailwind values (`gap-[17px]`) - use scale utilities
360
+ - No hardcoded z-indexes (`z-[999]`) - use Radix/shadcn Portals
341
361
  - Every list/table/feed has a designed empty state
342
362
 
343
363
  ### Engineering
@@ -348,10 +368,10 @@ These rules apply regardless of which skills are loaded:
348
368
 
349
369
  ### Completion Protocol
350
370
  When finishing a workflow or task, always report your final status clearly using one of the following:
351
- - **DONE** — completed with evidence.
352
- - **DONE_WITH_CONCERNS** — completed, but list specific concerns.
353
- - **BLOCKED** — cannot proceed; state blocker and what was tried.
354
- - **NEEDS_CONTEXT** — missing info; state exactly what is needed.
371
+ - **DONE** - completed with evidence.
372
+ - **DONE_WITH_CONCERNS** - completed, but list specific concerns.
373
+ - **BLOCKED** - cannot proceed; state blocker and what was tried.
374
+ - **NEEDS_CONTEXT** - missing info; state exactly what is needed.
355
375
 
356
376
  ---
357
377
 
@@ -7,6 +7,7 @@ const fs = require('fs');
7
7
  const path = require('path');
8
8
  const { AGENTS_MD_PATH, collectSkillDirectories, extractYamlField, stripFrontmatter } = require('../shared.js');
9
9
  const { registerAdapter, applyArtifacts, createProvenanceHeader } = require('../pure-compiler.js');
10
+ const YAML = require('../../compiler/vendor/yaml.js');
10
11
 
11
12
  const GENERATOR_ID = 'aider@2';
12
13
 
@@ -43,7 +44,7 @@ function buildSkillSection(skillDir) {
43
44
  }
44
45
 
45
46
  const descLine = description ? `> ${description.replace(/\r?\n+/g, ' ').trim()}\n` : '';
46
- const skillRef = `*Source: \`.agents/skills/${skillName}/SKILL.md\` — Load via \`/read .agents/skills/${skillName}/SKILL.md\`*\n`;
47
+ const skillRef = `*Source: \`.agents/skills/${skillName}/SKILL.md\` - Load via \`/read .agents/skills/${skillName}/SKILL.md\`*\n`;
47
48
  return `\n## Skill: ${title}\n${descLine}${skillRef}`;
48
49
  }
49
50
 
@@ -68,23 +69,49 @@ function render(context) {
68
69
  }, 'markdown');
69
70
 
70
71
  // 1. .aider.conf.yml
71
- const aiderConfContent = [
72
- yamlProv,
73
- '# Load project conventions as a read-only context file on every session',
74
- 'read:',
75
- ' - CONVENTIONS.md',
76
- '',
77
- '# Auto commit edits with standard git format',
78
- 'auto-commits: true',
79
- 'dirty-commits: true',
80
- '',
81
- ].join('\n');
72
+ const existingAiderConfPath = path.join(projectRoot, '.aider.conf.yml');
73
+ let aiderConfContent = '';
74
+
75
+ if (fs.existsSync(existingAiderConfPath)) {
76
+ try {
77
+ const rawUserConf = fs.readFileSync(existingAiderConfPath, 'utf8');
78
+ const parsed = YAML.parse(rawUserConf) || {};
79
+
80
+ if (!parsed.read) {
81
+ parsed.read = ['CONVENTIONS.md'];
82
+ } else if (Array.isArray(parsed.read)) {
83
+ if (!parsed.read.includes('CONVENTIONS.md')) {
84
+ parsed.read.push('CONVENTIONS.md');
85
+ }
86
+ } else if (typeof parsed.read === 'string') {
87
+ if (parsed.read !== 'CONVENTIONS.md') {
88
+ parsed.read = [parsed.read, 'CONVENTIONS.md'];
89
+ }
90
+ }
91
+
92
+ aiderConfContent = yamlProv + '\n' + YAML.stringify(parsed);
93
+ } catch {
94
+ aiderConfContent = yamlProv + '\nread:\n - CONVENTIONS.md\n';
95
+ }
96
+ } else {
97
+ aiderConfContent = [
98
+ yamlProv,
99
+ '# Load project conventions as a read-only context file on every session',
100
+ 'read:',
101
+ ' - CONVENTIONS.md',
102
+ '',
103
+ '# Auto commit edits with standard git format',
104
+ 'auto-commits: true',
105
+ 'dirty-commits: true',
106
+ '',
107
+ ].join('\n');
108
+ }
82
109
 
83
110
  // 2. CONVENTIONS.md
84
111
  const convSections = [];
85
112
  convSections.push(
86
113
  mdProv +
87
- `# ContextOS — Project Conventions for Aider\n\n` +
114
+ `# ContextOS - Project Conventions for Aider\n\n` +
88
115
  `> **Core law: Do not read everything. Read only what the current task requires.**\n\n`
89
116
  );
90
117
 
@@ -97,7 +124,7 @@ function render(context) {
97
124
  `Skills are loaded on demand. Use \`/read .agents/skills/<skill>/SKILL.md\` when needed.\n\n` +
98
125
  `### Skill Index\n`);
99
126
 
100
- const skills = collectSkillDirectories(context?.profile);
127
+ const skills = collectSkillDirectories(context?.profile, context?.projectRoot);
101
128
  for (const skill of skills) {
102
129
  const section = buildSkillSection(skill);
103
130
  if (section) convSections.push(section);
@@ -54,7 +54,7 @@ function renderClaudeSkill(skillDir, context) {
54
54
  }
55
55
 
56
56
  function render(context) {
57
- const skills = collectSkillDirectories(context?.profile);
57
+ const skills = collectSkillDirectories(context?.profile, context?.projectRoot);
58
58
  const artifacts = [];
59
59
 
60
60
  for (const skill of skills) {
@@ -79,7 +79,7 @@ function render(context) {
79
79
  `| --- | --- | --- |\n`
80
80
  );
81
81
 
82
- const skills = collectSkillDirectories(context?.profile);
82
+ const skills = collectSkillDirectories(context?.profile, context?.projectRoot);
83
83
  for (const skill of skills) {
84
84
  const skillName = path.basename(skill);
85
85
  const yamlPath = path.join(skill, 'skill.yaml');
@@ -187,7 +187,7 @@ ${agentsMd}
187
187
  });
188
188
  }
189
189
 
190
- const skills = collectSkillDirectories(context?.profile);
190
+ const skills = collectSkillDirectories(context?.profile, context?.projectRoot);
191
191
  for (const skill of skills) {
192
192
  const mdc = generateCursorMdc(skill);
193
193
  if (mdc) {
@@ -23,6 +23,9 @@ const DRIFT_STATES = {
23
23
  ORPHAN_MANAGED_OUTPUT: 'ORPHAN_MANAGED_OUTPUT',
24
24
  ADAPTER_VERSION_MISMATCH: 'ADAPTER_VERSION_MISMATCH',
25
25
  PROFILE_MISMATCH: 'PROFILE_MISMATCH',
26
+ CORRUPT_LOCKFILE: 'CORRUPT_LOCKFILE',
27
+ EMPTY_PROJECTION: 'EMPTY_PROJECTION',
28
+ CONFIG_ERROR: 'CONFIG_ERROR',
26
29
  };
27
30
 
28
31
  /**
@@ -67,9 +70,6 @@ function computeDiffSnippet(beforeStr, afterStr, maxLines = 15) {
67
70
  function detectDrift(projectRoot, adapters = 'all', options = {}) {
68
71
  const absRoot = path.resolve(projectRoot);
69
72
  const lockManager = new LockfileV2Manager(absRoot);
70
- const lockfile = lockManager.read();
71
-
72
- const { artifacts, collisions, context } = renderAdapters(absRoot, adapters, options);
73
73
 
74
74
  const findings = {
75
75
  [DRIFT_STATES.STALE_INPUT]: [],
@@ -78,11 +78,57 @@ function detectDrift(projectRoot, adapters = 'all', options = {}) {
78
78
  [DRIFT_STATES.ORPHAN_MANAGED_OUTPUT]: [],
79
79
  [DRIFT_STATES.ADAPTER_VERSION_MISMATCH]: [],
80
80
  [DRIFT_STATES.PROFILE_MISMATCH]: [],
81
+ [DRIFT_STATES.CORRUPT_LOCKFILE]: [],
82
+ [DRIFT_STATES.EMPTY_PROJECTION]: [],
83
+ [DRIFT_STATES.CONFIG_ERROR]: [],
81
84
  };
82
85
 
83
86
  const diffs = [];
84
87
 
85
- // 1. Check Profile Mismatch
88
+ // 0. Safe lockfile load with corrupt lockfile detection
89
+ let lockfile = null;
90
+ try {
91
+ lockfile = lockManager.read();
92
+ } catch (err) {
93
+ findings[DRIFT_STATES.CORRUPT_LOCKFILE].push({
94
+ reason: `Lockfile is corrupt: ${err.message}`,
95
+ });
96
+ }
97
+
98
+ // 1. Adapter rendering with error containment
99
+ let rendered;
100
+ try {
101
+ rendered = renderAdapters(absRoot, adapters, options);
102
+ } catch (err) {
103
+ findings[DRIFT_STATES.CONFIG_ERROR].push({
104
+ reason: err.message,
105
+ });
106
+ return {
107
+ hasDrift: true,
108
+ hasError: true,
109
+ code: 2,
110
+ totalFindings: 1,
111
+ findings,
112
+ collisions: [],
113
+ diffs: [],
114
+ projectedCount: 0,
115
+ error: err.message,
116
+ };
117
+ }
118
+
119
+ const { artifacts, collisions, context } = rendered;
120
+
121
+ // 2. Empty projection check
122
+ if (artifacts.length === 0) {
123
+ const hasAgentsDir = fs.existsSync(path.join(absRoot, '.agents'));
124
+ if (hasAgentsDir) {
125
+ findings[DRIFT_STATES.EMPTY_PROJECTION].push({
126
+ reason: 'Projected artifact set is empty while .agents directory exists',
127
+ });
128
+ }
129
+ }
130
+
131
+ // 3. Check Profile Mismatch
86
132
  if (lockfile && lockfile.profile) {
87
133
  if (context.profileId && lockfile.profile.id !== context.profileId) {
88
134
  findings[DRIFT_STATES.PROFILE_MISMATCH].push({
@@ -92,7 +138,7 @@ function detectDrift(projectRoot, adapters = 'all', options = {}) {
92
138
  }
93
139
  }
94
140
 
95
- // 2. Check Stale Input (Source Graph Hash)
141
+ // 4. Check Stale Input (Source Graph Hash)
96
142
  if (lockfile && lockfile.sourceGraphHash) {
97
143
  if (context.sourceGraphHash && lockfile.sourceGraphHash !== context.sourceGraphHash) {
98
144
  findings[DRIFT_STATES.STALE_INPUT].push({
@@ -104,7 +150,7 @@ function detectDrift(projectRoot, adapters = 'all', options = {}) {
104
150
 
105
151
  const projectedPaths = new Set(artifacts.map(a => a.path));
106
152
 
107
- // 3. Inspect each projected artifact against disk and lockfile
153
+ // 5. Inspect each projected artifact against disk and lockfile
108
154
  for (const art of artifacts) {
109
155
  const fullPath = path.resolve(absRoot, art.path);
110
156
  const projectedContent = art.content.toString('utf8');
@@ -151,14 +197,32 @@ function detectDrift(projectRoot, adapters = 'all', options = {}) {
151
197
  }
152
198
  }
153
199
 
154
- // 4. Check for orphan files recorded in lockfile but no longer projected
200
+ // 6. Check for orphan files recorded in lockfile but no longer projected
201
+ // Task 1.4: Scoped strictly to the active adapters being checked
155
202
  if (lockfile && lockfile.managedFiles) {
203
+ const targetGenerators = new Set(artifacts.map(a => a.generator));
204
+ const adapterList = adapters === 'all' ? null : (Array.isArray(adapters) ? adapters : [adapters]);
205
+ const allowedPrefixes = adapterList ? adapterList.map(a => `${a}@`) : null;
206
+
156
207
  for (const [recordedPath, meta] of Object.entries(lockfile.managedFiles)) {
208
+ if (meta && meta.generator && allowedPrefixes) {
209
+ const matchesTarget = targetGenerators.has(meta.generator) ||
210
+ allowedPrefixes.some(p => meta.generator.startsWith(p));
211
+ if (!matchesTarget) {
212
+ continue; // Skip files from adapters not currently being verified
213
+ }
214
+ }
215
+
216
+ if (meta && meta.kind && meta.kind !== 'generated-adapter') {
217
+ continue;
218
+ }
219
+
157
220
  if (!projectedPaths.has(recordedPath)) {
158
221
  const fullRecorded = path.resolve(absRoot, recordedPath);
159
222
  if (fs.existsSync(fullRecorded)) {
160
223
  findings[DRIFT_STATES.ORPHAN_MANAGED_OUTPUT].push({
161
224
  path: recordedPath,
225
+ generator: meta.generator,
162
226
  reason: 'File recorded in lockfile is no longer generated by active skills/profile',
163
227
  });
164
228
  diffs.push({
@@ -178,9 +242,18 @@ function detectDrift(projectRoot, adapters = 'all', options = {}) {
178
242
 
179
243
  const totalFindings = Object.values(findings).reduce((acc, list) => acc + list.length, 0);
180
244
  const hasDrift = totalFindings > 0 || collisions.length > 0;
245
+ const hasError = findings[DRIFT_STATES.CORRUPT_LOCKFILE].length > 0 ||
246
+ findings[DRIFT_STATES.EMPTY_PROJECTION].length > 0 ||
247
+ findings[DRIFT_STATES.CONFIG_ERROR].length > 0;
248
+ const code = hasError ? 2 : (hasDrift ? 1 : 0);
249
+ const status = hasError ? 'error' : (hasDrift ? 'drift' : 'pass');
181
250
 
182
251
  return {
252
+ schemaVersion: '2.0.0',
253
+ status,
183
254
  hasDrift,
255
+ hasError,
256
+ code,
184
257
  totalFindings,
185
258
  findings,
186
259
  collisions,
@@ -103,7 +103,7 @@ ${mergedContent.trimStart()}
103
103
  }
104
104
 
105
105
  function render(context) {
106
- const skills = collectSkillDirectories(context?.profile);
106
+ const skills = collectSkillDirectories(context?.profile, context?.projectRoot);
107
107
  const artifacts = [];
108
108
 
109
109
  for (const skill of skills) {
@@ -139,6 +139,13 @@ function registerAdapter(name, adapter) {
139
139
  adaptersRegistry.set(name, adapter);
140
140
  }
141
141
 
142
+ /**
143
+ * Unregisters an adapter from the pure compiler registry.
144
+ */
145
+ function unregisterAdapter(name) {
146
+ adaptersRegistry.delete(name);
147
+ }
148
+
142
149
  /**
143
150
  * Retrieves a registered adapter.
144
151
  */
@@ -436,8 +443,11 @@ module.exports = {
436
443
  createProvenanceHeader,
437
444
  loadCompilerContext,
438
445
  registerAdapter,
446
+ unregisterAdapter,
439
447
  getAdapter,
440
448
  listAdapters,
441
449
  renderAdapters,
442
450
  applyArtifacts,
451
+ computeExactHash,
452
+ computeSemanticHash,
443
453
  };
@@ -12,17 +12,26 @@ const AGENTS_MD_PATH = path.join(AGENTS_DIR, 'AGENTS.md');
12
12
  * Plugins intentionally live outside `core/skills`, so adapters must use this
13
13
  * helper rather than enumerate the core directory themselves.
14
14
  */
15
- function collectSkillDirectories(overrideProfile = null) {
15
+ function collectSkillDirectories(overrideProfile = null, projectRoot = null) {
16
+ let profile = overrideProfile;
17
+ let root = projectRoot;
18
+
19
+ if (overrideProfile && typeof overrideProfile === 'object') {
20
+ if (overrideProfile.projectRoot && !root) {
21
+ root = overrideProfile.projectRoot;
22
+ }
23
+ }
24
+
25
+ const effectiveRoot = root ? path.resolve(root) : process.cwd();
16
26
  const plugins = require(path.join(AGENTS_DIR, 'plugins.js'));
17
- let dirs = plugins.collectAllSkillDirs()
27
+ let dirs = plugins.collectAllSkillDirs(effectiveRoot)
18
28
  .filter(dir => fs.existsSync(dir) && fs.statSync(dir).isDirectory())
19
29
  .sort((a, b) => path.basename(a).localeCompare(path.basename(b)));
20
30
 
21
- let profile = overrideProfile;
22
31
  if (!profile) {
23
32
  try {
24
33
  const profilesEngine = require(path.join(AGENTS_DIR, 'profiles.js'));
25
- profile = profilesEngine.getActiveProfile();
34
+ profile = profilesEngine.getActiveProfile(effectiveRoot);
26
35
  } catch {
27
36
  profile = null;
28
37
  }
@@ -95,7 +95,7 @@ function render(context) {
95
95
  `### Available Skills\n`
96
96
  );
97
97
 
98
- const skills = collectSkillDirectories(context?.profile);
98
+ const skills = collectSkillDirectories(context?.profile, context?.projectRoot);
99
99
  for (const skill of skills) {
100
100
  const res = buildSkillSection(skill);
101
101
  if (res) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "compilerVersion": "2.0.0",
4
- "sourceGraphHash": "sha256:c15f3691d9ed833630152b65959fdef465d88a7cf5bb27d44a086621e20c89c1",
4
+ "sourceGraphHash": "sha256:938c5051454535087e03f26af35c434cf194f414d2ec8044b4ae754e8524cf37",
5
5
  "skills": {
6
6
  "context-manager": {
7
7
  "id": "context-manager",
@@ -66,9 +66,9 @@
66
66
  "category": "general",
67
67
  "type": "compiler",
68
68
  "entrypoint": "SKILL.md",
69
- "entrypointHash": "sha256:f28a8b6df5cf6d0dc8b32d8e4149f866b59ee11da0c1c050f766a0009674ca86",
70
- "resourceTreeHash": "sha256:697cd51226283b147f719e2f4074acb058be1f3fe42714a3babb771e52e26a73",
71
- "estimatedTokens": 1227,
69
+ "entrypointHash": "sha256:ab14bcd603573c975a69cb95b5ef8a305de8eb888c81c20c994121313f017239",
70
+ "resourceTreeHash": "sha256:48568f01d27fa53e2e01a6a63afd60eb2d43cabdc9eb2cfe6f02a2b67d0f53e1",
71
+ "estimatedTokens": 1365,
72
72
  "source": ".agents/core/skills/context-os/skill.yaml",
73
73
  "signals": {
74
74
  "aliases": [
@@ -85,7 +85,7 @@
85
85
  },
86
86
  "context": {
87
87
  "priority": 50,
88
- "estimatedTokens": 1227
88
+ "estimatedTokens": 1365
89
89
  },
90
90
  "resources": [
91
91
  {
@@ -137,9 +137,9 @@
137
137
  "category": "general",
138
138
  "type": "instruction-only",
139
139
  "entrypoint": "SKILL.md",
140
- "entrypointHash": "sha256:0985a21360cdd796a2f2970b659b6a7a1cdd55672dd35b0292400f9a0092b556",
141
- "resourceTreeHash": "sha256:6e2e654c903e1043609c1f7f36980a19c1e20e35bc3fa337ad051293f1e9124c",
142
- "estimatedTokens": 3065,
140
+ "entrypointHash": "sha256:88b606d086f63c5e293630ad84ff524d2542f2953fc1a5a451bd77352073b0ad",
141
+ "resourceTreeHash": "sha256:e78a054d8f54a72550cf10d551a82f56015aedb3f16a14021e654574bad5804f",
142
+ "estimatedTokens": 3083,
143
143
  "source": ".agents/core/skills/engineering-workflow/skill.yaml",
144
144
  "signals": {
145
145
  "aliases": [
@@ -156,7 +156,7 @@
156
156
  },
157
157
  "context": {
158
158
  "priority": 50,
159
- "estimatedTokens": 3065
159
+ "estimatedTokens": 3083
160
160
  },
161
161
  "resources": [
162
162
  {
@@ -188,9 +188,9 @@
188
188
  "category": "general",
189
189
  "type": "instruction-only",
190
190
  "entrypoint": "SKILL.md",
191
- "entrypointHash": "sha256:677c7229e8b483990cf4b441b990328f5933127a7c449830fe2786cd232321c4",
192
- "resourceTreeHash": "sha256:38e0e3e512df2855647a083a6e0ae759a3af613b7f2e2848046b8d6998143539",
193
- "estimatedTokens": 1868,
191
+ "entrypointHash": "sha256:bd091c13a5c15c2ac55a8c27b309ffdd8e0a5a8b8260198808b70e45e685b9fd",
192
+ "resourceTreeHash": "sha256:8ae82b8dd89128820c8b28c7e9e8aac878f363381dd2a11043b8aff9d03ae35e",
193
+ "estimatedTokens": 1890,
194
194
  "source": ".agents/core/skills/gemini-precision/skill.yaml",
195
195
  "signals": {
196
196
  "aliases": [
@@ -207,13 +207,21 @@
207
207
  },
208
208
  "context": {
209
209
  "priority": 50,
210
- "estimatedTokens": 1868
210
+ "estimatedTokens": 1890
211
211
  },
212
212
  "resources": [
213
+ {
214
+ "path": "EXAMPLES.md",
215
+ "mode": "on-demand"
216
+ },
213
217
  {
214
218
  "path": "SKILL.md",
215
219
  "mode": "on-demand"
216
220
  },
221
+ {
222
+ "path": "TROUBLESHOOTING.md",
223
+ "mode": "on-demand"
224
+ },
217
225
  {
218
226
  "path": "VALIDATION.json",
219
227
  "mode": "on-demand"
@@ -231,9 +239,9 @@
231
239
  "category": "general",
232
240
  "type": "instruction-only",
233
241
  "entrypoint": "SKILL.md",
234
- "entrypointHash": "sha256:faaa89d02bf41416c173e6387e5c9c5065cfe4d82e76c2ae244b77c6cecd3230",
235
- "resourceTreeHash": "sha256:f83fba0726700070887643c7e20a0584ba29b0f96c2587bcd834860362ce7a95",
236
- "estimatedTokens": 1774,
242
+ "entrypointHash": "sha256:09334359de594f9c3e667ae0660db9a5c977c583b25ccf7de71fe25b7134454e",
243
+ "resourceTreeHash": "sha256:0bcfb511ef61a6782e3394c0779e5f5eed1833aff6e24c7749957df209c6185a",
244
+ "estimatedTokens": 1791,
237
245
  "source": ".agents/core/skills/gstack-roles/skill.yaml",
238
246
  "signals": {
239
247
  "aliases": [
@@ -250,7 +258,7 @@
250
258
  },
251
259
  "context": {
252
260
  "priority": 50,
253
- "estimatedTokens": 1774
261
+ "estimatedTokens": 1791
254
262
  },
255
263
  "resources": [
256
264
  {
@@ -333,9 +341,9 @@
333
341
  "category": "backend",
334
342
  "type": "instruction-only",
335
343
  "entrypoint": "SKILL.md",
336
- "entrypointHash": "sha256:151bc9080230cdec8e1de9d703d03b739ab0767e24fb2551acd5cf58feb4f3ab",
337
- "resourceTreeHash": "sha256:da5be685a6db8c48faeb74722891816960e4b6a86378b680f045a81a204ac572",
338
- "estimatedTokens": 1615,
344
+ "entrypointHash": "sha256:5daec60e9bb1c49a2b66e43d73e897397507e3604ef4bf02588d35cfd59b1903",
345
+ "resourceTreeHash": "sha256:b4302851046e1faffc18bc600c79d92d1da7f31bed03781eee89e84ddedc4956",
346
+ "estimatedTokens": 2237,
339
347
  "source": ".agents/core/skills/security/skill.yaml",
340
348
  "signals": {
341
349
  "aliases": [
@@ -403,7 +411,7 @@
403
411
  },
404
412
  "context": {
405
413
  "priority": 90,
406
- "estimatedTokens": 1615
414
+ "estimatedTokens": 2237
407
415
  },
408
416
  "resources": [
409
417
  {
@@ -421,10 +429,6 @@
421
429
  {
422
430
  "path": "VALIDATION.json",
423
431
  "mode": "on-demand"
424
- },
425
- {
426
- "path": "security.md",
427
- "mode": "on-demand"
428
432
  }
429
433
  ],
430
434
  "deprecated": false,