contextos-agents 1.6.1 → 1.7.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 (86) hide show
  1. package/.agents/AGENTS.md +5 -0
  2. package/.agents/adapters/aider/export.js +4 -2
  3. package/.agents/adapters/copilot/export.js +4 -2
  4. package/.agents/adapters/cursor/export.js +48 -12
  5. package/.agents/adapters/zed/export.js +53 -14
  6. package/.agents/core/skills/adapters/skill.yaml +6 -0
  7. package/.agents/core/skills/architecture-diagrams/skill.yaml +4 -0
  8. package/.agents/core/skills/brutalist-design/skill.yaml +4 -0
  9. package/.agents/core/skills/context-manager/references/context-rules.md +59 -0
  10. package/.agents/core/skills/context-manager/skill.yaml +7 -0
  11. package/.agents/core/skills/context-os/skill.yaml +11 -0
  12. package/.agents/core/skills/database/skill.yaml +6 -0
  13. package/.agents/core/skills/ddd/skill.yaml +7 -0
  14. package/.agents/core/skills/decisions/skill.yaml +6 -0
  15. package/.agents/core/skills/docker/skill.yaml +6 -0
  16. package/.agents/core/skills/engineering-workflow/SKILL.md +1 -1
  17. package/.agents/core/skills/engineering-workflow/skill.yaml +6 -0
  18. package/.agents/core/skills/fastapi/skill.yaml +7 -0
  19. package/.agents/core/skills/gemini-precision/SKILL.md +4 -0
  20. package/.agents/core/skills/gemini-precision/skill.yaml +4 -0
  21. package/.agents/core/skills/generators/skill.yaml +15 -0
  22. package/.agents/core/skills/graphify/SKILL.md +2 -2
  23. package/.agents/core/skills/graphify/skill.yaml +6 -1
  24. package/.agents/core/skills/gstack-roles/SKILL.md +3 -1
  25. package/.agents/core/skills/gstack-roles/skill.yaml +6 -0
  26. package/.agents/core/skills/impeccable-design/skill.yaml +6 -0
  27. package/.agents/core/skills/interview-me/skill.yaml +4 -0
  28. package/.agents/core/skills/microservices/skill.yaml +7 -0
  29. package/.agents/core/skills/minimalist-design/skill.yaml +4 -0
  30. package/.agents/core/skills/nestjs/skill.yaml +7 -0
  31. package/.agents/core/skills/nextjs/skill.yaml +7 -0
  32. package/.agents/core/skills/node/skill.yaml +7 -0
  33. package/.agents/core/skills/performance/skill.yaml +7 -0
  34. package/.agents/core/skills/ponytail-mindset/skill.yaml +6 -0
  35. package/.agents/core/skills/react/skill.yaml +7 -0
  36. package/.agents/core/skills/react-best-practices/skill.yaml +4 -0
  37. package/.agents/core/skills/redesign-audit/skill.yaml +4 -0
  38. package/.agents/core/skills/security/skill.yaml +7 -0
  39. package/.agents/core/skills/soft-design/skill.yaml +4 -0
  40. package/.agents/core/skills/state-management/skill.yaml +6 -0
  41. package/.agents/core/skills/subagent-orchestrator/SKILL.md +17 -0
  42. package/.agents/core/skills/subagent-orchestrator/skill.yaml +4 -0
  43. package/.agents/core/skills/system-design/skill.yaml +7 -0
  44. package/.agents/core/skills/testing/skill.yaml +6 -0
  45. package/.agents/core/skills/typescript/skill.yaml +7 -0
  46. package/.agents/core/skills/ui-design/skill.yaml +7 -0
  47. package/.agents/core/skills/ui-ux-pro/skill.yaml +6 -0
  48. package/.agents/core/skills/ux-design/skill.yaml +7 -0
  49. package/.agents/core/skills/vercel-optimize/scripts/collect-signals.mjs +131 -0
  50. package/.agents/core/skills/vercel-optimize/scripts/gate-investigations.mjs +142 -0
  51. package/.agents/core/skills/vercel-optimize/scripts/merge-signals.mjs +143 -0
  52. package/.agents/core/skills/vercel-optimize/scripts/scan-codebase.mjs +174 -0
  53. package/.agents/core/skills/vercel-optimize/skill.yaml +8 -0
  54. package/.agents/core/skills/web-accessibility/skill.yaml +7 -0
  55. package/.agents/ctx.js +14 -1
  56. package/.agents/doctor.js +193 -4
  57. package/.agents/generated/claude/skills/engineering-workflow/SKILL.md +1 -1
  58. package/.agents/generated/claude/skills/gemini-precision/SKILL.md +4 -0
  59. package/.agents/generated/claude/skills/graphify/SKILL.md +1 -1
  60. package/.agents/generated/claude/skills/gstack-roles/SKILL.md +3 -1
  61. package/.agents/generated/claude/skills/subagent-orchestrator/SKILL.md +17 -0
  62. package/.agents/generated/gemini/skills/engineering-workflow/SKILL.md +1 -1
  63. package/.agents/generated/gemini/skills/gemini-precision/SKILL.md +4 -0
  64. package/.agents/generated/gemini/skills/graphify/SKILL.md +2 -2
  65. package/.agents/generated/gemini/skills/gstack-roles/SKILL.md +3 -1
  66. package/.agents/generated/gemini/skills/subagent-orchestrator/SKILL.md +17 -0
  67. package/.agents/plugins/contextos/hooks.json +25 -0
  68. package/.agents/plugins/contextos/plugin.json +19 -0
  69. package/.agents/plugins.js +180 -20
  70. package/.agents/profiles.js +26 -0
  71. package/.agents/resolver.js +150 -30
  72. package/.agents/stats.js +22 -9
  73. package/.agents/validate.js +99 -13
  74. package/bin/commands/uninstall.js +207 -0
  75. package/bin/commands/update.js +262 -0
  76. package/bin/commands.js +305 -0
  77. package/bin/index.js +203 -83
  78. package/bin/lib/detector.js +106 -0
  79. package/bin/lib/lockfile.js +251 -0
  80. package/bin/lib/safe-writer.js +259 -0
  81. package/package.json +5 -6
  82. package/registry.json +13 -5
  83. package/registry.schema.json +3 -1
  84. package/.agents/mcp/runtime.py +0 -470
  85. package/.agents/mcp/server.mjs +0 -189271
  86. package/benchmarks/gemini-issues.js +0 -533
