smart-context-mcp 1.1.0 → 1.3.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/README.md CHANGED
@@ -7,16 +7,70 @@ MCP server that reduces AI agent token usage by 90% with intelligent context com
7
7
 
8
8
  ## Installation
9
9
 
10
+ ### Cursor
10
11
  ```bash
11
- npm install smart-context-mcp
12
+ npm install -g smart-context-mcp
13
+ npx smart-context-init --target . --clients cursor
14
+ ```
15
+ Restart Cursor. Done.
16
+
17
+ ### Codex CLI
18
+ ```bash
19
+ npm install -g smart-context-mcp
20
+ npx smart-context-init --target . --clients codex
21
+ ```
22
+ Restart Codex. Done.
23
+
24
+ ### Claude Desktop
25
+ ```bash
26
+ npm install -g smart-context-mcp
27
+ npx smart-context-init --target . --clients claude
28
+ ```
29
+ Restart Claude Desktop. Done.
30
+
31
+ ### Qwen Code
32
+ ```bash
33
+ npm install -g smart-context-mcp
34
+ npx smart-context-init --target . --clients qwen
35
+ ```
36
+ Restart Qwen Code. Done.
37
+
38
+ ### All Clients
39
+ ```bash
40
+ npm install -g smart-context-mcp
12
41
  npx smart-context-init --target .
13
42
  ```
43
+ Restart your AI client. Done.
44
+
45
+ ## How it Works in Practice
46
+
47
+ **The reality:** This MCP does not intercept prompts automatically. Here's the actual flow:
14
48
 
15
- Restart your AI client. Tools are immediately available.
49
+ 1. **You:** "Fix the login bug"
50
+ 2. **Agent reads rules:** Sees debugging workflow
51
+ 3. **Agent decides:** Uses `smart_search(intent=debug)`
52
+ 4. **MCP returns:** Ranked results (errors prioritized)
53
+ 5. **Agent continues:** Calls `smart_read(symbol)` for function
54
+ 6. **Agent fixes:** Makes changes
55
+ 7. **Agent verifies:** Calls `smart_shell('npm test')`
56
+ 8. **Agent checkpoints:** Calls `smart_turn(end)`
57
+
58
+ **Key points:**
59
+ - ✅ Agent **chooses** to use devctx tools (not forced)
60
+ - ✅ Rules **guide** the agent (not enforce)
61
+ - ✅ Agent can use built-in tools when appropriate
62
+ - ✅ Token savings: 85-90% on complex tasks
63
+
64
+ Check actual usage:
65
+ - **Real-time feedback** - See usage immediately (enable with `export DEVCTX_SHOW_USAGE=true`)
66
+ - `npm run report:metrics` - Tool-level savings + adoption analysis
67
+ - `npm run report:workflows` - Workflow-level savings (requires `DEVCTX_WORKFLOW_TRACKING=true`)
16
68
 
17
69
  ## What it does
18
70
 
19
- Replaces inefficient file reading and searching with 12 specialized tools:
71
+ Provides **two key components**:
72
+
73
+ ### 1. Specialized Tools (12 tools)
20
74
 
21
75
  | Tool | Purpose | Savings |
22
76
  |------|---------|---------|
@@ -24,8 +78,8 @@ Replaces inefficient file reading and searching with 12 specialized tools:
24
78
  | `smart_read_batch` | Read multiple files in one call | 90% |
25
79
  | `smart_search` | Intent-aware code search with ranking | 95% |
26
80
  | `smart_context` | One-call context builder | 85% |
27
- | `smart_summary` | Session state management | 98% |
28
- | `smart_turn` | Turn orchestration | - |
81
+ | `smart_summary` | Task checkpoint management | 98% |
82
+ | `smart_turn` | Task recovery orchestration | - |
29
83
  | `smart_metrics` | Token usage inspection | - |
30
84
  | `smart_shell` | Safe command execution | 94% |
31
85
  | `build_index` | Symbol index builder | - |
@@ -33,10 +87,150 @@ Replaces inefficient file reading and searching with 12 specialized tools:
33
87
  | `git_blame` | Function-level code attribution | - |
34
88
  | `cross_project` | Multi-project context | - |
35
89
 
