@exchanet/enet 1.0.18 → 1.0.20

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exchanet/enet",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "description": "enet — exchanet methods manager. Install, scaffold and manage AI coding methods.",
5
5
  "bin": {
6
6
  "enet": "src/index.js"
@@ -3,11 +3,12 @@ import ora from 'ora'
3
3
  import fs from 'fs-extra'
4
4
  import path from 'path'
5
5
  import enquirer from 'enquirer'
6
- const { MultiSelect } = enquirer
6
+ const { MultiSelect, Select } = enquirer
7
7
  import { detectSystemAgents, getInstallPath, AGENTS } from '../utils/agent_detector.js'
8
8
  import { getMethod, fetchFromGitHub, readInstallRecord, writeInstallRecord } from '../utils/registry.js'
9
9
 
10
10
  export async function installCommand(methodId, options) {
11
+ if (options.project) options.global = false
11
12
  // 1. Load method from registry
12
13
  const spinner = ora('Fetching registry...').start()
13
14
  const method = await getMethod(methodId).catch(() => null)
@@ -20,12 +21,7 @@ export async function installCommand(methodId, options) {
20
21
  }
21
22
 
22
23
  console.log(chalk.bold(`\n ◆ ${method.name}`))
23
- console.log(chalk.dim(` ${method.description}`))
24
- if (options.global) {
25
- console.log(chalk.cyan(' Destination: global (home) — available for all agents/projects\n'))
26
- } else {
27
- console.log(chalk.dim(` Destination: current project (use ${chalk.white('--global')} for all agents)\n`))
28
- }
24
+ console.log(chalk.dim(` ${method.description}\n`))
29
25
 
30
26
  // 2. Read existing install record — know what is already installed
31
27
  const record = await readInstallRecord(methodId)
@@ -70,7 +66,31 @@ export async function installCommand(methodId, options) {
70
66
  }
71
67
  }
72
68
 
73
- console.log()
69
+ // 3b. If neither -g nor -p was passed, ask: global or project?
70
+ if (options.global === undefined && process.stdin.isTTY) {
71
+ const destPrompt = new Select({
72
+ name: 'destination',
73
+ message: 'Install to:',
74
+ choices: [
75
+ { name: 'global', message: 'Global (home) — available for all agents and projects', value: true },
76
+ { name: 'project', message: 'Project — this folder only', value: false }
77
+ ]
78
+ })
79
+ try {
80
+ options.global = await destPrompt.run()
81
+ } catch {
82
+ console.log(chalk.dim('\n Cancelled.\n'))
83
+ process.exit(0)
84
+ }
85
+ }
86
+ // Default when not TTY or when skipped: global
87
+ if (options.global === undefined) options.global = true
88
+
89
+ if (options.global) {
90
+ console.log(chalk.cyan('\n Destination: global (home) — available for all agents/projects\n'))
91
+ } else {
92
+ console.log(chalk.dim('\n Destination: this project only\n'))
93
+ }
74
94
 
75
95
  // 4. Install each selected agent
76
96
  const newlyInstalled = []
@@ -107,10 +127,10 @@ async function checkboxSelect(detected, method, alreadyInstalled = new Set(), op
107
127
  console.log(chalk.dim(` No adapter for: ${unavailable.map(a => a.name).join(', ')}\n`))
108
128
  }
109
129
 
110
- const installScope = options.global ? 'global (home)' : 'current project'
130
+ const scopeLabel = options.global === true ? 'global (home)' : options.global === false ? 'this project' : 'choose in next step'
111
131
  const prompt = new MultiSelect({
112
132
  name: 'agents',
113
- message: `Select adapters to install (destination: ${installScope})`,
133
+ message: `Select adapters to install (destination: ${scopeLabel})`,
114
134
  choices: available.map(a => ({
115
135
  name: a.key,
116
136
  message: `${a.name}${alreadyInstalled.has(a.key) ? ' — installed' : ' — new'}${!method.adapters[a.key] ? ' (generic)' : ''}`,
package/src/index.js CHANGED
@@ -17,36 +17,42 @@ const require = createRequire(import.meta.url)
17
17
  const pkg = require('../package.json')
18
18
  const VERSION = pkg.version
19
19
 
20
- // ── Version check ─────────────────────────────────────────────────────────────
21
- // Runs in background never blocks the command, never crashes if offline
20
+ function isNewerVersion (latest, current) {
21
+ const parts = (v) => String(v).replace(/^v/, '').split('.').map(Number)
22
+ const a = parts(latest)
23
+ const b = parts(current)
24
+ for (let i = 0; i < Math.max(a.length, b.length); i++) {
25
+ const x = a[i] || 0
26
+ const y = b[i] || 0
27
+ if (x > y) return true
28
+ if (x < y) return false
29
+ }
30
+ return false
31
+ }
32
+
33
+ // ── Version check (every command) ─────────────────────────────────────────────
34
+ // Shows warning if a newer enet is on npm; never blocks, never crashes if offline
22
35
 
23
- async function checkForUpdate() {
36
+ async function checkForUpdate () {
24
37
  try {
25
- const res = await fetch(
26
- 'https://registry.npmjs.org/@exchanet/enet/latest',
27
- { signal: AbortSignal.timeout(3000) }
28
- )
38
+ const res = await fetch('https://registry.npmjs.org/@exchanet/enet/latest', { signal: AbortSignal.timeout(3000) })
29
39
  if (!res.ok) return
30
40
  const data = await res.json()
31
- const latest = data.version
32
- if (latest && latest !== VERSION) {
41
+ const latest = data?.version
42
+ if (latest && isNewerVersion(latest, VERSION)) {
33
43
  console.log(
34
- chalk.yellow(' ⚠ Update available: ') +
35
- chalk.dim(`v${VERSION}`) +
36
- chalk.white(' ') +
37
- chalk.green(`v${latest}`) + '\n' +
38
- chalk.dim(' Run ') +
39
- chalk.white('npm install -g @exchanet/enet') +
40
- chalk.dim(' to update.\n')
44
+ chalk.yellow(' ⚠ Warning: a newer version of enet is available.\n') +
45
+ chalk.dim(` Current: v${VERSION} → Latest: v${latest}\n`) +
46
+ chalk.dim(' Update: ') +
47
+ chalk.white('npm install -g @exchanet/enet\n')
41
48
  )
42
49
  }
43
50
  } catch {
44
- // Offline or npm unreachable — silently skip
51
+ // Offline or timeoutskip silently
45
52
  }
46
53
  }
47
54
 
48
- // Fire in background without await — command runs immediately
49
- checkForUpdate()
55
+ await checkForUpdate()
50
56
 
51
57
  // ── Header ────────────────────────────────────────────────────────────────────
52
58
 
@@ -61,9 +67,10 @@ program
61
67
 
62
68
  program
63
69
  .command('install <method>')
64
- .description('Install a method into the current project')
70
+ .description('Install a method (default: global; use -p for this project only)')
65
71
  .option('-a, --agent <agent>', 'Force agent: cursor | windsurf | antigravity | claudecode | copilot | generic')
66
- .option('-g, --global', 'Install globally to home directory')
72
+ .option('-g, --global', 'Install globally (default) available for all agents/projects')
73
+ .option('-p, --project', 'Install only in current project')
67
74
  .option('--all', 'Install for all detected agents without prompting')
68
75
  .action(installCommand)
69
76