contextos-agents 1.6.0 → 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 (88) 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/profiles/mvp.yaml +1 -0
  7. package/.agents/core/skills/adapters/skill.yaml +6 -0
  8. package/.agents/core/skills/architecture-diagrams/skill.yaml +4 -0
  9. package/.agents/core/skills/brutalist-design/skill.yaml +4 -0
  10. package/.agents/core/skills/context-manager/references/context-rules.md +59 -0
  11. package/.agents/core/skills/context-manager/skill.yaml +7 -0
  12. package/.agents/core/skills/context-os/skill.yaml +11 -0
  13. package/.agents/core/skills/database/skill.yaml +6 -0
  14. package/.agents/core/skills/ddd/skill.yaml +7 -0
  15. package/.agents/core/skills/decisions/skill.yaml +6 -0
  16. package/.agents/core/skills/docker/skill.yaml +6 -0
  17. package/.agents/core/skills/engineering-workflow/SKILL.md +1 -1
  18. package/.agents/core/skills/engineering-workflow/skill.yaml +6 -0
  19. package/.agents/core/skills/fastapi/skill.yaml +7 -0
  20. package/.agents/core/skills/gemini-precision/SKILL.md +4 -0
  21. package/.agents/core/skills/gemini-precision/skill.yaml +4 -0
  22. package/.agents/core/skills/generators/skill.yaml +15 -0
  23. package/.agents/core/skills/graphify/SKILL.md +2 -2
  24. package/.agents/core/skills/graphify/skill.yaml +6 -1
  25. package/.agents/core/skills/gstack-roles/SKILL.md +3 -1
  26. package/.agents/core/skills/gstack-roles/skill.yaml +6 -0
  27. package/.agents/core/skills/impeccable-design/skill.yaml +6 -0
  28. package/.agents/core/skills/interview-me/skill.yaml +4 -0
  29. package/.agents/core/skills/microservices/skill.yaml +7 -0
  30. package/.agents/core/skills/minimalist-design/skill.yaml +4 -0
  31. package/.agents/core/skills/nestjs/skill.yaml +7 -0
  32. package/.agents/core/skills/nextjs/skill.yaml +7 -0
  33. package/.agents/core/skills/node/skill.yaml +7 -0
  34. package/.agents/core/skills/performance/skill.yaml +7 -0
  35. package/.agents/core/skills/ponytail-mindset/skill.yaml +6 -0
  36. package/.agents/core/skills/react/skill.yaml +7 -0
  37. package/.agents/core/skills/react-best-practices/skill.yaml +4 -0
  38. package/.agents/core/skills/redesign-audit/skill.yaml +4 -0
  39. package/.agents/core/skills/security/skill.yaml +7 -0
  40. package/.agents/core/skills/soft-design/skill.yaml +4 -0
  41. package/.agents/core/skills/state-management/skill.yaml +6 -0
  42. package/.agents/core/skills/subagent-orchestrator/SKILL.md +17 -0
  43. package/.agents/core/skills/subagent-orchestrator/skill.yaml +4 -0
  44. package/.agents/core/skills/system-design/skill.yaml +7 -0
  45. package/.agents/core/skills/testing/skill.yaml +6 -0
  46. package/.agents/core/skills/typescript/skill.yaml +7 -0
  47. package/.agents/core/skills/ui-design/skill.yaml +7 -0
  48. package/.agents/core/skills/ui-ux-pro/skill.yaml +6 -0
  49. package/.agents/core/skills/ux-design/skill.yaml +7 -0
  50. package/.agents/core/skills/vercel-optimize/scripts/collect-signals.mjs +131 -0
  51. package/.agents/core/skills/vercel-optimize/scripts/gate-investigations.mjs +142 -0
  52. package/.agents/core/skills/vercel-optimize/scripts/merge-signals.mjs +143 -0
  53. package/.agents/core/skills/vercel-optimize/scripts/scan-codebase.mjs +174 -0
  54. package/.agents/core/skills/vercel-optimize/skill.yaml +8 -0
  55. package/.agents/core/skills/web-accessibility/skill.yaml +7 -0
  56. package/.agents/ctx.js +44 -0
  57. package/.agents/doctor.js +193 -4
  58. package/.agents/generated/claude/skills/engineering-workflow/SKILL.md +1 -1
  59. package/.agents/generated/claude/skills/gemini-precision/SKILL.md +4 -0
  60. package/.agents/generated/claude/skills/graphify/SKILL.md +1 -1
  61. package/.agents/generated/claude/skills/gstack-roles/SKILL.md +3 -1
  62. package/.agents/generated/claude/skills/subagent-orchestrator/SKILL.md +17 -0
  63. package/.agents/generated/gemini/skills/engineering-workflow/SKILL.md +1 -1
  64. package/.agents/generated/gemini/skills/gemini-precision/SKILL.md +4 -0
  65. package/.agents/generated/gemini/skills/graphify/SKILL.md +2 -2
  66. package/.agents/generated/gemini/skills/gstack-roles/SKILL.md +3 -1
  67. package/.agents/generated/gemini/skills/subagent-orchestrator/SKILL.md +17 -0
  68. package/.agents/plugins/contextos/hooks.json +25 -0
  69. package/.agents/plugins/contextos/plugin.json +19 -0
  70. package/.agents/plugins.js +180 -20
  71. package/.agents/profiles.js +26 -0
  72. package/.agents/resolver.js +150 -30
  73. package/.agents/stats.js +22 -9
  74. package/.agents/validate.js +152 -13
  75. package/README.md +77 -47
  76. package/bin/commands/uninstall.js +207 -0
  77. package/bin/commands/update.js +262 -0
  78. package/bin/commands.js +305 -0
  79. package/bin/index.js +275 -119
  80. package/bin/lib/detector.js +106 -0
  81. package/bin/lib/lockfile.js +251 -0
  82. package/bin/lib/safe-writer.js +259 -0
  83. package/package.json +6 -9
  84. package/registry.json +13 -5
  85. package/registry.schema.json +3 -1
  86. package/.agents/mcp/runtime.py +0 -470
  87. package/.agents/mcp/server.mjs +0 -189386
  88. package/benchmarks/gemini-issues.js +0 -533