90
+ ### 2. Agent Rules (Task-Specific Guidance)
91
+
92
+ Installation generates rules that teach agents optimal workflows:
93
+
94
+ **Debugging:** `smart_search(intent=debug)` → `smart_read(symbol)` → fix (90% savings)
95
+ **Code Review:** `smart_context(diff=true)` → `smart_read(signatures)` → review (87% savings)
96
+ **Refactoring:** `smart_context(entryFile)` → `smart_read(signatures)` → refactor (89% savings)
97
+ **Testing:** `smart_search(intent=tests)` → `smart_read(symbol)` → write test (90% savings)
98
+ **Architecture:** `smart_context(detail=minimal)` → `smart_read(signatures)` → analyze (90% savings)
99
+
100
+ **Key insight:** The value isn't just in the tools—it's in teaching agents **when** and **how** to use them.
101
+
36
102
  ## Real Metrics
37
103
 
38
104
  Production usage: **14.5M tokens → 1.6M tokens** (89.87% reduction)
39
105
 
106
+ ## Verify It's Working
107
+
108
+ ### Real-Time Feedback (Auto-enabled for First 10 Calls)
109
+
110
+ Feedback is **automatically enabled** for your first 10 tool calls (onboarding mode), then auto-disables.
111
+
112
+ **To keep it enabled permanently:**
113
+ ```bash
114
+ export DEVCTX_SHOW_USAGE=true
115
+ ```
116
+
117
+ **To disable immediately:**
118
+ ```bash
119
+ export DEVCTX_SHOW_USAGE=false
120
+ ```
121
+
122
+ You'll see at the end of agent responses:
123
+
124
+ ```markdown
125
+ ---
126
+
127
+ 📊 **devctx usage this session:**
128
+ - **smart_read**: 3 calls | ~45.0K tokens saved (file1.js, file2.js, file3.js)
129
+ - **smart_search**: 1 call | ~12.0K tokens saved (query)
130
+
131
+ **Total saved:** ~57.0K tokens
132
+
133
+ *Onboarding mode: showing for 3 more tool calls. To keep: `export DEVCTX_SHOW_USAGE=true`*
134
+ ```
135
+
136
+ **Why this is useful:**
137
+ - ✅ Verify agent is following rules
138
+ - ✅ See token savings in real-time
139
+ - ✅ Debug adoption issues instantly
140
+ - ✅ Validate forcing prompts worked
141
+
142
+ ### Historical Metrics
143
+
144
+ ```bash
145
+ npm run report:metrics
146
+ ```
147
+
148
+ Shows adoption analysis + token savings over time.
149
+
150
+ ### Decision Explanations (Optional)
151
+
152
+ Understand **why** the agent chose devctx tools:
153
+
154
+ ```bash
155
+ export DEVCTX_EXPLAIN=true
156
+ ```
157
+
158
+ You'll see explanations like:
159
+
160
+ ```markdown
161
+ 🤖 **Decision explanations:**
162
+
163
+ **smart_read** (read server.js (outline mode))
164
+ - **Why:** File is large (2500 lines), outline mode extracts structure only
165
+ - **Instead of:** Read (full file)
166
+ - **Expected benefit:** ~45.0K tokens saved
167
+
168
+ **smart_search** (search "bug" (intent: debug))
169
+ - **Why:** Intent-aware search prioritizes relevant results
170
+ - **Expected benefit:** Better result ranking
171
+ ```
172
+
173
+ **When to use:**
174
+ - Learning how devctx works
175
+ - Debugging tool selection
176
+ - Understanding best practices
177
+
178
+ ### Missed Opportunities Detection (Optional)
179
+
180
+ Detect when devctx **should have been used but wasn't**:
181
+
182
+ ```bash
183
+ export DEVCTX_DETECT_MISSED=true
184
+ ```
185
+
186
+ You'll see warnings like:
187
+
188
+ ```markdown
189
+ ⚠️ **Missed devctx opportunities detected:**
190
+
191
+ **Session stats:**
192
+ - devctx operations: 2
193
+ - Estimated total: 25
194
+ - Adoption: 8%
195
+
196
+ 🟡 **low devctx adoption**
197
+ - **Issue:** Low adoption (8%). Target: >50%
198
+ - **Potential savings:** ~184.0K tokens
199
+ ```
200
+
201
+ **Detects:**
202
+ - No devctx usage in long sessions
203
+ - Low adoption (<30%)
204
+ - Usage dropped mid-session
205
+
206
+ **Combine all features:**
207
+
208
+ ```bash
209
+ export DEVCTX_SHOW_USAGE=true # See what's used
210
+ export DEVCTX_EXPLAIN=true # Understand why
211
+ export DEVCTX_DETECT_MISSED=true # Detect gaps
212
+ ```
213
+
214
+ ## MCP Prompts
215
+
216
+ The MCP server provides **prompts** for automatic forcing:
217
+
218
+ ```
219
+ /prompt use-devctx
220
+ ```
221
+
222
+ **Available prompts:**
223
+ - `use-devctx` - Ultra-short forcing prompt
224
+ - `devctx-workflow` - Complete workflow template
225
+ - `devctx-preflight` - Preflight checklist
226
+
227
+ **Benefits:**
228
+ - No manual typing
229
+ - Centrally managed
230
+ - No typos
231
+
232
+ See [MCP Prompts Documentation](../../docs/mcp-prompts.md).
233
+
40
234
  ## Core Tools