@@ -0,0 +1,251 @@
1
+ /**
2
+ * bin/lib/lockfile.js
3
+ * ContextOS Lockfile Engine & Provenance Tracking (schemaVersion: 1)
4
+ *
5
+ * Tracks files managed by ContextOS installations to ensure:
6
+ * - Zero data loss during updates (never overwrite user-modified files)
7
+ * - Safe uninstallation (never delete user-created files or modified managed files)
8
+ * - Transparent provenance for adapters and generated files
9
+ */
10
+
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+ const crypto = require('crypto');
14
+
15
+ const LOCKFILE_REL_PATH = '.agents/contextos.lock.json';
16
+
17
+ /**
18
+ * Normalize a relative path to standard POSIX-style relative path without leading ./
19
+ * e.g. ".agents\\core\\skills" -> ".agents/core/skills"
20
+ */
21
+ function normalizePath(relPath) {
22
+ if (!relPath) return '';
23
+ return relPath
24
+ .replace(/\\/g, '/')
25
+ .replace(/^\.\//, '')
26
+ .replace(/^\//, '');
27
+ }
28
+
29
+ /**
30
+ * Compute SHA-256 hash of a string or buffer.
31
+ * Automatically normalizes CRLF line endings to LF to ensure cross-platform reproducibility.
32
+ */
33
+ function computeHash(content) {
34
+ if (content === null || content === undefined) return '';
35
+ const normalized = typeof content === 'string'
36
+ ? content.replace(/\r\n/g, '\n')
37
+ : content;
38
+ return crypto.createHash('sha256').update(normalized).digest('hex');
39
+ }
40
+
41
+ /**
42
+ * Read a file and compute its SHA-256 hash (with CRLF normalization).
43
+ * Returns null if file does not exist or cannot be read.
44
+ */
45
+ function computeFileHash(filePath) {
46
+ try {
47
+ if (!fs.existsSync(filePath)) return null;
48
+ const content = fs.readFileSync(filePath, 'utf8');
49
+ return computeHash(content);
50
+ } catch {
51
+ return null;
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Create a fresh lockfile data structure.
57
+ */
58
+ function createLockfileData(options = {}) {
59
+ return {
60
+ schemaVersion: 1,
61
+ installedPackage: options.installedPackage || 'contextos-agents',
62
+ version: options.version || '1.7.0',
63
+ selectedProfile: options.selectedProfile || 'default',
64
+ installedAt: options.installedAt || new Date().toISOString(),
65
+ managedFiles: options.managedFiles ? { ...options.managedFiles } : {},
66
+ };
67
+ }
68
+
69
+ /**
70
+ * Record a managed file entry in the lockfile data.
71
+ */
72
+ function recordManagedFile(lockData, relPath, contentOrHash) {
73
+ if (!lockData || !relPath) return;
74
+ const norm = normalizePath(relPath);
75
+ const hash = typeof contentOrHash === 'string' && contentOrHash.length === 64 && /^[0-9a-f]{64}$/i.test(contentOrHash)
76
+ ? contentOrHash.toLowerCase()
77
+ : computeHash(contentOrHash);
78
+
79
+ lockData.managedFiles[norm] = {
80
+ sha256: hash,
81
+ managed: true,
82
+ };
83
+ }
84
+
85
+ /**
86
+ * Load and parse the lockfile from target project directory.
87
+ * Returns null if lockfile does not exist or is invalid.
88
+ */
89
+ function loadLockfile(projectDir) {
90
+ try {
91
+ const lockfilePath = path.join(projectDir, LOCKFILE_REL_PATH);
92
+ if (!fs.existsSync(lockfilePath)) return null;
93
+
94
+ const raw = fs.readFileSync(lockfilePath, 'utf8');
95
+ const parsed = JSON.parse(raw);
96
+
97
+ if (parsed && parsed.schemaVersion === 1 && typeof parsed.managedFiles === 'object') {
98
+ return parsed;
99
+ }
100
+ return null;
101
+ } catch {
102
+ return null;
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Save lockfile data to target project directory atomically.
108
+ */
109
+ function saveLockfile(projectDir, lockData) {
110
+ const lockfilePath = path.join(projectDir, LOCKFILE_REL_PATH);
111
+ const lockfileDir = path.dirname(lockfilePath);
112
+
113
+ if (!fs.existsSync(lockfileDir)) {
114
+ fs.mkdirSync(lockfileDir, { recursive: true });
115
+ }
116
+
117
+ const tmpPath = `${lockfilePath}.tmp-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
118
+ const content = JSON.stringify(lockData, null, 2) + '\n';
119
+
120
+ try {
121
+ fs.writeFileSync(tmpPath, content, 'utf8');
122
+ fs.renameSync(tmpPath, lockfilePath);
123
+ } catch (err) {
124
+ try {
125
+ if (fs.existsSync(tmpPath)) fs.unlinkSync(tmpPath);
126
+ } catch {}
127
+ // Fallback direct write
128
+ fs.writeFileSync(lockfilePath, content, 'utf8');
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Check if a given relative path is tracked as a managed file in the lockfile.
134
+ */
135
+ function isManagedFile(lockData, relPath) {
136
+ if (!lockData || !lockData.managedFiles) return false;
137
+ const norm = normalizePath(relPath);
138
+ return Boolean(lockData.managedFiles[norm]?.managed);
139
+ }
140
+
141
+ /**
142
+ * Check if a managed file has been modified by the user compared to its recorded installation hash.
143
+ * Returns false if file is unmanaged or does not exist on disk.
144
+ */
145
+ function isFileModified(projectDir, relPath, lockData) {
146
+ if (!lockData || !lockData.managedFiles) return false;
147
+ const norm = normalizePath(relPath);
148
+ const entry = lockData.managedFiles[norm];
149
+
150
+ if (!entry || !entry.managed) return false;
151
+
152
+ const fullPath = path.join(projectDir, norm);
153
+ if (!fs.existsSync(fullPath)) return false;
154
+
155
+ const diskHash = computeFileHash(fullPath);
156
+ if (!diskHash) return false;
157
+
158
+ return diskHash !== entry.sha256;
159
+ }
160
+
161
+ /**
162
+ * Classify a file into an explicit lifecycle state:
163
+ * - 'UNMANAGED': File not present in lockfile (e.g. user-created skill or config)
164
+ * - 'MANAGED_CLEAN': File present in lockfile and content matches installation hash
165
+ * - 'MANAGED_MODIFIED': File present in lockfile but modified on disk by user
166
+ * - 'MISSING': File present in lockfile but not found on disk
167
+ */
168
+ function classifyFile(projectDir, relPath, lockData) {
169
+ const norm = normalizePath(relPath);
170
+ const fullPath = path.join(projectDir, norm);
171
+ const exists = fs.existsSync(fullPath);
172
+ const managed = isManagedFile(lockData, norm);
173
+
174
+ if (!managed) return 'UNMANAGED';
175
+ if (!exists) return 'MISSING';
176
+
177
+ return isFileModified(projectDir, norm, lockData) ? 'MANAGED_MODIFIED' : 'MANAGED_CLEAN';
178
+ }
179
+
180
+ /**
181
+ * Safe migration helper for existing installations that lack a lockfile.
182
+ * Recursively scans target project's .agents directory, compares each file
183
+ * against the distribution sourceDir.
184
+ *
185
+ * ONLY files whose content hash exactly matches the distribution source are
186
+ * claimed as managed. User custom skills or edited files are left unmanaged.
187
+ */
188
+ function migrateExistingInstallation(projectDir, sourceAgentsDir, options = {}) {
189
+ const targetAgentsDir = path.join(projectDir, '.agents');
190
+ const lockData = createLockfileData(options);
191
+
192
+ if (!fs.existsSync(targetAgentsDir)) {
193
+ if (!options.inMemory && !options.dryRun) {
194
+ saveLockfile(projectDir, lockData);
195
+ }
196
+ return lockData;
197
+ }
198
+
199
+ function walk(currentDir) {
200
+ let entries;
201
+ try {
202
+ entries = fs.readdirSync(currentDir, { withFileTypes: true });
203
+ } catch {
204
+ return;
205
+ }
206
+
207
+ for (const entry of entries) {
208
+ const fullPath = path.join(currentDir, entry.name);
209
+ if (entry.isDirectory()) {
210
+ walk(fullPath);
211
+ } else if (entry.isFile()) {
212
+ // Skip lockfile itself
213
+ if (entry.name === 'contextos.lock.json') continue;
214
+
215
+ const relToAgents = path.relative(targetAgentsDir, fullPath).replace(/\\/g, '/');
216
+ const relToProject = `.agents/${relToAgents}`;
217
+
218
+ const sourceFile = path.join(sourceAgentsDir, relToAgents);
219
+ if (fs.existsSync(sourceFile) && fs.statSync(sourceFile).isFile()) {
220
+ const targetHash = computeFileHash(fullPath);
221
+ const sourceHash = computeFileHash(sourceFile);
222
+
223
+ if (targetHash && sourceHash && targetHash === sourceHash) {
224
+ recordManagedFile(lockData, relToProject, targetHash);
225
+ }
226
+ }
227
+ }
228
+ }
229
+ }
230
+
231
+ walk(targetAgentsDir);
232
+ if (!options.inMemory && !options.dryRun) {
233
+ saveLockfile(projectDir, lockData);
234
+ }
235
+ return lockData;
236
+ }
237
+
238
+ module.exports = {
239
+ LOCKFILE_REL_PATH,
240
+ normalizePath,
241
+ computeHash,
242
+ computeFileHash,
243
+ createLockfileData,
244
+ recordManagedFile,
245
+ loadLockfile,
246
+ saveLockfile,
247
+ isManagedFile,
248
+ isFileModified,
249
+ classifyFile,
250
+ migrateExistingInstallation,
251
+ };
@@ -0,0 +1,259 @@
1
+ /**
2
+ * bin/lib/safe-writer.js
3
+ * Safe Atomic File Writer & Conflict Management for ContextOS
4
+ *
5
+ * Implements non-destructive file writes and uninstalls:
6
+ * - Classified actions: CREATE, UPDATE, CONFLICT, SKIP, DELETE
7
+ * - Unmanaged user-created files are NEVER touched or deleted
8
+ * - User-modified managed files trigger sidecar (.contextos.new) without overwriting user work
9
+ * - Atomic write via temporary file + rename with rollback on failure
10
+ */
11
+
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+ const {
15
+ normalizePath,
16
+ computeHash,
17
+ computeFileHash,
18
+ classifyFile,
19
+ recordManagedFile,
20
+ isManagedFile,
21
+ } = require('./lockfile.js');
22
+
23
+ /**
24
+ * Atomically write content to a file with directory creation and rollback.
25
+ */
26
+ function atomicWriteFile(targetPath, content) {
27
+ const dir = path.dirname(targetPath);
28
+ if (!fs.existsSync(dir)) {
29
+ fs.mkdirSync(dir, { recursive: true });
30
+ }
31
+
32
+ const tmpPath = `${targetPath}.tmp-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
33
+ try {
34
+ fs.writeFileSync(tmpPath, content, 'utf8');
35
+ fs.renameSync(tmpPath, targetPath);
36
+ } catch (err) {
37
+ try {
38
+ if (fs.existsSync(tmpPath)) fs.unlinkSync(tmpPath);
39
+ } catch {}
40
+ // Direct write fallback
41
+ fs.writeFileSync(targetPath, content, 'utf8');
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Clean up empty parent directories up to the .agents boundary.
47
+ */
48
+ function cleanEmptyParentDirectories(filePath) {
49
+ let currentDir = path.dirname(filePath);
50
+ while (
51
+ currentDir &&
52
+ currentDir.includes('.agents') &&
53
+ !currentDir.endsWith('.agents') &&
54
+ !currentDir.endsWith('.agents/') &&
55
+ !currentDir.endsWith('.agents\\')
56
+ ) {
57
+ try {
58
+ const entries = fs.readdirSync(currentDir);
59
+ if (entries.length === 0) {
60
+ fs.rmdirSync(currentDir);
61
+ currentDir = path.dirname(currentDir);
62
+ } else {
63
+ break;
64
+ }
65
+ } catch {
66
+ break;
67
+ }
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Plan a file write operation against the current filesystem and lockfile state.
73
+ *
74
+ * Returns an ActionPlan:
75
+ * - 'CREATE': File does not exist on disk yet
76
+ * - 'SKIP': File exists and is either already identical ('UP_TO_DATE') or user-created ('UNMANAGED_USER_FILE')
77
+ * - 'UPDATE': Clean managed file with updated content
78
+ * - 'CONFLICT': Managed file that the user has customized; writes to .contextos.new
79
+ */
80
+ function planFileWrite({ projectDir, relPath, content, lockData, options = {} }) {
81
+ const normRel = normalizePath(relPath);
82
+ const fullPath = path.join(projectDir, normRel);
83
+ const newHash = computeHash(content);
84
+
85
+ if (!fs.existsSync(fullPath)) {
86
+ return {
87
+ action: 'CREATE',
88
+ relPath: normRel,
89
+ targetPath: fullPath,
90
+ newContent: content,
91
+ newHash,
92
+ reason: 'NEW_FILE',
93
+ };
94
+ }
95
+
96
+ const classification = classifyFile(projectDir, normRel, lockData);
97
+
98
+ if (classification === 'UNMANAGED') {
99
+ return {
100
+ action: 'SKIP',
101
+ relPath: normRel,
102
+ targetPath: fullPath,
103
+ reason: 'UNMANAGED_USER_FILE',
104
+ };
105
+ }
106
+
107
+ if (classification === 'MANAGED_MODIFIED') {
108
+ const conflictFullPath = `${fullPath}.contextos.new`;
109
+ const conflictRelPath = `${normRel}.contextos.new`;
110
+ return {
111
+ action: 'CONFLICT',
112
+ relPath: normRel,
113
+ targetPath: fullPath,
114
+ conflictFullPath,
115
+ conflictPath: conflictRelPath,
116
+ newContent: content,
117
+ newHash,
118
+ reason: 'USER_MODIFIED',
119
+ };
120
+ }
121
+
122
+ // MANAGED_CLEAN: check if content changed
123
+ const diskHash = computeFileHash(fullPath);
124
+ if (diskHash === newHash) {
125
+ return {
126
+ action: 'SKIP',
127
+ relPath: normRel,
128
+ targetPath: fullPath,
129
+ reason: 'UP_TO_DATE',
130
+ };
131
+ }
132
+
133
+ return {
134
+ action: 'UPDATE',
135
+ relPath: normRel,
136
+ targetPath: fullPath,
137
+ newContent: content,
138
+ oldHash: diskHash,
139
+ newHash,
140
+ reason: 'CONTENT_UPDATED',
141
+ };
142
+ }
143
+
144
+ /**
145
+ * Execute a planned file write operation.
146
+ */
147
+ function executeFileWrite(planItem, lockData, { dryRun = false } = {}) {
148
+ if (dryRun) {
149
+ return { ...planItem, executed: false, dryRun: true };
150
+ }
151
+
152
+ if (planItem.action === 'SKIP') {
153
+ return { ...planItem, executed: false };
154
+ }
155
+
156
+ if (planItem.action === 'CREATE' || planItem.action === 'UPDATE') {
157
+ atomicWriteFile(planItem.targetPath, planItem.newContent);
158
+ if (lockData) {
159
+ recordManagedFile(lockData, planItem.relPath, planItem.newHash || planItem.newContent);
160
+ }
161
+ return { ...planItem, executed: true };
162
+ }
163
+
164
+ if (planItem.action === 'CONFLICT') {
165
+ const conflictTarget = planItem.conflictFullPath || `${planItem.targetPath}.contextos.new`;
166
+ atomicWriteFile(conflictTarget, planItem.newContent);
167
+ return {
168
+ ...planItem,
169
+ executed: true,
170
+ conflictPath: planItem.conflictPath || `${planItem.relPath}.contextos.new`,
171
+ };
172
+ }
173
+
174
+ return { ...planItem, executed: false };
175
+ }
176
+
177
+ /**
178
+ * Plan a file deletion operation during uninstall or cleanup.
179
+ *
180
+ * Returns ActionPlan:
181
+ * - 'DELETE': Managed file whose disk content matches installation hash (clean)
182
+ * - 'SKIP': File is unmanaged ('UNMANAGED_USER_FILE'), modified by user ('USER_MODIFIED_PRESERVED'),
183
+ * or already gone ('ALREADY_MISSING').
184
+ */
185
+ function planFileDelete({ projectDir, relPath, lockData, options = {} }) {
186
+ const normRel = normalizePath(relPath);
187
+ const fullPath = path.join(projectDir, normRel);
188
+ const classification = classifyFile(projectDir, normRel, lockData);
189
+
190
+ if (classification === 'UNMANAGED') {
191
+ return {
192
+ action: 'SKIP',
193
+ relPath: normRel,
194
+ targetPath: fullPath,
195
+ reason: 'UNMANAGED_USER_FILE',
196
+ };
197
+ }
198
+
199
+ if (classification === 'MANAGED_MODIFIED') {
200
+ return {
201
+ action: 'SKIP',
202
+ relPath: normRel,
203
+ targetPath: fullPath,
204
+ reason: 'USER_MODIFIED_PRESERVED',
205
+ };
206
+ }
207
+
208
+ if (classification === 'MISSING') {
209
+ return {
210
+ action: 'SKIP',
211
+ relPath: normRel,
212
+ targetPath: fullPath,
213
+ reason: 'ALREADY_MISSING',
214
+ };
215
+ }
216
+
217
+ return {
218
+ action: 'DELETE',
219
+ relPath: normRel,
220
+ targetPath: fullPath,
221
+ reason: 'MANAGED_CLEAN',
222
+ };
223
+ }
224
+
225
+ /**
226
+ * Execute a planned file deletion operation.
227
+ */
228
+ function executeFileDelete(planItem, lockData, { dryRun = false } = {}) {
229
+ if (dryRun) {
230
+ return { ...planItem, executed: false, dryRun: true };
231
+ }
232
+
233
+ if (planItem.action === 'DELETE') {
234
+ if (fs.existsSync(planItem.targetPath)) {
235
+ try {
236
+ fs.unlinkSync(planItem.targetPath);
237
+ } catch (err) {
238
+ return { ...planItem, executed: false, error: err.message };
239
+ }
240
+ }
241
+
242
+ if (lockData && lockData.managedFiles) {
243
+ delete lockData.managedFiles[planItem.relPath];
244
+ }
245
+
246
+ cleanEmptyParentDirectories(planItem.targetPath);
247
+ return { ...planItem, executed: true };
248
+ }
249
+
250
+ return { ...planItem, executed: false };
251
+ }
252
+
253
+ module.exports = {
254
+ atomicWriteFile,
255
+ planFileWrite,
256
+ executeFileWrite,
257
+ planFileDelete,
258
+ executeFileDelete,
259
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "contextos-agents",
3
- "version": "1.6.1",
4
- "description": "Install a .agents folder into your project to teach AI assistants best practices: UI/UX, architecture, security, and engineering workflow skills.",
3
+ "version": "1.7.0",
4
+ "description": "ContextOS — Deterministic context compiler, MCP runtime, and high-precision agent skills for pair-programming.",
5
5
  "bin": {
6
6
  "contextos": "./bin/index.js",
7
7
  "contextos-agents": "./bin/index.js",
@@ -25,8 +25,7 @@
25
25
  ".agents/adapters",
26
26
  ".agents/core",
27
27
  ".agents/generated",
28
- ".agents/mcp",
29
- "benchmarks/gemini-issues.js"
28
+ ".agents/plugins/contextos"
30
29
  ],
31
30
  "scripts": {
32
31
  "build": "node .agents/ctx.js export all",
@@ -39,8 +38,8 @@
39
38
  "check:secrets": "node scripts/check-secrets.js --all",
40
39
  "setup:hooks": "node scripts/install-hooks.js",
41
40
  "watch": "node .agents/watch.js",
42
- "test": "node --test --test-concurrency=1 tests/install.test.js tests/export.test.js tests/skills.test.js tests/validate.test.js tests/plugins.test.js tests/benchmark.test.js tests/profile.test.js tests/resolver.test.js",
43
- "prepublishOnly": "npm run validate && cd contextos-mcp && npm install && npm run build:bundle && cd .. && npm run build"
41
+ "test": "node --test --test-concurrency=1 tests/install.test.js tests/lockfile.test.js tests/safe-writer.test.js tests/adapter-safety.test.js tests/update.test.js tests/uninstall.test.js tests/plugin-security.test.js tests/export.test.js tests/skills.test.js tests/validate.test.js tests/plugins.test.js tests/benchmark.test.js tests/profile.test.js tests/resolver.test.js tests/cli-registry.test.js tests/profile-enforcement.test.js tests/doctor-hardening.test.js",
42
+ "prepublishOnly": "cd contextos-mcp && npm install && npm run build && npm run build:root-sync && cd .. && npm run validate && npm run build"
44
43
  },
45
44
  "keywords": [
46
45
  "ai",
package/registry.json CHANGED
@@ -12,7 +12,9 @@
12
12
  "npm": null,
13
13
  "github": "kok-o/contextos-agents",
14
14
  "path": ".agents/core/skills/ponytail-mindset",
15
- "builtin": true
15
+ "builtin": true,
16
+ "type": "instruction-only",
17
+ "resources": ["EXAMPLES.md", "SKILL.md", "TROUBLESHOOTING.md", "VALIDATION.json"]
16
18
  },
17
19
  {
18
20
  "id": "koko-o/gstack-roles",
@@ -23,7 +25,9 @@
23
25
  "npm": null,
24
26
  "github": "kok-o/contextos-agents",
25
27
  "path": ".agents/core/skills/gstack-roles",
26
- "builtin": true
28
+ "builtin": true,
29
+ "type": "instruction-only",
30
+ "resources": ["EXAMPLES.md", "SKILL.md", "TROUBLESHOOTING.md", "VALIDATION.json"]
27
31
  },
28
32
  {
29
33
  "id": "koko-o/impeccable-design",
@@ -34,18 +38,22 @@
34
38
  "npm": null,
35
39
  "github": "kok-o/contextos-agents",
36
40
  "path": ".agents/core/skills/impeccable-design",
37
- "builtin": true
41
+ "builtin": true,
42
+ "type": "instruction-only",
43
+ "resources": ["EXAMPLES.md", "SKILL.md", "TROUBLESHOOTING.md", "VALIDATION.json"]
38
44
  },
39
45
  {
40
46
  "id": "koko-o/graphify",
41
47
  "name": "graphify",
42
- "description": "Codebase knowledge graph generator via Tree-sitter AST parsing and semantic indexing.",
48
+ "description": "Codebase knowledge graph generator and architecture mapping guide. Instructs agents on AST dependency extraction and blast radius analysis.",
43
49
  "author": "koko-o",
44
50
  "tags": ["knowledge-graph", "ast", "tree-sitter", "dependencies", "architecture"],
45
51
  "npm": null,
46
52
  "github": "kok-o/contextos-agents",
47
53
  "path": ".agents/core/skills/graphify",
48
- "builtin": true
54
+ "builtin": true,
55
+ "type": "instruction-only",
56
+ "resources": ["EXAMPLES.md", "SKILL.md", "VALIDATION.json"]
49
57
  }
50
58
  ],
51
59
  "contributing": "https://github.com/kok-o/contextos-agents/blob/main/CONTRIBUTING.md#publishing-a-skill-as-a-plugin",
@@ -25,7 +25,9 @@
25
25
  "npm": { "type": ["string", "null"], "description": "npm package name if published" },
26
26
  "github": { "type": ["string", "null"], "description": "GitHub repo in owner/repo format" },
27
27
  "path": { "type": ["string", "null"], "description": "Path within the GitHub repo to the skill directory" },
28
- "builtin": { "type": "boolean", "description": "true = ships with contextos-agents core" }
28
+ "builtin": { "type": "boolean", "description": "true = ships with contextos-agents core" },
29
+ "type": { "type": "string", "enum": ["instruction-only", "compiler", "runtime", "experimental"], "description": "Skill capability model" },
30
+ "resources": { "type": "array", "items": { "type": "string" }, "description": "Explicit manifest of files bundled with this skill" }
29
31
  }
30
32
  }
31
33
  }