@exchanet/enet 1.0.11 → 1.0.13

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,11 +1,16 @@
1
1
  {
2
2
  "name": "@exchanet/enet",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "enet — exchanet methods manager. Install, scaffold and manage AI coding methods.",
5
5
  "bin": {
6
6
  "enet": "src/index.js"
7
7
  },
8
8
  "type": "module",
9
+ "files": [
10
+ "src",
11
+ "registry.json",
12
+ "manifest.schema.json"
13
+ ],
9
14
  "scripts": {
10
15
  "dev": "node src/index.js",
11
16
  "test": "node --test"
@@ -15,7 +20,6 @@
15
20
  "commander": "^12.0.0",
16
21
  "enquirer": "^2.4.1",
17
22
  "ora": "^8.0.1",
18
- "node-fetch": "^3.3.2",
19
23
  "ajv": "^8.12.0",
20
24
  "ajv-formats": "^3.0.1",
21
25
  "fs-extra": "^11.2.0"
package/src/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { program } from 'commander'
4
4
  import chalk from 'chalk'
5
+ import { createRequire } from 'module'
5
6
  import { installCommand } from './commands/install.js'
6
7
  import { listCommand } from './commands/list.js'
7
8
  import { initCommand } from './commands/init.js'
@@ -11,10 +12,48 @@ import { updateCommand } from './commands/update.js'
11
12
  import { statusCommand } from './commands/status.js'
12
13
  import { doctorCommand } from './commands/doctor.js'
13
14
 
14
- const VERSION = '1.0.0'
15
+ // Read version from package.json — single source of truth
16
+ const require = createRequire(import.meta.url)
17
+ const pkg = require('../package.json')
18
+ const VERSION = pkg.version
19
+
20
+ // ── Version check ─────────────────────────────────────────────────────────────
21
+ // Runs in background — never blocks the command, never crashes if offline
22
+
23
+ async function checkForUpdate() {
24
+ try {
25
+ const res = await fetch(
26
+ 'https://registry.npmjs.org/@exchanet/enet/latest',
27
+ { signal: AbortSignal.timeout(3000) }
28
+ )
29
+ if (!res.ok) return
30
+ const data = await res.json()
31
+ const latest = data.version
32
+ if (latest && latest !== VERSION) {
33
+ 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')
41
+ )
42
+ }
43
+ } catch {
44
+ // Offline or npm unreachable — silently skip
45
+ }
46
+ }
47
+
48
+ // Fire in background without await — command runs immediately
49
+ checkForUpdate()
50
+
51
+ // ── Header ────────────────────────────────────────────────────────────────────
15
52
 
16
53
  console.log(chalk.cyan(`\n◆ enet v${VERSION} — exchanet methods manager\n`))
17
54
 
55
+ // ── Commands ──────────────────────────────────────────────────────────────────
56
+
18
57
  program
19
58
  .name('enet')
20
59
  .description('Install, scaffold and manage exchanet AI coding methods')
@@ -23,8 +62,9 @@ program
23
62
  program
24
63
  .command('install <method>')
25
64
  .description('Install a method into the current project')
26
- .option('-a, --agent <agent>', 'Force agent: cursor | windsurf | copilot | generic')
65
+ .option('-a, --agent <agent>', 'Force agent: cursor | windsurf | antigravity | claudecode | copilot | generic')
27
66
  .option('-g, --global', 'Install globally to home directory')
67
+ .option('--all', 'Install for all detected agents without prompting')
28
68
  .action(installCommand)
29
69
 
30
70
  program
@@ -58,8 +98,11 @@ program
58
98
 
59
99
  program
60
100
  .command('update [method]')
61
- .description('Update installed methods to latest version')
62
- .option('--all', 'Update all installed methods')
101
+ .description('Update installed methods and add adapters for new agents')
102
+ .option('--all', 'Add all new agents without prompting')
103
+ .option('--add-only', 'Only add new agents, skip re-downloading existing')
104
+ .option('--update-only', 'Only re-download existing, skip new agent prompt')
105
+ .option('-g, --global', 'Update global install')
63
106
  .action(updateCommand)
64
107
 
65
108
  program
@@ -1,43 +1,60 @@
1
- import fetch from 'node-fetch'
2
1
  import fs from 'fs-extra'
3
2
  import path from 'path'
4
3
  import { fileURLToPath } from 'url'
5
4
 
6
5
  const __dirname = path.dirname(fileURLToPath(import.meta.url))
7
- const RAW_BASE = 'https://raw.githubusercontent.com'
6
+ const RAW_BASE = 'https://raw.githubusercontent.com'
8
7
  const REGISTRY_URL = `${RAW_BASE}/exchanet/enet/main/registry.json`
9
8
  const CACHE_FILE = path.join(__dirname, '../../.registry-cache.json')
10
9
  const CACHE_TTL_MS = 1000 * 60 * 60 // 1 hour
11
10
 
12
11
  // ── Registry ──────────────────────────────────────────────────────────────────
13
12
 
13
+ /**
14
+ * Loads the registry from:
15
+ * 1. Remote GitHub (exchanet/enet/registry.json) — always fresh
16
+ * 2. Local cache if remote fails — fallback
17
+ * 3. Bundled registry.json in the package — last resort
18
+ */
14
19
  export async function loadRegistry() {
15
20
  try {
16
- const res = await fetch(REGISTRY_URL, { timeout: 5000 })
21
+ const res = await fetch(REGISTRY_URL, { signal: AbortSignal.timeout(5000) })
17
22
  if (res.ok) {
18
23
  const data = await res.json()
19
24
  await fs.writeJson(CACHE_FILE, { ...data, _cachedAt: Date.now() }).catch(() => {})
20
25
  return data
21
26
  }
22
- } catch { /* network unavailable */ }
27
+ } catch {
28
+ // Network unavailable — fall through to cache
29
+ }
23
30
 
24
31
  try {
25
32
  if (await fs.pathExists(CACHE_FILE)) {
26
33
  const cached = await fs.readJson(CACHE_FILE)
27
34
  const age = Date.now() - (cached._cachedAt || 0)
28
- if (age < CACHE_TTL_MS * 24) return cached
35
+ if (age < CACHE_TTL_MS * 24) {
36
+ return cached
37
+ }
29
38
  }
30
- } catch { /* cache corrupted */ }
39
+ } catch {
40
+ // Cache corrupted — fall through to bundled
41
+ }
31
42
 