41
235
 
42
236
  ### smart_read
@@ -80,16 +274,18 @@ Returns: relevant files + compressed content + symbol details + graph relationsh
80
274
 
81
275
  ### smart_summary
82
276
 
83
- Maintain session state:
277
+ Maintain task checkpoint:
84
278
 
85
279
  ```javascript
86
- // Start
87
- { action: 'update', update: { goal: 'Implement OAuth', status: 'in_progress' }}
280
+ // Save checkpoint
281
+ { action: 'update', update: { goal: 'Implement OAuth', status: 'in_progress', nextStep: '...' }}
88
282
 
89
- // Resume
283
+ // Resume task
90
284
  { action: 'get' }
91
285
  ```
92
286
 
287
+ Stores compressed task state (~100 tokens: goal, status, decisions, blockers), not full conversation.
288
+
93
289
  ## New Features
94
290
 
95
291
  ### Diff-Aware Context
@@ -189,8 +385,8 @@ npm run verify
189
385
 
190
386
  Data stored in `.devctx/`:
191
387
  - `index.json` - Symbol index
192
- - `state.sqlite` - Sessions, metrics, patterns
193
- - `metrics.jsonl` - Legacy fallback
388
+ - `state.sqlite` - Task checkpoints, metrics, patterns (Node 22+)
389
+ - `metrics.jsonl` - Legacy fallback (Node 18-20)
194
390
 
195
391
  Add to `.gitignore`:
196
392
  ```
@@ -202,22 +398,45 @@ Add to `.gitignore`:
202
398
  - Node.js 18+ (22+ for SQLite features)
203
399
  - Git (for diff and blame features)
204
400
 
401
+ ## Security
402
+
403
+ This MCP is **secure by default**:
404
+
405
+ - ✅ **Allowlist-only commands** - Only safe diagnostic commands (`ls`, `git status`, `npm test`, etc.)
406
+ - ✅ **No shell operators** - Blocks `|`, `&`, `;`, `>`, `<`, `` ` ``, `$()`
407
+ - ✅ **Path validation** - Cannot escape project root
408
+ - ✅ **No write access** - Cannot modify your code
409
+ - ✅ **Repository safety** - Prevents accidental commit of local state
410
+ - ✅ **Resource limits** - 15s timeout, 10MB buffer
411
+
412
+ **Configuration:**
413
+
414
+ ```bash
415
+ # Disable shell execution entirely
416
+ export DEVCTX_SHELL_DISABLED=true
417
+
418
+ # Disable cache warming
419
+ export DEVCTX_CACHE_WARMING=false
420
+ ```
421
+
422
+ See [SECURITY.md](https://github.com/Arrayo/smart-context-mcp/blob/main/SECURITY.md) for complete security documentation.
423
+
205
424
  ## Documentation
206
425
 
207
- Full documentation in [GitHub repository](https://github.com/Arrayo/devctx-mcp-mvp):
426
+ Full documentation in [GitHub repository](https://github.com/Arrayo/smart-context-mcp):
208
427
 
209
- - [STREAMING.md](https://github.com/Arrayo/devctx-mcp-mvp/blob/main/STREAMING.md) - Progress notifications
210
- - [CONTEXT-PREDICTION.md](https://github.com/Arrayo/devctx-mcp-mvp/blob/main/CONTEXT-PREDICTION.md) - File prediction
211
- - [DIFF-AWARE.md](https://github.com/Arrayo/devctx-mcp-mvp/blob/main/DIFF-AWARE.md) - Change analysis
212
- - [CACHE-WARMING.md](https://github.com/Arrayo/devctx-mcp-mvp/blob/main/CACHE-WARMING.md) - Cold-start optimization
213
- - [GIT-BLAME.md](https://github.com/Arrayo/devctx-mcp-mvp/blob/main/GIT-BLAME.md) - Code attribution
214
- - [CROSS-PROJECT.md](https://github.com/Arrayo/devctx-mcp-mvp/blob/main/CROSS-PROJECT.md) - Multi-project support
428
+ - [Streaming Progress](https://github.com/Arrayo/smart-context-mcp/blob/main/docs/features/streaming.md) - Progress notifications
429
+ - [Context Prediction](https://github.com/Arrayo/smart-context-mcp/blob/main/docs/features/context-prediction.md) - File prediction
430
+ - [Diff-Aware Context](https://github.com/Arrayo/smart-context-mcp/blob/main/docs/features/diff-aware.md) - Change analysis
431
+ - [Cache Warming](https://github.com/Arrayo/smart-context-mcp/blob/main/docs/features/cache-warming.md) - Cold-start optimization
432
+ - [Git Blame](https://github.com/Arrayo/smart-context-mcp/blob/main/docs/features/git-blame.md) - Code attribution
433
+ - [Cross-Project Context](https://github.com/Arrayo/smart-context-mcp/blob/main/docs/features/cross-project.md) - Multi-project support
215
434
 
216
435
  ## Links
217
436
 
218
- - [GitHub](https://github.com/Arrayo/devctx-mcp-mvp)
437
+ - [GitHub](https://github.com/Arrayo/smart-context-mcp)
219
438
  - [npm](https://www.npmjs.com/package/smart-context-mcp)
220
- - [Issues](https://github.com/Arrayo/devctx-mcp-mvp/issues)
439
+ - [Issues](https://github.com/Arrayo/smart-context-mcp/issues)
221
440
 
222
441
  ## Author
223
442
 
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "smart-context-mcp",
3
- "version": "1.1.0",
4
- "description": "MCP server that reduces agent token usage and improves response quality with compact file summaries, ranked code search, and curated context.",
3
+ "version": "1.3.0",
4
+ "description": "MCP server that reduces agent token usage by 90% with intelligent context compression, task checkpoint persistence, and workflow-aware agent guidance.",
5
5
  "author": "Francisco Caballero Portero <fcp1978@hotmail.com>",
6
6
  "type": "module",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "git+https://github.com/Arrayo/devctx-mcp-mvp.git"
9
+ "url": "git+https://github.com/Arrayo/smart-context-mcp.git"
10
10
  },
11
- "homepage": "https://github.com/Arrayo/devctx-mcp-mvp#readme",
11
+ "homepage": "https://github.com/Arrayo/smart-context-mcp#readme",
12
12
  "bugs": {
13
- "url": "https://github.com/Arrayo/devctx-mcp-mvp/issues"
13
+ "url": "https://github.com/Arrayo/smart-context-mcp/issues"
14
14
  },
15
15
  "bin": {
16
16
  "smart-context-headless": "scripts/headless-wrapper.js",
@@ -30,7 +30,8 @@
30
30
  "scripts/devctx-server.js",
31
31
  "scripts/headless-wrapper.js",
32
32
  "scripts/init-clients.js",
33
- "scripts/report-metrics.js"
33
+ "scripts/report-metrics.js",
34
+ "scripts/report-workflow-metrics.js"
34
35
  ],
35
36
  "engines": {
36
37
  "node": ">=18"
@@ -52,12 +53,14 @@
52
53
  "smoke:formats": "node ./scripts/format-smoke.js",
53
54
  "test": "node --test --test-concurrency=1 ./tests/*.test.js",
54
55
  "verify": "node ./scripts/verify-features-direct.js",
56
+ "benchmark": "node ./scripts/run-benchmark.js",
55
57
  "eval": "node ./evals/harness.js",
56
58
  "eval:context": "node ./evals/harness.js --tool=context",
57
59
  "eval:both": "node ./evals/harness.js --tool=both",
58
60
  "eval:self": "node ./evals/harness.js --root=../.. --corpus=./evals/corpus/self-tasks.json",
59
61
  "eval:report": "node ./evals/report.js",
60
- "report:metrics": "node ./scripts/report-metrics.js"
62
+ "report:metrics": "node ./scripts/report-metrics.js",
63
+ "report:workflows": "node ./scripts/report-workflow-metrics.js"
61
64
  },
62
65
  "dependencies": {
63
66
  "@modelcontextprotocol/sdk": "^1.13.0",
@@ -375,42 +375,71 @@ const updatePreCommitHook = (targetDir, dryRun) => {
375
375
  // Agent rules — instruct agents to prefer devctx tools over built-in ones
376
376
  // ---------------------------------------------------------------------------
377
377
 
378
- const agentRuleBody = `Always prefer devctx MCP tools over built-in file reading, code search, diagnostics, and context recovery.
379
-
380
- - For every non-trivial user prompt, start with smart_turn phase=start before exploring the codebase. Pass the current user prompt and ensureSession=true for a meaningful new task.
381
- - Treat smart_turn phase=start as the default entrypoint for context recovery instead of manually deciding whether to call smart_summary(get).
382
- - Inspect repoSafety from smart_turn or smart_summary responses. If .devctx/state.sqlite is tracked or staged, mutating context writes are blocked until git hygiene is fixed.
383
- - If smart_turn phase=start reports ambiguous_resume, choose the recommended session explicitly with smart_summary sessionId="auto" before continuing.
384
- - After meaningful milestones, end the turn with smart_turn phase=end and the appropriate event (milestone, decision, blocker, task_complete, session_end) so persistence stays event-driven.
385
- - Before ending work, persist the latest nextStep with smart_turn phase=end and event=session_end.
386
- - Use smart_read outline or signatures before full (~90% token savings).
387
- - Use smart_read symbol (string or array) to extract specific functions/classes before editing.
388
- - Use smart_read range for specific lines when you know the location.
389
- - Use full mode only when outline/signatures/symbol are insufficient.
390
- - Use smart_search instead of grep/ripgrep it groups, ranks, and filters automatically.
391
- - Pass intent to smart_search to get task-aware ranking (implementation/debug/tests/config/docs/explore).
392
- - Use smart_shell for diagnostics: git status, ls, find, pwd, test output.
393
- - Use smart_metrics to report token savings or recent devctx usage instead of reading metrics files manually.
394
-
395
- By task:
396
- - Debugging: smart_turn(start) smart_search with intent=debug read signatures inspect symbol smart_shell for tests/errors → smart_turn(end event=milestone or blocker).
397
- - Review: smart_turn(start) → smart_search with intent=implementation → read outline/signatures, focus on changed symbols, minimal changes → smart_turn(end event=milestone).
398
- - Refactor: smart_turn(start) → smart_search with intent=implementation → signatures for public API, preserve behavior, small edits, verify with tests → smart_turn(end event=milestone).
399
- - Tests: smart_turn(start) → smart_search with intent=tests → find existing tests, read symbol of function under test → smart_turn(end event=milestone).
400
- - Config: smart_search with intent=config → find settings, env vars, infrastructure files.
401
- - Architecture: smart_turn(start) → smart_search with intent=explore → directory structure, outlines of key modules and API boundaries → smart_turn(end event=task_switch or milestone).`;
378
+ const agentRuleBody = `**First time in project?** Run build_index to enable search/context quality.
379
+
380
+ Prefer devctx MCP for non-trivial tasks:
381
+ - smart_read(outline|signatures|symbol) instead of Read 90% savings
382
+ - smart_search(intent=...) instead of Grep ranked results
383
+ - smart_context instead of multiple reads one-call builder
384
+ - smart_shell instead of Shell safe diagnostics
385
+
386
+ For non-trivial tasks: smart_turn(start) [work with devctx tools] → smart_turn(end)
387
+
388
+ Reading cascade: outline signatures symbol full (last resort)
389
+
390
+ Detailed workflows: .cursor/rules/profiles-compact/ (debugging, code-review, refactoring, testing, architecture)
391
+
392
+ ---
393
+
394
+ If you didn't use devctx tools in a non-trivial programming task, add at the end:
395
+
396
+ **Note:** devctx not used because: [task too simple | MCP unavailable | index not built | already had sufficient context | native tool more direct for this case]. To use devctx next time: "Use smart-context-mcp: smart_turn(start) → smart_context/smart_searchsmart_read → smart_turn(end)"`;
402
397
 
403
398
  const cursorRuleContent = `---
404
- description: Prefer devctx MCP tools for file reading, code search, and diagnostics
399
+ description: Prefer devctx MCP tools for non-trivial tasks
405
400
  alwaysApply: true
406
401
  ---
407
402
 
408
403
  ${agentRuleBody}
409
404
  `;
410
405
 
406
+ const cursorProfilesNote = `
407
+ # Task-Specific Profiles
408
+
409
+ For detailed workflows, see rules in this directory:
410
+ - debugging.mdc - Error-first, symbol-focused (90% savings)
411
+ - code-review.mdc - Diff-aware, API-focused (87% savings)
412
+ - refactoring.mdc - Graph-aware, test-verified (89% savings)
413
+ - testing.mdc - Coverage-aware, TDD-friendly (90% savings)
414
+ - architecture.mdc - Index-first, minimal-detail (90% savings)
415
+
416
+ These profiles are **conditionally applied** based on file globs and task context.
417
+ The base rule (devctx.mdc) is **always active** but kept minimal to reduce fixed context cost.
418
+ `;
419
+
411
420
  const updateCursorRule = (targetDir, dryRun) => {
412
- const filePath = path.join(targetDir, '.cursor', 'rules', 'devctx.mdc');
413
- writeFile(filePath, cursorRuleContent, dryRun);
421
+ const rulesDir = path.join(targetDir, '.cursor', 'rules');
422
+ const profilesDir = path.join(rulesDir, 'profiles-compact');
423
+
424
+ // Write base rule (always active)
425
+ const baseFilePath = path.join(rulesDir, 'devctx.mdc');
426
+ writeFile(baseFilePath, cursorRuleContent, dryRun);
427
+
428
+ // Write profiles README
429
+ const profilesReadmePath = path.join(profilesDir, 'README.md');
430
+ writeFile(profilesReadmePath, cursorProfilesNote, dryRun);
431
+
432
+ // Copy compact profiles from package
433
+ const sourceProfilesDir = path.join(devctxDir, 'agent-rules', 'profiles-compact');
434
+ if (fs.existsSync(sourceProfilesDir)) {
435
+ const profiles = fs.readdirSync(sourceProfilesDir).filter(f => f.endsWith('.mdc'));
436
+ profiles.forEach(profile => {
437
+ const sourcePath = path.join(sourceProfilesDir, profile);
438
+ const targetPath = path.join(profilesDir, profile);
439
+ const content = fs.readFileSync(sourcePath, 'utf8');
440
+ writeFile(targetPath, content, dryRun);
441
+ });
442
+ }
414
443
  };
415
444
 
416
445
  const SECTION_START = '<!-- devctx:start -->';
@@ -2,6 +2,7 @@
2
2
  import path from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
4
  import { smartMetrics } from '../src/tools/smart-metrics.js';
5
+ import { formatAdoptionReport } from '../src/analytics/adoption.js';
5
6
 
6
7
  const requireValue = (argv, index, flag) => {
7
8
  const value = argv[index + 1];
@@ -88,6 +89,10 @@ const printHuman = (report) => {
88
89
  ` ${tool.tool.padEnd(14)} count=${formatNumber(tool.count)} raw=${formatNumber(tool.rawTokens)} final=${formatNumber(tool.compressedTokens)} saved=${formatNumber(tool.savedTokens)} (${tool.savingsPct}%)`
89
90
  );
90
91
  }
92
+
93
+ if (report.adoption) {
94
+ console.log(formatAdoptionReport(report.adoption));
95
+ }
91
96
  };
92
97
 
93
98
  export const main = async () => {