package/bin/index.js CHANGED
@@ -4,6 +4,9 @@ const fs = require('fs');
4
4
  const path = require('path');
5
5
  const { version } = require('../package.json');
6
6
  const profiles = require('../.agents/profiles.js');
7
+ const { isKnownCommand, getStatus, formatStatusText } = require('./commands.js');
8
+ const { detectProjectAttributes } = require('./lib/detector.js');
9
+ const lockfileLib = require('./lib/lockfile.js');
7
10
 
8
11
  // ── CLI argument parsing ──────────────────────────────────────────────────────
9
12
  const args = process.argv.slice(2);
@@ -15,7 +18,12 @@ const flags = {
15
18
  skipCompile: args.includes('--skip-compile'),
16
19
  auto: args.includes('--auto'),
17
20
  minimal: args.includes('--minimal'),
21
+ json: args.includes('--json'),
18
22
  withMcp: args.includes('--with-mcp') || args.includes('--mcp'),
23
+ agent: (() => {
24
+ const i = args.indexOf('--agent');
25
+ return i !== -1 ? args[i + 1] : null;
26
+ })(),
19
27
  profile: (() => {
20
28
  const i = args.indexOf('--profile');
21
29
  return i !== -1 ? args[i + 1] : null;
@@ -28,7 +36,11 @@ const flags = {
28
36
 
29
37
  // ── Help / Version ────────────────────────────────────────────────────────────
30
38
  if (flags.ver) {
31
- console.log(`contextos-agents v${version}`);
39
+ if (flags.json) {
40
+ console.log(JSON.stringify({ package: 'contextos-agents', version }));
41
+ } else {
42
+ console.log(`contextos-agents v${version}`);
43
+ }
32
44
  process.exit(0);
33
45
  }
34
46
 
@@ -38,12 +50,15 @@ contextos / contextos-agents v${version}
38
50
  Install AI assistant skills and rules into your project.
39
51
 
40
52
  Usage:
41
- npx contextos [options]
53
+ npx contextos-agents init [options]
54
+ npx contextos-agents <command> [args...]
42
55
  contextos <command> [args...]
43
56
 
44
57
  Options:
45
58
  --help, -h Show this help message
46
59
  --version, -v Show version number
60
+ --json Output machine-readable JSON format
61
+ --agent <name> Target AI agent or IDE (gemini, claude, cursor, auto)
47
62
  --dry-run Preview what will be copied without making changes
48
63
  --force Overwrite an existing .agents/ folder
49
64
  --minimal Install only 5 core skills (lightweight footprint)
@@ -54,6 +69,10 @@ Options:
54
69
  --add-skill <ref> Install a community plugin skill after setup
55
70
 
56
71
  Commands:
72
+ init Install and configure .agents/ in target project
73
+ status Display project configuration, active profile, and lockfile status
74
+ update Safely update skills without overwriting custom changes
75
+ uninstall Safely uninstall ContextOS files (preserves user custom skills)
57
76
  doctor Run full project diagnostic health check
58
77
  audit Validate local skills (alias for validate)
59
78
  validate Validate local skills, frontmatter, and sync
@@ -62,7 +81,7 @@ Commands:
62
81
  resolve <prompt> Dynamically resolve minimal skills for a prompt or files
63
82
  stats Display token context savings report
64
83
  watch Start continuous file watcher and auto-sync daemon
65
- detect Analyze project and display detected tech stack
84
+ detect Analyze project and display detected tech stack & IDE
66
85
  install-skill Interactive skill installer (or pass <ref> / --from-repo)
67
86
  setup-mcp Add MCP execution server to an existing .agents/ project
68
87
 
@@ -82,12 +101,12 @@ Plugin ref formats:
82
101
  @scope/npm-package A scoped npm skill package
83
102
 
84
103
  Examples:
85
- npx contextos Install .agents/ into current project
86
- npx contextos --minimal Install only 5 core essential skills
87
- npx contextos --profile startup Install with startup profile
88
- contextos doctor Run project health check
89
- contextos export gemini Compile skills for Gemini
90
- contextos profile list List available profiles
104
+ npx contextos-agents init Install .agents/ with auto-detected stack
105
+ npx contextos-agents init --agent auto Install and configure for detected stack & IDE
106
+ npx contextos-agents init --minimal Install only 5 core essential skills
107
+ npx contextos status Show project configuration and lockfile status
108
+ npx contextos doctor Run project health check
109
+ npx contextos export gemini Compile skills for Gemini
91
110
  `);
92
111
  process.exit(0);
93
112
  }
@@ -95,53 +114,61 @@ Examples:
95
114
  // ── Top-level Commands & Proxy Routing ────────────────────────────────────────
96
115
  const mainCommand = args[0] && !args[0].startsWith('-') ? args[0] : null;
97
116
 
98
- // Doctor diagnostic health check
99
- if (mainCommand === 'doctor') {
100
- let doctorModule;
101
- const localDoctor = path.join(process.cwd(), '.agents', 'doctor.js');
102
- if (fs.existsSync(localDoctor)) {
103
- doctorModule = require(localDoctor);
117
+ // Unknown command check
118
+ if (mainCommand && mainCommand !== 'init' && !isKnownCommand(mainCommand)) {
119
+ if (flags.json) {
120
+ console.error(JSON.stringify({ error: `Unknown command: ${mainCommand}`, code: 1 }));
104
121
  } else {
105
- doctorModule = require('../.agents/doctor.js');
122
+ console.error(`[ERROR] Unknown command: ${mainCommand}`);
123
+ console.error(' Run `npx contextos-agents --help` to view available commands.');
106
124
  }
107
- doctorModule.runDoctor(process.cwd());
108
- process.exit(0);
125
+ process.exit(1);
109
126
  }
110
127
 
111
- // Context savings statistics report
112
- if (mainCommand === 'stats') {
113
- let statsModule;
114
- const localStats = path.join(process.cwd(), '.agents', 'stats.js');
115
- if (fs.existsSync(localStats)) {
116
- statsModule = require(localStats);
128
+ // Status command
129
+ if (mainCommand === 'status') {
130
+ const status = getStatus(process.cwd());
131
+ if (flags.json) {
132
+ console.log(JSON.stringify(status, null, 2));
117
133
  } else {
118
- statsModule = require('../.agents/stats.js');
134
+ console.log(formatStatusText(status));
119
135
  }
120
- statsModule.runStats(process.cwd());
121
136
  process.exit(0);
122
137
  }
123
138
 
124
- // Background auto-sync file watcher daemon
125
- if (mainCommand === 'watch') {
126
- let watchModule;
127
- const localWatch = path.join(process.cwd(), '.agents', 'watch.js');
128
- if (fs.existsSync(localWatch)) {
129
- watchModule = require(localWatch);
139
+ // Detect command
140
+ if (mainCommand === 'detect') {
141
+ const detection = detectProjectAttributes(process.cwd());
142
+ if (flags.json) {
143
+ console.log(JSON.stringify(detection, null, 2));
130
144
  } else {
131
- watchModule = require('../.agents/watch.js');
145
+ console.log('\nContextOS — Tech Stack & Environment Detection\n');
146
+ console.log(` Detected Technologies : ${detection.summary.technologies.join(', ')}`);
147
+ console.log(` Detected Environments : ${detection.summary.ides.join(', ')}`);
148
+ console.log(` Recommended Profile : ${detection.summary.recommendedProfile}`);
149
+ console.log(` Recommended Agents : ${detection.summary.recommendedAgents.join(', ')}`);
150
+ console.log(` Recommended Skills : ${detection.summary.recommendedSkills.join(', ')}\n`);
132
151
  }
133
- watchModule.runWatch(process.cwd());
152
+ process.exit(0);
153
+ }
154
+
155
+ // Doctor command
156
+ if (mainCommand === 'doctor') {
157
+ const doctorModule = require('../.agents/doctor.js');
158
+ const result = doctorModule.runDoctor(process.cwd(), { json: flags.json });
159
+ process.exit(result && result.ok === false ? 1 : 0);
134
160
  }
135
161
 
136
162
  // Proxy commands to .agents/ctx.js when executed in a ContextOS project
137
- const PROXY_COMMANDS = ['profile', 'export', 'validate', 'resolve', 'skill', 'index', 'clean-worktrees'];
138
- if (mainCommand && PROXY_COMMANDS.includes(mainCommand)) {
139
- const ctxPath = path.join(process.cwd(), '.agents', 'ctx.js');
140
- if (!fs.existsSync(ctxPath)) {
141
- console.error('[ERROR] .agents/ctx.js not found in current directory.');
142
- console.error(' Are you in a ContextOS project? Run `contextos` or `npx contextos-agents` first.');
143
- process.exit(1);
144
- }
163
+ const PROXY_COMMANDS = [
164
+ 'profile', 'export', 'validate', 'resolve', 'skill', 'index',
165
+ 'clean-worktrees', 'stats', 'watch'
166
+ ];
167
+
168
+ const ctxPath = path.join(process.cwd(), '.agents', 'ctx.js');
169
+ const hasLocalCtx = fs.existsSync(ctxPath);
170
+
171
+ if (mainCommand && PROXY_COMMANDS.includes(mainCommand) && hasLocalCtx) {
145
172
  const { execFileSync } = require('child_process');
146
173
  try {
147
174
  execFileSync(process.execPath, [ctxPath, ...args], { stdio: 'inherit' });
@@ -151,9 +178,45 @@ if (mainCommand && PROXY_COMMANDS.includes(mainCommand)) {
151
178
  process.exit(0);
152
179
  }
153
180
 
181
+ // Fallbacks when running outside an initialized .agents/ directory
182
+ if (mainCommand === 'update') {
183
+ const { runUpdate } = require('./commands/update.js');
184
+ runUpdate(process.cwd(), {
185
+ dryRun: flags.dryRun,
186
+ skipCompile: flags.skipCompile,
187
+ profile: flags.profile,
188
+ });
189
+ process.exit(0);
190
+ }
191
+
192
+ if (mainCommand === 'uninstall') {
193
+ const { runUninstall } = require('./commands/uninstall.js');
194
+ runUninstall(process.cwd(), {
195
+ dryRun: flags.dryRun,
196
+ });
197
+ process.exit(0);
198
+ }
199
+
200
+ if (mainCommand === 'stats') {
201
+ const statsModule = require('../.agents/stats.js');
202
+ statsModule.runStats(process.cwd());
203
+ process.exit(0);
204
+ }
205
+
206
+ if (mainCommand === 'watch') {
207
+ const watchModule = require('../.agents/watch.js');
208
+ watchModule.runWatch(process.cwd());
209
+ }
210
+
211
+ const PROJECT_ONLY_COMMANDS = ['profile', 'export', 'validate', 'resolve', 'skill', 'index', 'clean-worktrees'];
212
+ if (mainCommand && PROJECT_ONLY_COMMANDS.includes(mainCommand) && !hasLocalCtx) {
213
+ console.error('[ERROR] .agents/ctx.js not found in current directory.');
214
+ console.error(' Are you in a ContextOS project? Run `contextos` or `npx contextos-agents` first.');
215
+ process.exit(1);
216
+ }
217
+
154
218
  if (mainCommand === 'audit') {
155
- const ctxPath = path.join(process.cwd(), '.agents', 'ctx.js');
156
- if (!fs.existsSync(ctxPath)) {
219
+ if (!hasLocalCtx) {
157
220
  console.error('[ERROR] .agents/ctx.js not found. Are you in a ContextOS project?');
158
221
  process.exit(1);
159
222
  }
@@ -166,15 +229,6 @@ if (mainCommand === 'audit') {
166
229
  process.exit(0);
167
230
  }
168
231
 
169
- if (mainCommand === 'detect') {
170
- const stack = profiles.detectStack(process.cwd());
171
- console.log('\nContextOS — Tech Stack Detection\n');
172
- console.log(` Detected Technologies : ${stack.detected.length ? stack.detected.join(', ') : 'Generic JavaScript'}`);
173
- console.log(` Recommended Profile : ${stack.recommendedProfile}`);
174
- console.log(` Recommended Skills : ${stack.recommendedSkills.join(', ')}\n`);
175
- process.exit(0);
176
- }
177
-
178
232
  if (mainCommand === 'install-skill') {
179
233
  const ctxPath = path.join(process.cwd(), '.agents', 'ctx.js');
180
234
  if (!fs.existsSync(ctxPath)) {
@@ -198,10 +252,10 @@ if (mainCommand === 'install-skill') {
198
252
  }
199
253
  process.exit(0);
200
254
  } else {
201
- // Interactive menu
255
+ // Interactive menu using standard library readline
202
256
  (async () => {
203
257
  try {
204
- const inquirer = require('inquirer');
258
+ const readline = require('readline');
205
259
  const https = require('https');
206
260
 
207
261
  console.log('Fetching community skills from registry...');
@@ -210,33 +264,68 @@ if (mainCommand === 'install-skill') {
210
264
  https.get('https://raw.githubusercontent.com/kok-o/contextos-agents/main/registry.json', (res) => {
211
265
  let data = '';
212
266
  res.on('data', chunk => data += chunk);
213
- res.on('end', () => resolve(JSON.parse(data)));
267
+ res.on('end', () => {
268
+ try {
269
+ resolve(JSON.parse(data));
270
+ } catch (err) {
271
+ reject(err);
272
+ }
273
+ });
214
274
  }).on('error', reject);
215
275
  });
216
276
 
217
277
  const registry = await fetchRegistry();
218
- const choices = registry.skills.map(s => ({
219
- name: `${s.name} - ${s.description}`,
278
+ const skillsList = (registry.skills || []).map((s, idx) => ({
279
+ idx: idx + 1,
280
+ name: s.name,
281
+ desc: s.description || '',
220
282
  value: s.github ? `${s.github}${s.path ? '/' + s.path : ''}` : s.npm
221
283
  }));
222
-
223
- const answers = await inquirer.prompt([
224
- {
225
- type: 'checkbox',
226
- name: 'selectedSkills',
227
- message: 'Select skills to install:',
228
- choices
229
- }
230
- ]);
231
-
232
- if (!answers.selectedSkills || answers.selectedSkills.length === 0) {
233
- console.log('No skills selected.');
284
+
285
+ if (skillsList.length === 0) {
286
+ console.log('No community skills found in registry.');
234
287
  process.exit(0);
235
288
  }
236
-
289
+
290
+ console.log('\nAvailable community skills:\n');
291
+ for (const item of skillsList) {
292
+ console.log(` [${item.idx}] ${item.name.padEnd(20)} ${item.desc}`);
293
+ }
294
+ console.log('\nEnter skill numbers to install (comma-separated, e.g. 1, 3) or press Enter to cancel:');
295
+
296
+ const rl = readline.createInterface({
297
+ input: process.stdin,
298
+ output: process.stdout,
299
+ });
300
+
301
+ const answer = await new Promise((resolve) => {
302
+ rl.question('> ', (ans) => {
303
+ rl.close();
304
+ resolve(ans.trim());
305
+ });
306
+ });
307
+
308
+ if (!answer) {
309
+ console.log('No skills selected. Operation cancelled.');
310
+ process.exit(0);
311
+ }
312
+
313
+ const selectedIndices = answer
314
+ .split(/[\s,]+/)
315
+ .map(n => parseInt(n, 10))
316
+ .filter(n => !isNaN(n) && n >= 1 && n <= skillsList.length);
317
+
318
+ const selectedSkills = selectedIndices.map(n => skillsList[n - 1].value);
319
+
320
+ if (selectedSkills.length === 0) {
321
+ console.log('No valid skill numbers selected.');
322
+ process.exit(0);
323
+ }
324
+
237
325
  const { execFileSync } = require('child_process');
238
- for (const skillRef of answers.selectedSkills) {
326
+ for (const skillRef of selectedSkills) {
239
327
  try {
328
+ console.log(`\nInstalling ${skillRef}...`);
240
329
  execFileSync(process.execPath, [ctxPath, 'skill', 'add', skillRef], { stdio: 'inherit' });
241
330
  } catch (e) {
242
331
  console.error(`Failed to install ${skillRef}`);
@@ -244,9 +333,6 @@ if (mainCommand === 'install-skill') {
244
333
  }
245
334
  } catch (error) {
246
335
  console.error('Failed to run interactive installer:', error.message);
247
- if (error.code === 'MODULE_NOT_FOUND' && error.message.includes('inquirer')) {
248
- console.error('It seems inquirer is not installed. Did you run npm install?');
249
- }
250
336
  process.exit(1);
251
337
  }
252
338
  })();
@@ -368,12 +454,18 @@ function installAtomically(source, target, options = {}) {
368
454
  }
369
455
  }
370
456
 
371
- // ── Stack detection ───────────────────────────────────────────────────────────
372
- const stackDetection = profiles.detectStack(process.cwd());
457
+ // ── Stack & IDE detection ───────────────────────────────────────────────────
458
+ const projectAttrs = detectProjectAttributes(process.cwd());
459
+ const stackDetection = projectAttrs.stack;
460
+ const ideDetection = projectAttrs.ide;
461
+
462
+ const targetProfile = flags.profile || (flags.auto || flags.agent === 'auto' ? stackDetection.recommendedProfile : 'none');
463
+ const targetAgents = (flags.agent === 'auto' || flags.auto)
464
+ ? ideDetection.recommendedAgents
465
+ : (flags.agent ? [flags.agent] : ['gemini']);
373
466
 
374
467
  // ── Dry run ───────────────────────────────────────────────────────────────────
375
468
  if (flags.dryRun) {
376
- console.log('[DRY-RUN] No files will be written.\n');
377
469
  if (!fs.existsSync(sourcePath)) {
378
470
  console.error('[ERROR] Source .agents/ folder not found in package.');
379
471
  process.exit(1);
@@ -403,14 +495,34 @@ if (flags.dryRun) {
403
495
  return count;
404
496
  };
405
497
  const total = countFiles(sourcePath);
498
+
499
+ if (flags.json) {
500
+ console.log(JSON.stringify({
501
+ dryRun: true,
502
+ targetPath,
503
+ targetProfile,
504
+ detectedStack: stackDetection.detected,
505
+ detectedIde: ideDetection.detected,
506
+ targetAgents,
507
+ filesCount: total,
508
+ minimal: flags.minimal,
509
+ withMcp: flags.withMcp,
510
+ }, null, 2));
511
+ process.exit(0);
512
+ }
513
+
514
+ console.log('[DRY-RUN] No files will be written.\n');
406
515
  if (fs.existsSync(targetPath)) {
407
516
  console.log(`[WARN] .agents/ already exists — would be overwritten with --force.`);
408
517
  } else {
409
518
  console.log(`[OK] Would create .agents/ in: ${process.cwd()}`);
410
519
  }
411
520
  console.log(`[INFO] Detected stack: ${stackDetection.detected.length ? stackDetection.detected.join(', ') : 'Generic JavaScript'}`);
412
- const targetProfile = flags.profile || (flags.auto ? stackDetection.recommendedProfile : 'none');
521
+ if (ideDetection.detected.length > 0) {
522
+ console.log(`[INFO] Detected IDEs: ${ideDetection.detected.join(', ')}`);
523
+ }
413
524
  console.log(`[INFO] Selected profile: ${targetProfile}`);
525
+ console.log(`[INFO] Target agents for export: ${targetAgents.join(', ')}`);
414
526
  if (flags.minimal) {
415
527
  console.log(`[INFO] Minimal mode: copying only 5 core essential skills`);
416
528
  }
@@ -420,7 +532,9 @@ if (flags.dryRun) {
420
532
  }
421
533
 
422
534
  // ── Main install ──────────────────────────────────────────────────────────────
423
- console.log('Installing AI assistant skills (.agents/)...');
535
+ if (!flags.json) {
536
+ console.log('Installing AI assistant skills (.agents/)...');
537
+ }
424
538
 
425
539
  try {
426
540
  if (!fs.existsSync(sourcePath)) {
@@ -441,14 +555,31 @@ try {
441
555
 
442
556
  installAtomically(sourcePath, targetPath, { withMcp: flags.withMcp, minimal: flags.minimal });
443
557
 
444
- console.log('[OK] .agents/ successfully installed in your project!');
445
- if (flags.minimal) {
446
- console.log('[OK] Minimal profile: 5 core skills installed.');
447
- console.log(' (engineering-workflow, ponytail-mindset, gstack-roles, gemini-precision, react)');
448
- console.log(' Tip: Add more skills anytime with: contextos skill add <name>');
558
+ // ── Create/update lockfile for provenance & safe lifecycle ─────────────────
559
+ const selectedProfile = flags.profile || (flags.auto || flags.agent === 'auto' ? stackDetection.recommendedProfile : null);
560
+ try {
561
+ lockfileLib.migrateExistingInstallation(process.cwd(), sourcePath, {
562
+ selectedProfile: selectedProfile || 'none',
563
+ installedPackage: 'contextos-agents',
564
+ version,
565
+ });
566
+ } catch (err) {
567
+ if (!flags.json) console.warn(`[WARN] Could not generate lockfile: ${err.message}`);
449
568
  }
450
- if (stackDetection.detected.length > 0) {
451
- console.log(`[OK] Detected project stack: ${stackDetection.detected.join(', ')}`);
569
+
570
+ if (!flags.json) {
571
+ console.log('[OK] .agents/ successfully installed in your project!');
572
+ if (flags.minimal) {
573
+ console.log('[OK] Minimal profile: 5 core skills installed.');
574
+ console.log(' (engineering-workflow, ponytail-mindset, gstack-roles, gemini-precision, react)');
575
+ console.log(' Tip: Add more skills anytime with: contextos skill add <name>');
576
+ }
577
+ if (stackDetection.detected.length > 0) {
578
+ console.log(`[OK] Detected project stack: ${stackDetection.detected.join(', ')}`);
579
+ }
580
+ if (ideDetection.detected.length > 0) {
581
+ console.log(`[OK] Detected developer environment: ${ideDetection.detected.join(', ')}`);
582
+ }
452
583
  }
453
584
 
454
585
  // ── Create mcp_config.json only if --with-mcp ────────────────────────────────
@@ -464,41 +595,80 @@ try {
464
595
  }
465
596
  };
466
597
  fs.writeFileSync(mcpConfigPath, JSON.stringify(defaultMcpConfig, null, 2));
467
- console.log('[OK] Created default MCP configuration (.agents/mcp_config.json)');
598
+ if (!flags.json) console.log('[OK] Created default MCP configuration (.agents/mcp_config.json)');
468
599
  }
469
600
  }
470
601
 
471
602
  // ── Apply profile if requested or auto ──────────────────────────────────────
472
- const selectedProfile = flags.profile || (flags.auto ? stackDetection.recommendedProfile : null);
473
603
  if (selectedProfile) {
474
604
  try {
475
605
  const applied = profiles.applyProfile(selectedProfile, process.cwd());
476
- console.log(`[OK] Applied profile '${applied.name}' (excluded: ${(applied.exclude_skills || []).join(', ') || 'none'})`);
606
+ if (!flags.json) console.log(`[OK] Applied profile '${applied.name}' (excluded: ${(applied.exclude_skills || []).join(', ') || 'none'})`);
477
607
  } catch (e) {
478
- console.warn(`[WARN] Could not apply profile '${selectedProfile}': ${e.message}`);
608
+ if (!flags.json) console.warn(`[WARN] Could not apply profile '${selectedProfile}': ${e.message}`);
479
609
  }
480
610
  }
481
611
 
482
- console.log('[OK] Your AI assistant now has skills and rules configured.\n');
612
+ if (!flags.json) {
613
+ console.log('[OK] Your AI assistant now has skills and rules configured.\n');
614
+ }
483
615
 
484
- // ── Auto-compile skills ───────────────────────────────────────────────────
616
+ // ── Auto-compile skills for target agents ──────────────────────────────────
485
617
  if (!flags.skipCompile) {
486
618
  const ctxPath = path.join(targetPath, 'ctx.js');
487
619
  if (fs.existsSync(ctxPath)) {
488
- console.log('Compiling skills for Gemini...');
620
+ const { execFileSync } = require('child_process');
621
+ for (const ag of targetAgents) {
622
+ if (!flags.json) console.log(`Compiling skills for ${ag}...`);
623
+ try {
624
+ execFileSync(process.execPath, [ctxPath, 'export', ag], {
625
+ cwd: process.cwd(),
626
+ stdio: flags.json ? 'ignore' : 'inherit',
627
+ });
628
+ } catch (e) {
629
+ if (!flags.json) {
630
+ console.warn(`[WARN] Skill compilation for '${ag}' failed — run manually:`);
631
+ console.warn(` contextos export ${ag}`);
632
+ }
633
+ }
634
+ }
635
+ }
636
+ } else if (!flags.json) {
637
+ console.log('Tip: Run `contextos export gemini` to compile skills.');
638
+ }
639
+
640
+ // ── --add-skill flag ────────────────────────────────────────────────────────
641
+ if (flags.addSkill) {
642
+ const ctxPath = path.join(targetPath, 'ctx.js');
643
+ if (fs.existsSync(ctxPath)) {
644
+ if (!flags.json) console.log(`Installing plugin skill: ${flags.addSkill}`);
489
645
  try {
490
646
  const { execFileSync } = require('child_process');
491
- execFileSync(process.execPath, [ctxPath, 'export', 'gemini'], {
647
+ execFileSync(process.execPath, [ctxPath, 'skill', 'add', flags.addSkill], {
492
648
  cwd: process.cwd(),
493
- stdio: 'inherit',
649
+ stdio: flags.json ? 'ignore' : 'inherit',
494
650
  });
495
651
  } catch (e) {
496
- console.warn('[WARN] Skill compilation failed — run manually:');
497
- console.warn(' contextos export gemini');
652
+ if (!flags.json) {
653
+ console.warn(`[WARN] Skill install failed — run manually:`);
654
+ console.warn(` node .agents/ctx.js skill add ${flags.addSkill}`);
655
+ }
498
656
  }
499
657
  }
500
- } else {
501
- console.log('Tip: Run `contextos export gemini` to compile skills.');
658
+ }
659
+
660
+ if (flags.json) {
661
+ console.log(JSON.stringify({
662
+ success: true,
663
+ package: 'contextos-agents',
664
+ version,
665
+ projectDir: process.cwd(),
666
+ profile: selectedProfile || 'default',
667
+ agents: targetAgents,
668
+ withMcp: flags.withMcp,
669
+ minimal: flags.minimal,
670
+ }, null, 2));
671
+ process.exit(0);
502
672
  }
503
673
 
504
674
  console.log('\n Next steps:');
@@ -522,26 +692,12 @@ try {
522
692
  }
523
693
  console.log('');
524
694
 
525
- // ── --add-skill flag ────────────────────────────────────────────────────────
526
- if (flags.addSkill) {
527
- const ctxPath = path.join(targetPath, 'ctx.js');
528
- if (fs.existsSync(ctxPath)) {
529
- console.log(`Installing plugin skill: ${flags.addSkill}`);
530
- try {
531
- const { execFileSync } = require('child_process');
532
- execFileSync(process.execPath, [ctxPath, 'skill', 'add', flags.addSkill], {
533
- cwd: process.cwd(),
534
- stdio: 'inherit',
535
- });
536
- } catch (e) {
537
- console.warn(`[WARN] Skill install failed — run manually:`);
538
- console.warn(` node .agents/ctx.js skill add ${flags.addSkill}`);
539
- }
540
- }
541
- }
542
-
543
695
  } catch (error) {
544
- console.error('[ERROR] Installation failed:', error.message);
696
+ if (flags.json) {
697
+ console.error(JSON.stringify({ success: false, error: error.message }));
698
+ } else {
699
+ console.error('[ERROR] Installation failed:', error.message);
700
+ }
545
701
  process.exit(1);
546
702
  }
547
703