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.
- package/.agents/AGENTS.md +53 -33
- package/.agents/adapters/aider/export.js +41 -14
- package/.agents/adapters/claude/export.js +1 -1
- package/.agents/adapters/copilot/export.js +1 -1
- package/.agents/adapters/cursor/export.js +1 -1
- package/.agents/adapters/drift-detector.js +80 -7
- package/.agents/adapters/gemini/export.js +1 -1
- package/.agents/adapters/pure-compiler.js +10 -0
- package/.agents/adapters/shared.js +13 -4
- package/.agents/adapters/zed/export.js +1 -1
- package/.agents/compiled/registry.v2.json +29 -25
- package/.agents/compiled/registry.v2.sha256 +1 -1
- package/.agents/core/skills/context-os/SKILL.md +34 -37
- package/.agents/core/skills/engineering-workflow/SKILL.md +24 -24
- package/.agents/core/skills/gemini-precision/EXAMPLES.md +72 -0
- package/.agents/core/skills/gemini-precision/SKILL.md +2 -1
- package/.agents/core/skills/gemini-precision/TROUBLESHOOTING.md +25 -0
- package/.agents/core/skills/gemini-precision/skill.yaml +2 -0
- package/.agents/core/skills/gstack-roles/SKILL.md +7 -6
- package/.agents/core/skills/security/SKILL.md +44 -16
- package/.agents/core/skills/security/skill.yaml +0 -1
- package/.agents/ctx.js +16 -10
- package/.agents/generated/claude/skills/context-os/SKILL.md +34 -37
- package/.agents/generated/claude/skills/engineering-workflow/SKILL.md +24 -24
- package/.agents/generated/claude/skills/gemini-precision/SKILL.md +102 -1
- package/.agents/generated/claude/skills/gstack-roles/SKILL.md +7 -6
- package/.agents/generated/claude/skills/security/SKILL.md +44 -16
- package/.agents/generated/gemini/skills/context-os/SKILL.md +34 -37
- package/.agents/generated/gemini/skills/engineering-workflow/SKILL.md +24 -24
- package/.agents/generated/gemini/skills/gemini-precision/SKILL.md +105 -1
- package/.agents/generated/gemini/skills/gstack-roles/SKILL.md +7 -6
- package/.agents/generated/gemini/skills/security/SKILL.md +44 -125
- package/.agents/plugins.js +5 -4
- package/.agents/resolver/canonical-resolver.js +7 -7
- package/.agents/validate.js +69 -1
- package/README.md +80 -23
- package/bin/commands/hook.js +129 -0
- package/bin/commands/scan.js +70 -0
- package/bin/commands.js +39 -1
- package/bin/index.js +144 -33
- package/bin/lib/gate.js +171 -0
- package/bin/lib/git-snapshot.js +187 -0
- package/bin/lib/scan.js +380 -0
- package/package.json +4 -2
- package/.agents/core/skills/security/security.md +0 -106
package/.agents/AGENTS.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ContextOS
|
|
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
|
|
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 (
|
|
31
|
+
## Skill Architecture (High Fidelity & Progressive Disclosure)
|
|
32
32
|
|
|
33
|
-
Skills
|
|
34
|
-
1. **
|
|
35
|
-
2. **
|
|
36
|
-
3. **
|
|
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**
|
|
47
|
-
| **gstack-roles** | `gstack-roles/SKILL.md` | **Every task**
|
|
48
|
-
| **ponytail-mindset** | `ponytail-mindset/SKILL.md` | **Every BUILD phase**
|
|
49
|
-
| **gemini-precision** | `gemini-precision/SKILL.md` | **All Gemini tasks**
|
|
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**
|
|
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
|
|
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
|
|
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
|
|
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
|
|
240
|
-
- Typography rules T1
|
|
241
|
-
- Color rules C1
|
|
242
|
-
- Layout rules L1
|
|
243
|
-
- Component rules K1
|
|
244
|
-
- Animation rules A1
|
|
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
|
|
349
|
+
- No `// TODO` in committed code - create a tracked issue instead
|
|
330
350
|
- All async operations have explicit error handling
|
|
331
|
-
- No secrets hardcoded
|
|
351
|
+
- No secrets hardcoded - use environment variables
|
|
332
352
|
|
|
333
353
|
### Security
|
|
334
|
-
- Auth check BEFORE any data access
|
|
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
|
|
356
|
+
- SQL queries use parameterized form - no string concatenation
|
|
337
357
|
|
|
338
358
|
### Design
|
|
339
|
-
- No arbitrary Tailwind values (`gap-[17px]`)
|
|
340
|
-
- No hardcoded z-indexes (`z-[999]`)
|
|
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**
|
|
352
|
-
- **DONE_WITH_CONCERNS**
|
|
353
|
-
- **BLOCKED**
|
|
354
|
-
- **NEEDS_CONTEXT**
|
|
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\`
|
|
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
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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:
|
|
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:
|
|
70
|
-
"resourceTreeHash": "sha256:
|
|
71
|
-
"estimatedTokens":
|
|
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":
|
|
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:
|
|
141
|
-
"resourceTreeHash": "sha256:
|
|
142
|
-
"estimatedTokens":
|
|
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":
|
|
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:
|
|
192
|
-
"resourceTreeHash": "sha256:
|
|
193
|
-
"estimatedTokens":
|
|
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":
|
|
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:
|
|
235
|
-
"resourceTreeHash": "sha256:
|
|
236
|
-
"estimatedTokens":
|
|
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":
|
|
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:
|
|
337
|
-
"resourceTreeHash": "sha256:
|
|
338
|
-
"estimatedTokens":
|
|
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":
|
|
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,
|