32
43
  const bundled = path.join(__dirname, '../../registry.json')
33
44
  return fs.readJson(bundled)
34
45
  }
35
46
 
47
+ /**
48
+ * Returns a single method from the registry, or null if not found.
49
+ */
36
50
  export async function getMethod(id) {
37
51
  const registry = await loadRegistry()
38
52
  return registry.methods?.[id] ?? null
39
53
  }
40
54
 
55
+ /**
56
+ * Returns all methods from the registry as an array.
57
+ */
41
58
  export async function getAllMethods() {
42
59
  const registry = await loadRegistry()
43
60
  return Object.values(registry.methods ?? {})
@@ -45,22 +62,27 @@ export async function getAllMethods() {
45
62
 
46
63
  // ── GitHub file fetcher ───────────────────────────────────────────────────────
47
64
 
65
+ /**
66
+ * Fetches a raw file from a GitHub repo (main branch).
67
+ */
48
68
  export async function fetchFromGitHub(repo, filePath) {
49
69
  const url = `${RAW_BASE}/${repo}/main/${filePath}`
50
70
  const res = await fetch(url)
71
+
51
72
  if (!res.ok) {
52
73
  throw new Error(
53
74
  `Could not fetch ${filePath} from ${repo} (HTTP ${res.status})\n` +
54
75
  ` URL: ${url}`
55
76
  )
56
77
  }
78
+
57
79
  return res.text()
58
80
  }
59
81
 
60
82
  // ── Install state ─────────────────────────────────────────────────────────────
61
83
  //
62
84
  // Tracks which agents have each method installed.
63
- // Stored in <project>/.enet/installed.json
85
+ // Stored in .enet/installed.json in the project root.
64
86
  //
65
87
  // Format:
66
88
  // {
@@ -68,15 +90,19 @@ export async function fetchFromGitHub(repo, filePath) {
68
90
  // "agents": ["cursor", "claudecode", "antigravity"],
69
91
  // "version": "3.0.0",
70
92
  // "updatedAt": "2025-03-01T10:00:00.000Z"
71
- // }
93
+ // },
94
+ // "modular-design": { ... }
72
95
  // }
73
96
 
74
97
  function getInstallRecordFile() {
98
+ // Resolve relative to cwd so it works in any project
75
99
  return path.join(process.cwd(), '.enet', 'installed.json')
76
100
  }
77
101
 
78
102
  /**
79
- * Returns the install record for a single method, or null if never installed.
103
+ * Reads the install record for a single method.
104
+ * Returns { agents: ['cursor', ...], version: '3.0.0', updatedAt: '...' }
105
+ * or null if the method has never been installed.
80
106
  */
81
107
  export async function readInstallRecord(methodId) {
82
108
  try {
@@ -90,22 +116,25 @@ export async function readInstallRecord(methodId) {
90
116
  }
91
117
 
92
118
  /**
93
- * Writes the install record for a single method.
94
- * Merges with existing records — other methods are never touched.
119
+ * Writes (or updates) the install record for a single method.
120
+ * Merges with existing records — other methods are not touched.
95
121
  */
96
122
  export async function writeInstallRecord(methodId, record) {
97
123
  try {
98
124
  const file = getInstallRecordFile()
99
125
  await fs.ensureDir(path.dirname(file))
126
+
100
127
  let data = {}
101
128
  if (await fs.pathExists(file)) {
102
129
  data = await fs.readJson(file).catch(() => ({}))
103
130
  }
131
+
104
132
  data[methodId] = {
105
- agents: record.agents,
106
- version: record.version ?? null,
133
+ agents: record.agents,
134
+ version: record.version ?? null,
107
135
  updatedAt: new Date().toISOString()
108
136
  }
137
+
109
138
  await fs.writeJson(file, data, { spaces: 2 })
110
139
  } catch {
111
140
  // Non-fatal — install works correctly even if state cannot be saved
@@ -1,136 +0,0 @@
1
- # METHOD MODULAR DESIGN — Agent Instructions
2
- > Universal Modular Architecture · v1.0.0 · @exchanet
3
-
4
- ---
5
-
6
- ## YOUR PRIMARY DIRECTIVE / TU DIRECTIVA PRINCIPAL
7
-
8
- You are building a modular application using Method Modular Design. Every module you create must be self-describing via a `manifest.json` file. The manifest is written **before any code**. The system reads manifests to automatically generate the Admin Panel, dashboard, and settings UI. You never manually wire backend logic to the Admin Panel — the manifest does it.
9
-
10
- Estás construyendo una aplicación modular usando Method Modular Design. Cada módulo que crees debe ser auto-descriptivo a través de un archivo `manifest.json`. El manifest se escribe **antes de cualquier código**. El sistema lee los manifests para generar automáticamente el Panel Admin, dashboard y UI de configuración. Nunca cablearás manualmente la lógica backend al Panel Admin — el manifest lo hace.
11
-
12
- **If a module has no manifest, it does not exist.**
13
- **Si un módulo no tiene manifest, no existe.**
14
-
15
- ---
16
-
17
- ## ABSOLUTE RULES / REGLAS ABSOLUTAS
18
-
19
- 1. **No manifest = module does not exist.** Core rejects modules without valid `manifest.json`.
20
- 2. **Manifest before code.** Complete manifest before any handler, model, or component.
21
- 3. **Zero hardcoded configuration.** Every configurable value lives in `manifest.settings`, read via `context.settings.get("key")`.
22
- 4. **Core has no business logic.** Domain logic lives in modules only.
23
- 5. **Admin Panel is a renderer.** Never code it to show a specific module — modules declare capabilities, Admin Panel renders them.
24
- 6. **A module is complete only when the Admin Panel reflects it correctly.**
25
- 7. **Removing a module folder requires zero code changes elsewhere.**
26
-
27
- ---
28
-
29
- ## WORKFLOW / FLUJO DE TRABAJO
30
-
31
- ### Starting a new project / Nuevo proyecto:
32
- 1. Ask for spectech if not provided (stack, database, deploy target)
33
- 2. Declare the architecture you will build
34
- 3. **Wait for confirmation before writing any code**
35
- 4. Build Core → Manifest schema → Modules → Admin Panel
36
-
37
- ### Adding a module / Añadir un módulo:
38
- 1. Write complete `manifest.json` (all settings + capabilities + hooks)
39
- 2. Validate against `manifest.schema.json`
40
- 3. Implement all handlers referenced in manifest
41
- 4. Place in modules directory (Core discovers automatically)
42
- 5. Boot system and verify module appears in Admin Panel
43
- 6. Build custom UI components only if manifest declares a `component` field
44
-
45
- ### When you cannot complete a manifest / Cuando no puedes completar un manifest:
46
-
47
- **STOP. Ask the user:**
48
-
49
- ```
50
- "I cannot complete the manifest for [module name] because I don't understand
51
- [specific aspect]. Before I continue, I need you to clarify: [specific question]"
52
-
53
- "No puedo completar el manifest de [nombre del módulo] porque no entiendo
54
- [aspecto específico]. Antes de continuar, necesito que aclares: [pregunta específica]"
55
- ```
56
-
57
- Do not proceed. Do not create a partial manifest. Do not make assumptions. Wait.
58
- No continúes. No crees un manifest parcial. No hagas suposiciones. Espera.
59
-
60
- ---
61
-
62
- ## MANIFEST FORMAT / FORMATO DEL MANIFEST
63
-
64
- ```json
65
- {
66
- "id": "module-id",
67
- "name": "Human Name",
68
- "version": "1.0.0",
69
- "type": "functional",
70
- "section": "admin-section",
71
- "dependencies": [],
72
- "hooks": { "event.name": "ClassName.method" },
73
- "settings": {
74
- "key": {
75
- "type": "integer|string|boolean|select",
76
- "label": "Label",
77
- "default": null,
78
- "ui": "slider|toggle|text|select"
79
- }
80
- },
81
- "capabilities": [
82
- { "type": "view", "label": "Label", "data": "ClassName.method" },
83
- { "type": "action", "label": "Label", "handler": "ClassName.method", "dangerous": false },
84
- { "type": "metric", "label": "Label", "data": "ClassName.method" },
85
- { "type": "widget", "label": "Label", "data": "ClassName.method", "component": "ComponentName" }
86
- ]
87
- }
88
- ```
89
-
90
- ---
91
-
92
- ## WHAT THE CORE MUST IMPLEMENT / QUÉ DEBE IMPLEMENTAR EL CORE
93
-
94
- - Module discovery — scan modules dir for valid manifests
95
- - Manifest validation — reject invalid manifests with clear errors (never silent)
96
- - Dependency resolution — boot in correct order
97
- - Handler registry — map `ClassName.method` references to implementations
98
- - Hook system — dispatch events to declared handlers
99
- - Settings store — persistent, namespaced by module ID, initialized from defaults
100
- - REFLEX engine — read all manifests, build Admin nav, dashboard, settings schemas
101
- - Admin API — standard endpoints (same in every project, every stack)
102
-
103
- ```
104
- GET /api/admin/manifest-registry
105
- GET /api/admin/navigation
106
- GET /api/admin/settings/:moduleId
107
- POST /api/admin/settings/:moduleId
108
- GET /api/admin/dashboard
109
- POST /api/admin/action/:moduleId/:actionId
110
- GET /api/admin/health
111
- ```
112
-
113
- **The Core has ZERO business logic. / El Core tiene CERO lógica de negocio.**
114
-
115
- ---
116
-
117
- ## COMPLETION CHECKLIST / CHECKLIST DE COMPLETITUD
118
-
119
- Before marking any module complete / Antes de marcar cualquier módulo como completo:
120
-
121
- - [ ] `manifest.json` valid / válido
122
- - [ ] All declared handlers implemented / Todos los handlers declarados implementados
123
- - [ ] Zero hardcoded values — all settings use `context.settings.get()` / Cero hardcoded
124
- - [ ] Module appears in Admin Panel navigation / El módulo aparece en la navegación del Panel Admin
125
- - [ ] All views render with data / Todas las vistas renderizan con datos
126
- - [ ] All actions execute correctly / Todas las acciones ejecutan correctamente
127
- - [ ] Dangerous actions show confirmation dialog / Las acciones peligrosas muestran diálogo
128
- - [ ] All metrics show in dashboard / Todas las métricas aparecen en el dashboard
129
- - [ ] All settings render and save correctly / Todos los settings renderizan y guardan
130
- - [ ] Adding this module required zero Core changes / Añadir el módulo requirió cero cambios en el Core
131
- - [ ] Removing module folder removes it completely from Admin Panel / Eliminar la carpeta lo elimina del Panel Admin
132
-
133
- ---
134
-
135
- *For full documentation / Para documentación completa: `METHOD.md`*
136
- *Method Modular Design v1.0.0 · @exchanet · MIT*
package/.enet/pdca-t.md DELETED
@@ -1,110 +0,0 @@
1
- ---
2
- description: Method PDCA-T — Systematic quality cycle for AI-assisted coding
3
- trigger: always_on
4
- ---
5
-
6
- # METHOD PDCA-T — Active for all tasks in this project
7
-
8
- You are operating under the PDCA-T quality methodology. Apply this 8-phase cycle to every coding task without exception.
9
-
10
- ## PHASE 1 — PLANNING
11
- Before writing any code:
12
- - State the exact objective in one sentence
13
- - Define what IS and IS NOT in scope
14
- - Ask clarifying questions if anything is ambiguous
15
- - Identify external dependencies
16
- - Define the acceptance criterion
17
-
18
- Do not advance until the objective is unambiguous.
19
-
20
- ## PHASE 2 — REQUIREMENTS ANALYSIS
21
- - List Functional Requirements: `FR-NN: [what the system must do]`
22
- - List Non-Functional Requirements: `NFR-NN: [constraint or quality attribute with metric]`
23
- - Build Risk Register: `RISK-NN: [risk] | Probability | Impact | Mitigation`
24
-
25
- ## PHASE 3 — ARCHITECTURE DESIGN
26
- Before any implementation:
27
- - Write ADRs: `ADR-NN: [title] | Context | Decision | Alternatives | Consequences`
28
- - Define interface contracts (function signatures + full docstrings) before implementing bodies
29
- - Define module structure: domain / infrastructure / interfaces
30
-
31
- ## PHASE 4 — MICRO-TASK CYCLE (≤ 50 lines per task)
32
-
33
- **4.1** — Check available skills in `.cursor/skills/` and reusable context
34
-
35
- **4.2** — Write tests FIRST. Required categories:
36
- - Happy path · Error cases · Edge cases · Security · Performance (if applicable)
37
- - Structure: Arrange / Act / Assert
38
- - Naming: `test_[function]_[scenario]_[expected_outcome]`
39
-
40
- **4.3** — Implement code. Standards:
41
- - Full type hints on every parameter and return value
42
- - Docstring with Args, Returns, Raises
43
- - Single responsibility per function
44
- - `Decimal` not `float` for monetary values
45
- - Specific exception types — never bare `except:`
46
- - Zero hardcoded configuration
47
- - Structured logging with context fields
48
-
49
- **4.4** — Self-review before running tests:
50
- ```
51
- □ Type hints complete? □ All inputs validated?
52
- □ Docstring written? □ No hardcoded secrets?
53
- □ Single responsibility? □ Semantic names?
54
- □ No code duplication? □ Errors logged with context?
55
- ```
56
-
57
- **4.5** — Execute tests and show REAL complete output:
58
- ```bash
59
- pytest tests/ -v --cov=src --cov-report=term-missing --tb=short
60
- ```
61
- Never summarize. Never say "tests pass". Show the exact output.
62
-
63
- **4.6** — Validate:
64
- - All tests pass (100%)? If not → fix code, explain, re-run
65
- - Coverage ≥ 99%? If not → identify uncovered lines → add tests → re-run
66
- - Repeat until both conditions are met
67
-
68
- ## PHASE 5 — INTEGRAL VALIDATION
69
- After all micro-tasks:
70
- - **Security:** No OWASP Top 10 issues · inputs validated · outputs sanitized · no hardcoded secrets · minimum privilege
71
- - **Tests:** 100% passed · 0 failed · coverage ≥ 99% · all categories present
72
- - **Code quality:** Type hints 100% · cyclomatic complexity < 10 · no duplication · SRP · docstrings 100%
73
- - **Performance:** No N+1 · indexes on filter fields · pagination in collections · timeouts configured
74
- - **Architecture:** No circular imports · layers respected · low coupling · inward dependencies only
75
-
76
- ## PHASE 6 — TECHNICAL DEBT MANAGEMENT
77
- Register every known issue before delivery:
78
- ```
79
- DEBT-XXX: [Short title]
80
- Type: Technical | Test | Documentation | Architecture | Security | Performance
81
- Description: [What and why]
82
- Impact: High | Medium | Low — [justification]
83
- Effort: Xh
84
- Priority: High | Medium | Low
85
- Plan: [Specific action and target version]
86
- ```
87
- Do not write TODO/FIXME in code — register as DEBT-XXX instead.
88
-
89
- ## PHASE 7 — REFINEMENT TO ≥ 99%
90
- If any metric is below target:
91
- `Identify → Classify → Plan → Execute → Verify → Confirm ≥ 99%`
92
- Never advance to Phase 8 without confirming ≥ 99% on all 5 validation dimensions.
93
-
94
- ## PHASE 8 — DELIVERY REPORT
95
- Always close every task with:
96
- 1. Implementation summary (2-3 sentences)
97
- 2. Test table: total / passed / failed / coverage / time
98
- 3. Full unedited pytest output
99
- 4. Key technical decisions with justifications
100
- 5. Technical debt registered (DEBT-XXX list)
101
- 6. CI/CD checklist (all items confirmed)
102
- 7. Suggested next steps
103
-
104
- ## ABSOLUTE RULES — NEVER VIOLATE
105
- 1. Tests BEFORE implementation — always, no exceptions
106
- 2. Show REAL test output — never summarize or omit
107
- 3. No hardcoded secrets — environment variables from commit 1
108
- 4. Coverage ≥ 99% before any delivery
109
- 5. ADRs for non-trivial decisions
110
- 6. All known issues as DEBT-XXX with priority and plan