nex-level-code 0.1.0 → 0.1.2
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/LICENSE +133 -0
- package/README.md +274 -0
- package/dist/commands/sync.d.ts +10 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +235 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/webui.d.ts +9 -0
- package/dist/commands/webui.d.ts.map +1 -0
- package/dist/commands/webui.js +258 -0
- package/dist/commands/webui.js.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/services/install.d.ts +5 -0
- package/dist/services/install.d.ts.map +1 -1
- package/dist/services/install.js +52 -0
- package/dist/services/install.js.map +1 -1
- package/package.json +2 -2
- package/templates/hooks/memory-sync.js +216 -0
- package/templates/rules/claude.md +2 -1
- package/templates/rules/cursor.md +2 -1
- package/templates/webui/patches.diff +372 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# PolyForm Noncommercial License 1.0.0
|
|
2
|
+
|
|
3
|
+
<https://polyformproject.org/licenses/noncommercial/1.0.0>
|
|
4
|
+
|
|
5
|
+
Required Notice: Copyright FTay Consulting (https://github.com/ftay1026/nex-level-code)
|
|
6
|
+
|
|
7
|
+
## Acceptance
|
|
8
|
+
|
|
9
|
+
In order to get any license under these terms, you must agree
|
|
10
|
+
to them as both strict obligations and conditions to all
|
|
11
|
+
your licenses.
|
|
12
|
+
|
|
13
|
+
## Copyright License
|
|
14
|
+
|
|
15
|
+
The licensor grants you a copyright license for the
|
|
16
|
+
software to do everything you might do with the software
|
|
17
|
+
that would otherwise infringe the licensor's copyright
|
|
18
|
+
in it for any permitted purpose. However, you may
|
|
19
|
+
only distribute the software according to [Distribution
|
|
20
|
+
License](#distribution-license) and make changes or new works
|
|
21
|
+
based on the software according to [Changes and New Works
|
|
22
|
+
License](#changes-and-new-works-license).
|
|
23
|
+
|
|
24
|
+
## Distribution License
|
|
25
|
+
|
|
26
|
+
The licensor grants you an additional copyright license
|
|
27
|
+
to distribute copies of the software. Your license
|
|
28
|
+
to distribute covers distributing the software with
|
|
29
|
+
changes and new works permitted by [Changes and New Works
|
|
30
|
+
License](#changes-and-new-works-license).
|
|
31
|
+
|
|
32
|
+
## Notices
|
|
33
|
+
|
|
34
|
+
You must ensure that anyone who gets a copy of any part of
|
|
35
|
+
the software from you also gets a copy of these terms or the
|
|
36
|
+
URL for them above, as well as copies of any plain-text lines
|
|
37
|
+
beginning with `Required Notice:` that the licensor provided
|
|
38
|
+
with the software. For example:
|
|
39
|
+
|
|
40
|
+
> Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
|
|
41
|
+
|
|
42
|
+
## Changes and New Works License
|
|
43
|
+
|
|
44
|
+
The licensor grants you an additional copyright license to
|
|
45
|
+
make changes and new works based on the software for any
|
|
46
|
+
permitted purpose.
|
|
47
|
+
|
|
48
|
+
## Patent License
|
|
49
|
+
|
|
50
|
+
The licensor grants you a patent license for the software that
|
|
51
|
+
covers patent claims the licensor can license, or becomes able
|
|
52
|
+
to license, that you would infringe by using the software.
|
|
53
|
+
|
|
54
|
+
## Noncommercial Purposes
|
|
55
|
+
|
|
56
|
+
Any noncommercial purpose is a permitted purpose.
|
|
57
|
+
|
|
58
|
+
## Personal Uses
|
|
59
|
+
|
|
60
|
+
Personal use for research, experiment, and testing for
|
|
61
|
+
the benefit of public knowledge, personal study, private
|
|
62
|
+
entertainment, hobby projects, amateur pursuits, or religious
|
|
63
|
+
observance, without any anticipated commercial application,
|
|
64
|
+
is use for a permitted purpose.
|
|
65
|
+
|
|
66
|
+
## Noncommercial Organizations
|
|
67
|
+
|
|
68
|
+
Use by any charitable organization, educational institution,
|
|
69
|
+
public research organization, public safety or health
|
|
70
|
+
organization, environmental protection organization,
|
|
71
|
+
or government institution is use for a permitted purpose
|
|
72
|
+
regardless of the source of funding or obligations resulting
|
|
73
|
+
from the funding.
|
|
74
|
+
|
|
75
|
+
## Fair Use
|
|
76
|
+
|
|
77
|
+
You may have "fair use" rights for the software under the
|
|
78
|
+
law. These terms do not limit them.
|
|
79
|
+
|
|
80
|
+
## No Other Rights
|
|
81
|
+
|
|
82
|
+
These terms do not allow you to sublicense or transfer any of
|
|
83
|
+
your licenses to anyone else, or prevent the licensor from
|
|
84
|
+
granting licenses to anyone else. These terms do not imply
|
|
85
|
+
any other licenses.
|
|
86
|
+
|
|
87
|
+
## Patent Defense
|
|
88
|
+
|
|
89
|
+
If you make any written claim that the software infringes or
|
|
90
|
+
contributes to infringement of any patent, your patent license
|
|
91
|
+
for the software granted under these terms ends immediately. If
|
|
92
|
+
your company makes such a claim, your patent license ends
|
|
93
|
+
immediately for work on behalf of your company.
|
|
94
|
+
|
|
95
|
+
## Violations
|
|
96
|
+
|
|
97
|
+
The first time you are notified in writing that you have
|
|
98
|
+
violated any of these terms, or done anything with the software
|
|
99
|
+
not covered by your licenses, your licenses can nonetheless
|
|
100
|
+
continue if you come into full compliance with these terms,
|
|
101
|
+
and take practical steps to correct past violations, within
|
|
102
|
+
32 days of receiving notice. Otherwise, all your licenses
|
|
103
|
+
end immediately.
|
|
104
|
+
|
|
105
|
+
## No Liability
|
|
106
|
+
|
|
107
|
+
***As far as the law allows, the software comes as is, without
|
|
108
|
+
any warranty or condition, and the licensor will not be liable
|
|
109
|
+
to you for any damages arising out of these terms or the use
|
|
110
|
+
or nature of the software, under any kind of legal claim.***
|
|
111
|
+
|
|
112
|
+
## Definitions
|
|
113
|
+
|
|
114
|
+
The **licensor** is the individual or entity offering these
|
|
115
|
+
terms, and the **software** is the software the licensor makes
|
|
116
|
+
available under these terms.
|
|
117
|
+
|
|
118
|
+
**You** refers to the individual or entity agreeing to these
|
|
119
|
+
terms.
|
|
120
|
+
|
|
121
|
+
**Your company** is any legal entity, sole proprietorship,
|
|
122
|
+
or other kind of organization that you work for, plus all
|
|
123
|
+
organizations that have control over, are under the control of,
|
|
124
|
+
or are under common control with that organization. **Control**
|
|
125
|
+
means ownership of substantially all the assets of an entity,
|
|
126
|
+
or the power to direct its management and policies by vote,
|
|
127
|
+
contract, or otherwise. Control can be direct or indirect.
|
|
128
|
+
|
|
129
|
+
**Your licenses** are all the licenses granted to you for the
|
|
130
|
+
software under these terms.
|
|
131
|
+
|
|
132
|
+
**Use** means anything you do with the software requiring one
|
|
133
|
+
of your licenses.
|
package/README.md
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# Nex Level Code (NLC)
|
|
2
|
+
|
|
3
|
+
**Turn your AI coding assistant into an agent that never forgets.**
|
|
4
|
+
|
|
5
|
+
One command. Persistent memory. Cross-device sync. Automatic task logging. Behavioral rules that actually stick. No infrastructure to manage, no Docker to run, no open ports, no attack surface.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx nex-level-code install
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Works with Claude Code, Cursor, GitHub Copilot, Windsurf, and OpenAI Codex.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## The Problem
|
|
16
|
+
|
|
17
|
+
AI coding assistants are powerful — but they're goldfish.
|
|
18
|
+
|
|
19
|
+
Every session starts from zero. Your agent doesn't know what it built yesterday, what decisions you made last week, or what's currently broken. You end up repeating context, re-explaining architecture, and watching it make the same mistakes you already corrected.
|
|
20
|
+
|
|
21
|
+
Platforms like [OpenClaw](https://github.com/nicepkg/openclaw) solve this with a full agent gateway — 43+ messaging channels, Docker sandboxing, vector databases, device control. But that means running infrastructure, managing ports, configuring databases, and accepting a massive attack surface.
|
|
22
|
+
|
|
23
|
+
**NLC takes a different approach.** Instead of replacing your tools, it enhances them. Your agent gets persistent memory, session continuity, and cross-device sync — with zero infrastructure. Just files, git, and hooks.
|
|
24
|
+
|
|
25
|
+
| | OpenClaw | Claude Code + NLC |
|
|
26
|
+
|---|---------|-------------------|
|
|
27
|
+
| **Memory** | Vector DB (LanceDB) | Flat files + git sync |
|
|
28
|
+
| **Session continuity** | JSONL + /compact | session-handoff.md + compaction |
|
|
29
|
+
| **Cross-device sync** | Not built-in | Git-backed, automatic |
|
|
30
|
+
| **Auto task logging** | None | Haiku-powered semantic logging |
|
|
31
|
+
| **IDE integration** | None | Native (VS Code, etc.) |
|
|
32
|
+
| **Attack surface** | WebSocket gateway, 43 channels, device control | Zero network-facing components |
|
|
33
|
+
| **Setup** | Docker + config + multiple services | `npx nex-level-code install` |
|
|
34
|
+
| **Cost** | Self-hosted + API keys | Your existing subscription ($20–$200/mo) |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## What You Get
|
|
39
|
+
|
|
40
|
+
### In the Box (default install)
|
|
41
|
+
|
|
42
|
+
#### 1. Memory Protocol
|
|
43
|
+
Your agent follows a strict memory protocol — reading context at session start, updating it incrementally as it works, and never losing progress.
|
|
44
|
+
|
|
45
|
+
- **session-handoff.md** — Living document of what's working, what's broken, key decisions, and current focus. Updated during work, not just at the end.
|
|
46
|
+
- **MEMORY.md** — Project overview, architecture notes, user preferences, setup state. The agent's long-term knowledge base.
|
|
47
|
+
- **Staleness warnings** — If memory files haven't been updated in over an hour, the agent gets a nudge.
|
|
48
|
+
|
|
49
|
+
#### 2. Automatic Development Logging
|
|
50
|
+
Every time the agent completes a meaningful task, it's logged automatically. No manual notes needed.
|
|
51
|
+
|
|
52
|
+
- Fires on every agent response via a Stop hook
|
|
53
|
+
- Sends the exchange to Claude Haiku for semantic analysis: *"Was a real task completed here?"*
|
|
54
|
+
- If yes, logs 1–2 lines to `memory/YYYY-MM-DD.md` with a timestamp
|
|
55
|
+
- Next session automatically sees yesterday's and today's logs
|
|
56
|
+
- Filters out noise — reading files, asking questions, and planning don't count
|
|
57
|
+
|
|
58
|
+
#### 3. Behavioral Rules
|
|
59
|
+
Pre-configured rules that make your agent actually useful:
|
|
60
|
+
|
|
61
|
+
- **Never ask permission to read** — files, URLs, docs. Just read them.
|
|
62
|
+
- **Always ask before writing** — no surprise edits to your codebase.
|
|
63
|
+
- **Log every decision** — when you make a call, it's recorded with context.
|
|
64
|
+
- **PREVC workflow** — Planning, Review, Execution, Validation, Confirmation. Scales from quick bug fixes (just Execute + Validate) to complex features (full cycle).
|
|
65
|
+
- **Communication style** — concise, direct, no false confidence, distinguishes solutions from workarounds.
|
|
66
|
+
|
|
67
|
+
#### 4. Auto-Permissions
|
|
68
|
+
Pre-approves common tool permissions (Bash, Read, Edit, Write, Grep, Glob, WebFetch, WebSearch) so you're not clicking "Allow" on every action.
|
|
69
|
+
|
|
70
|
+
#### 5. MCP Server
|
|
71
|
+
NLC registers an MCP server that gives your agent programmatic access to:
|
|
72
|
+
|
|
73
|
+
| Tool | What it does |
|
|
74
|
+
|------|-------------|
|
|
75
|
+
| `nlc-status` | Check NLC installation health |
|
|
76
|
+
| `nlc-handoff` | Read or update session-handoff.md |
|
|
77
|
+
| `nlc-memory` | Read or update MEMORY.md |
|
|
78
|
+
| `nlc-log` | Read development logs by date range |
|
|
79
|
+
| `nlc-doctor` | Run diagnostics and get a health report |
|
|
80
|
+
|
|
81
|
+
#### 6. Multi-Tool Support
|
|
82
|
+
NLC detects which AI coding tools you have installed and configures accordingly:
|
|
83
|
+
|
|
84
|
+
| Tool | Hooks | Rules File | MCP |
|
|
85
|
+
|------|-------|-----------|-----|
|
|
86
|
+
| **Claude Code** | Full support (5 events) | CLAUDE.md | .mcp.json |
|
|
87
|
+
| **Cursor** | Pending | .cursorrules | .cursor/mcp.json |
|
|
88
|
+
| **GitHub Copilot** | — | .github/copilot-instructions.md | .github/mcp.json |
|
|
89
|
+
| **Windsurf** | Pending | .windsurfrules | .windsurf/mcp.json |
|
|
90
|
+
| **OpenAI Codex** | — | AGENTS.md | .codex/mcp.json |
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### Optional Add-Ons
|
|
95
|
+
|
|
96
|
+
#### Cross-Device Memory Sync
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
nlc sync setup
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Share your agent's brain across machines. Work on your desktop, close the laptop, continue from your phone or a VPS — your agent picks up exactly where it left off.
|
|
103
|
+
|
|
104
|
+
- Creates a private GitHub repo for your memory files
|
|
105
|
+
- Installs hooks: **SessionStart** pulls latest, **Stop** pushes updates
|
|
106
|
+
- Syncs MEMORY.md, session-handoff.md, CLAUDE.md, and daily dev logs
|
|
107
|
+
- Content-based diffing — only syncs when files actually change
|
|
108
|
+
- Works across Windows, macOS, and Linux
|
|
109
|
+
|
|
110
|
+
**How it works:**
|
|
111
|
+
```
|
|
112
|
+
Desktop (Stop hook) → git push → GitHub → git pull → VPS (SessionStart hook)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Run `nlc sync setup` on each machine. That's it.
|
|
116
|
+
|
|
117
|
+
#### Web UI (Self-Hosted)
|
|
118
|
+
|
|
119
|
+
Access Claude Code from any browser — phone, tablet, another computer — with a clean web interface.
|
|
120
|
+
|
|
121
|
+
Based on [claudecodeui](https://github.com/siteboon/claudecodeui) with **9 production patches** applied:
|
|
122
|
+
|
|
123
|
+
| Patch | Problem Fixed |
|
|
124
|
+
|-------|--------------|
|
|
125
|
+
| Processing hang fix | UI stuck on "Processing..." for up to 5 minutes |
|
|
126
|
+
| Auto-approve tools | No more "Allow/Deny" popups for every action |
|
|
127
|
+
| Inline questions | Agent questions appear in chat, not hijacking the input |
|
|
128
|
+
| Textarea always enabled | Type your next message while the agent works |
|
|
129
|
+
| Crash handlers | Graceful shutdown, no orphaned processes |
|
|
130
|
+
| Abort on disconnect | Closing browser stops the API call (saves money) |
|
|
131
|
+
| JWT secret | Real secret, not the open-source default |
|
|
132
|
+
| Dead code cleanup | Removed unused imports and props |
|
|
133
|
+
| HTTPS + Firewall | nginx reverse proxy, Let's Encrypt SSL, locked-down ports |
|
|
134
|
+
|
|
135
|
+
> Setup guide: `nlc webui setup` *(coming soon — currently documented in [claude-code-webui.md](claude-code-webui.md))*
|
|
136
|
+
|
|
137
|
+
#### Messaging Relay (Telegram + Discord)
|
|
138
|
+
|
|
139
|
+
Talk to your agent from Telegram or Discord. It reads your project context, uses Claude Code under the hood, and maintains per-channel conversation threads.
|
|
140
|
+
|
|
141
|
+
- Telegram: DMs with your bot
|
|
142
|
+
- Discord: DMs, server channels, smart routing (only responds when relevant)
|
|
143
|
+
- Bot-to-bot communication (up to 3 exchanges per channel)
|
|
144
|
+
- Session continuity with `/new` to reset
|
|
145
|
+
|
|
146
|
+
> Setup: See [claude-telegram-relay](https://github.com/godagoo/claude-telegram-relay) — `nlc relay setup` coming soon.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## CLI Commands
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
nlc install # Install NLC to detected AI tool
|
|
154
|
+
nlc install --tool cursor # Force a specific tool
|
|
155
|
+
nlc install --force # Overwrite existing installation
|
|
156
|
+
|
|
157
|
+
nlc status # Check what's installed and healthy
|
|
158
|
+
nlc doctor # Diagnose issues and auto-fix them
|
|
159
|
+
nlc update # Update NLC scripts to latest version
|
|
160
|
+
nlc uninstall # Remove NLC (preserves your memory files)
|
|
161
|
+
|
|
162
|
+
nlc sync setup # Set up cross-device memory sync
|
|
163
|
+
nlc sync status # Check sync health and recent activity
|
|
164
|
+
|
|
165
|
+
nlc mcp # Start the MCP server (usually auto-configured)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## How It Works
|
|
171
|
+
|
|
172
|
+
NLC hooks into your AI tool's lifecycle events:
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
┌─────────────────────────────────────────────────────────┐
|
|
176
|
+
│ SessionStart │
|
|
177
|
+
│ ├─ Pull latest memory from GitHub (if sync enabled) │
|
|
178
|
+
│ └─ Inject memory protocol + recent dev logs │
|
|
179
|
+
│ │
|
|
180
|
+
│ UserPromptSubmit │
|
|
181
|
+
│ └─ Warn if session-handoff.md is stale (>1 hour) │
|
|
182
|
+
│ │
|
|
183
|
+
│ Stop (after each agent response) │
|
|
184
|
+
│ ├─ Extract preferences/requirements (memory-mcp) │
|
|
185
|
+
│ ├─ Analyze if a task was completed (Haiku) │
|
|
186
|
+
│ ├─ Log to YYYY-MM-DD.md if yes │
|
|
187
|
+
│ └─ Push memory to GitHub (if sync enabled) │
|
|
188
|
+
│ │
|
|
189
|
+
│ PreCompact / SessionEnd │
|
|
190
|
+
│ └─ Push memory to GitHub (if sync enabled) │
|
|
191
|
+
└─────────────────────────────────────────────────────────┘
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
No servers. No databases. No Docker. Just files and git.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Roadmap
|
|
199
|
+
|
|
200
|
+
NLC gives you persistent memory and session continuity today. Here's what's coming:
|
|
201
|
+
|
|
202
|
+
| Feature | Status | Description |
|
|
203
|
+
|---------|--------|-------------|
|
|
204
|
+
| Memory protocol | ✅ Shipped | session-handoff.md + MEMORY.md |
|
|
205
|
+
| Auto dev logging | ✅ Shipped | Haiku-powered task detection |
|
|
206
|
+
| Behavioral rules | ✅ Shipped | PREVC workflow + communication style |
|
|
207
|
+
| Cross-device sync | ✅ Shipped | Git-backed, automatic |
|
|
208
|
+
| MCP server | ✅ Shipped | In-session memory tools |
|
|
209
|
+
| Multi-tool support | ✅ Shipped | Claude, Cursor, Copilot, Windsurf, Codex |
|
|
210
|
+
| Web UI setup | 🔧 In progress | `nlc webui setup` with auto-patching |
|
|
211
|
+
| Relay setup | 🔧 In progress | `nlc relay setup` for Telegram/Discord |
|
|
212
|
+
| Browser automation | 📋 Planned | Playwright integration via MCP |
|
|
213
|
+
| Voice input/output | 📋 Planned | Whisper STT + TTS |
|
|
214
|
+
| Scheduling | 📋 Planned | Cron-based task automation |
|
|
215
|
+
| Vector memory | 📋 Planned | Semantic search over project history |
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Requirements
|
|
220
|
+
|
|
221
|
+
- **Node.js** 20+ (for hook scripts)
|
|
222
|
+
- **An AI coding tool** — Claude Code, Cursor, GitHub Copilot, Windsurf, or OpenAI Codex
|
|
223
|
+
- **GitHub CLI** (`gh`) — only needed for `nlc sync setup`
|
|
224
|
+
- **Anthropic API key** — only needed for the auto dev logger (calls Haiku at ~$0.001 per log entry)
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Install
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
# From npm (recommended)
|
|
232
|
+
npx nex-level-code install
|
|
233
|
+
|
|
234
|
+
# Or install globally
|
|
235
|
+
npm install -g nex-level-code
|
|
236
|
+
nlc install
|
|
237
|
+
|
|
238
|
+
# From GitHub (latest)
|
|
239
|
+
npx github:ftay1026/nex-level-code install
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
After installing, start a new session in your AI tool. NLC activates automatically.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Uninstall
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
nlc uninstall
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Removes all hooks, scripts, and MCP config. Your memory files (session-handoff.md, MEMORY.md, dev logs) are preserved — they're your data, not ours.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Philosophy
|
|
257
|
+
|
|
258
|
+
AI coding assistants should remember what they've done, learn from your preferences, and pick up where they left off. They shouldn't need a Kubernetes cluster to do it.
|
|
259
|
+
|
|
260
|
+
NLC is opinionated:
|
|
261
|
+
- **Files over databases** — Markdown files you can read, edit, and version control
|
|
262
|
+
- **Git over proprietary sync** — Your memory lives in your own private repo
|
|
263
|
+
- **Hooks over agents** — Lightweight lifecycle events, not a separate runtime
|
|
264
|
+
- **Enhancement over replacement** — Works with your existing tools, not instead of them
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## License
|
|
269
|
+
|
|
270
|
+
MIT
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
Built by [FTay Consulting](https://github.com/ftay1026) with Claude Code + NLC (naturally).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NLC Sync Command — Set up cross-device memory sync.
|
|
3
|
+
*
|
|
4
|
+
* Creates a private GitHub repo, clones it locally, installs the
|
|
5
|
+
* memory-sync hook, and registers it for SessionStart + Stop events.
|
|
6
|
+
* This lets multiple machines share the same agent "brain."
|
|
7
|
+
*/
|
|
8
|
+
import { Command } from 'commander';
|
|
9
|
+
export declare function registerSyncCommand(program: Command): void;
|
|
10
|
+
//# sourceMappingURL=sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAyCpC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA2K1D"}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* NLC Sync Command — Set up cross-device memory sync.
|
|
4
|
+
*
|
|
5
|
+
* Creates a private GitHub repo, clones it locally, installs the
|
|
6
|
+
* memory-sync hook, and registers it for SessionStart + Stop events.
|
|
7
|
+
* This lets multiple machines share the same agent "brain."
|
|
8
|
+
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
+
}) : function(o, v) {
|
|
23
|
+
o["default"] = v;
|
|
24
|
+
});
|
|
25
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
+
var ownKeys = function(o) {
|
|
27
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
+
var ar = [];
|
|
29
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
+
return ar;
|
|
31
|
+
};
|
|
32
|
+
return ownKeys(o);
|
|
33
|
+
};
|
|
34
|
+
return function (mod) {
|
|
35
|
+
if (mod && mod.__esModule) return mod;
|
|
36
|
+
var result = {};
|
|
37
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
+
__setModuleDefault(result, mod);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
42
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
43
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
44
|
+
};
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
exports.registerSyncCommand = registerSyncCommand;
|
|
47
|
+
const fs = __importStar(require("fs-extra"));
|
|
48
|
+
const path = __importStar(require("path"));
|
|
49
|
+
const os = __importStar(require("os"));
|
|
50
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
51
|
+
const child_process_1 = require("child_process");
|
|
52
|
+
const tools_1 = require("../registry/tools");
|
|
53
|
+
function getTemplatesDir() {
|
|
54
|
+
return path.join(__dirname, '..', '..', 'templates');
|
|
55
|
+
}
|
|
56
|
+
function getNodePath() {
|
|
57
|
+
return process.execPath;
|
|
58
|
+
}
|
|
59
|
+
function findRepo() {
|
|
60
|
+
const home = os.homedir();
|
|
61
|
+
const candidates = [
|
|
62
|
+
path.join(home, 'nex-memory'),
|
|
63
|
+
path.join(home, 'nlc-memory'),
|
|
64
|
+
];
|
|
65
|
+
if (process.platform === 'win32') {
|
|
66
|
+
for (const d of ['C', 'D', 'E']) {
|
|
67
|
+
candidates.push(path.join(`${d}:`, 'nex-memory'));
|
|
68
|
+
candidates.push(path.join(`${d}:`, 'dev', 'nex-memory'));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (process.env.NLC_MEMORY_REPO && fs.pathExistsSync(process.env.NLC_MEMORY_REPO)) {
|
|
72
|
+
return process.env.NLC_MEMORY_REPO;
|
|
73
|
+
}
|
|
74
|
+
for (const p of candidates) {
|
|
75
|
+
if (fs.pathExistsSync(path.join(p, '.git')))
|
|
76
|
+
return p;
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
function registerSyncCommand(program) {
|
|
81
|
+
const sync = program
|
|
82
|
+
.command('sync')
|
|
83
|
+
.description('Set up cross-device memory sync via a shared GitHub repo');
|
|
84
|
+
// ── nlc sync setup ──────────────────────────────────────────
|
|
85
|
+
sync
|
|
86
|
+
.command('setup')
|
|
87
|
+
.description('Create a shared memory repo and install sync hooks')
|
|
88
|
+
.option('-r, --repo <name>', 'GitHub repo name', 'nex-memory')
|
|
89
|
+
.option('-p, --path <path>', 'Local clone path (defaults to ~/nex-memory)')
|
|
90
|
+
.option('--private', 'Make the repo private (default)', true)
|
|
91
|
+
.action(async (options) => {
|
|
92
|
+
try {
|
|
93
|
+
console.log(chalk_1.default.bold('\n NLC Memory Sync — Setup\n'));
|
|
94
|
+
// 1. Check prerequisites
|
|
95
|
+
try {
|
|
96
|
+
(0, child_process_1.execSync)('gh --version', { stdio: 'pipe' });
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
console.log(chalk_1.default.red(' ✗ GitHub CLI (gh) is required but not found.'));
|
|
100
|
+
console.log(chalk_1.default.dim(' Install: https://cli.github.com\n'));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
(0, child_process_1.execSync)('gh auth status', { stdio: 'pipe' });
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
console.log(chalk_1.default.red(' ✗ Not authenticated with GitHub CLI.'));
|
|
108
|
+
console.log(chalk_1.default.dim(' Run: gh auth login\n'));
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
// 2. Check if repo already exists locally
|
|
112
|
+
const existing = findRepo();
|
|
113
|
+
const clonePath = options.path
|
|
114
|
+
? path.resolve(options.path)
|
|
115
|
+
: existing || path.join(os.homedir(), 'nex-memory');
|
|
116
|
+
if (existing) {
|
|
117
|
+
console.log(chalk_1.default.dim(` Found existing repo: ${existing}`));
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
// Create the GitHub repo
|
|
121
|
+
console.log(chalk_1.default.dim(` Creating GitHub repo: ${options.repo}...`));
|
|
122
|
+
try {
|
|
123
|
+
(0, child_process_1.execSync)(`gh repo create ${options.repo} --private --description "Shared AI assistant memory — synced across devices" --clone`, { cwd: path.dirname(clonePath), stdio: 'pipe', timeout: 30000 });
|
|
124
|
+
console.log(chalk_1.default.dim(` ✓ Repo created and cloned to ${clonePath}`));
|
|
125
|
+
}
|
|
126
|
+
catch (e) {
|
|
127
|
+
// Repo might already exist on GitHub — try cloning
|
|
128
|
+
try {
|
|
129
|
+
const username = (0, child_process_1.execSync)('gh api user -q .login', { stdio: 'pipe' }).toString().trim();
|
|
130
|
+
(0, child_process_1.execSync)(`gh repo clone ${username}/${options.repo} "${clonePath}"`, { stdio: 'pipe', timeout: 30000 });
|
|
131
|
+
console.log(chalk_1.default.dim(` ✓ Cloned existing repo to ${clonePath}`));
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
console.log(chalk_1.default.red(` ✗ Failed to create or clone repo: ${e.message}`));
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// 3. Install sync hook script
|
|
140
|
+
const tools = (0, tools_1.detectInstalledTools)();
|
|
141
|
+
if (tools.length === 0) {
|
|
142
|
+
console.log(chalk_1.default.yellow(' No AI coding tools detected.\n'));
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const templateSrc = path.join(getTemplatesDir(), 'hooks', 'memory-sync.js');
|
|
146
|
+
const nodePath = getNodePath();
|
|
147
|
+
for (const tool of tools) {
|
|
148
|
+
if (!tool.hooks.supported || !tool.paths.scriptsDir)
|
|
149
|
+
continue;
|
|
150
|
+
console.log(chalk_1.default.dim(`\n Tool: ${tool.displayName}`));
|
|
151
|
+
// Copy sync script
|
|
152
|
+
const scriptDst = path.join(tool.paths.scriptsDir, 'nlc-memory-sync.js');
|
|
153
|
+
await fs.ensureDir(tool.paths.scriptsDir);
|
|
154
|
+
await fs.copyFile(templateSrc, scriptDst);
|
|
155
|
+
console.log(chalk_1.default.dim(' ✓ Installed nlc-memory-sync.js'));
|
|
156
|
+
// Register hooks in settings
|
|
157
|
+
if (await fs.pathExists(tool.paths.settingsFile)) {
|
|
158
|
+
try {
|
|
159
|
+
const settings = await fs.readJSON(tool.paths.settingsFile);
|
|
160
|
+
if (!settings.hooks)
|
|
161
|
+
settings.hooks = {};
|
|
162
|
+
const quote = process.platform === 'win32' ? '"' : '';
|
|
163
|
+
const syncCommand = `${quote}${nodePath}${quote} ${quote}${scriptDst}${quote}`;
|
|
164
|
+
// Add to SessionStart (pull — before other hooks)
|
|
165
|
+
if (!settings.hooks.SessionStart)
|
|
166
|
+
settings.hooks.SessionStart = [{ hooks: [] }];
|
|
167
|
+
const startHooks = settings.hooks.SessionStart[0].hooks;
|
|
168
|
+
const hasSyncStart = startHooks.some((h) => h.command?.includes('nlc-memory-sync'));
|
|
169
|
+
if (!hasSyncStart) {
|
|
170
|
+
startHooks.unshift({ type: 'command', command: syncCommand, timeout: 20 });
|
|
171
|
+
console.log(chalk_1.default.dim(' ✓ Registered SessionStart → pull'));
|
|
172
|
+
}
|
|
173
|
+
// Add to Stop (push — after other hooks)
|
|
174
|
+
if (!settings.hooks.Stop)
|
|
175
|
+
settings.hooks.Stop = [{ hooks: [] }];
|
|
176
|
+
const stopHooks = settings.hooks.Stop[0].hooks;
|
|
177
|
+
const hasSyncStop = stopHooks.some((h) => h.command?.includes('nlc-memory-sync'));
|
|
178
|
+
if (!hasSyncStop) {
|
|
179
|
+
stopHooks.push({ type: 'command', command: syncCommand, timeout: 20 });
|
|
180
|
+
console.log(chalk_1.default.dim(' ✓ Registered Stop → push'));
|
|
181
|
+
}
|
|
182
|
+
await fs.writeJSON(tool.paths.settingsFile, settings, { spaces: 2 });
|
|
183
|
+
}
|
|
184
|
+
catch { }
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
console.log(chalk_1.default.green('\n ✓ Memory sync configured!\n'));
|
|
188
|
+
console.log(chalk_1.default.dim(' How it works:'));
|
|
189
|
+
console.log(chalk_1.default.dim(' • Session start → pulls latest memory from GitHub'));
|
|
190
|
+
console.log(chalk_1.default.dim(' • After each response → pushes updates to GitHub'));
|
|
191
|
+
console.log(chalk_1.default.dim(' • Run this same command on other machines to sync them\n'));
|
|
192
|
+
console.log(chalk_1.default.dim(` Repo: ${clonePath}`));
|
|
193
|
+
console.log(chalk_1.default.dim(' To add another machine: nlc sync setup\n'));
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
console.error(`\n Error: ${error.message}\n`);
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
// ── nlc sync status ─────────────────────────────────────────
|
|
201
|
+
sync
|
|
202
|
+
.command('status')
|
|
203
|
+
.description('Show memory sync status')
|
|
204
|
+
.action(async () => {
|
|
205
|
+
const repoPath = findRepo();
|
|
206
|
+
if (!repoPath) {
|
|
207
|
+
console.log(chalk_1.default.yellow('\n Memory sync not configured. Run: nlc sync setup\n'));
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
console.log(chalk_1.default.bold('\n NLC Memory Sync — Status\n'));
|
|
211
|
+
console.log(chalk_1.default.dim(` Repo: ${repoPath}`));
|
|
212
|
+
// Check git status
|
|
213
|
+
try {
|
|
214
|
+
const log = (0, child_process_1.execSync)('git log --oneline -5', { cwd: repoPath, stdio: 'pipe' }).toString().trim();
|
|
215
|
+
console.log(chalk_1.default.dim(`\n Recent syncs:`));
|
|
216
|
+
for (const line of log.split('\n')) {
|
|
217
|
+
console.log(chalk_1.default.dim(` ${line}`));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
console.log(chalk_1.default.red(' ✗ Could not read git log'));
|
|
222
|
+
}
|
|
223
|
+
// Check files
|
|
224
|
+
const files = fs.readdirSync(repoPath).filter(f => !f.startsWith('.') && f.endsWith('.md'));
|
|
225
|
+
console.log(chalk_1.default.dim(`\n Files synced: ${files.length}`));
|
|
226
|
+
for (const f of files) {
|
|
227
|
+
const stat = fs.statSync(path.join(repoPath, f));
|
|
228
|
+
const age = Math.floor((Date.now() - stat.mtimeMs) / (1000 * 60));
|
|
229
|
+
const ageStr = age < 60 ? `${age}m ago` : `${Math.floor(age / 60)}h ago`;
|
|
230
|
+
console.log(chalk_1.default.dim(` ${f} (${ageStr})`));
|
|
231
|
+
}
|
|
232
|
+
console.log('');
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CH,kDA2KC;AAnND,6CAA+B;AAC/B,2CAA6B;AAC7B,uCAAyB;AACzB,kDAA0B;AAC1B,iDAAyC;AACzC,6CAAyD;AAEzD,SAAS,eAAe;IACtB,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,WAAW;IAClB,OAAO,OAAO,CAAC,QAAQ,CAAC;AAC1B,CAAC;AAED,SAAS,QAAQ;IACf,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;IAC1B,MAAM,UAAU,GAAG;QACjB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC;QAC7B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC;KAC9B,CAAC;IAEF,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;YAChC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC;YAClD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;QAClF,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IACrC,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,IAAI,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAgB,mBAAmB,CAAC,OAAgB;IAClD,MAAM,IAAI,GAAG,OAAO;SACjB,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,0DAA0D,CAAC,CAAC;IAE3E,+DAA+D;IAC/D,IAAI;SACD,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,oDAAoD,CAAC;SACjE,MAAM,CAAC,mBAAmB,EAAE,kBAAkB,EAAE,YAAY,CAAC;SAC7D,MAAM,CAAC,mBAAmB,EAAE,6CAA6C,CAAC;SAC1E,MAAM,CAAC,WAAW,EAAE,iCAAiC,EAAE,IAAI,CAAC;SAC5D,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACxB,IAAI,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC,CAAC;YAEzD,yBAAyB;YACzB,IAAI,CAAC;gBACH,IAAA,wBAAQ,EAAC,cAAc,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YAC9C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC,CAAC;gBACzE,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC,CAAC;gBAChE,OAAO;YACT,CAAC;YAED,IAAI,CAAC;gBACH,IAAA,wBAAQ,EAAC,gBAAgB,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YAChD,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC,CAAC;gBACjE,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC,CAAC;gBACnD,OAAO;YACT,CAAC;YAED,0CAA0C;YAC1C,MAAM,QAAQ,GAAG,QAAQ,EAAE,CAAC;YAC5B,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI;gBAC5B,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;gBAC5B,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,YAAY,CAAC,CAAC;YAEtD,IAAI,QAAQ,EAAE,CAAC;gBACb,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,0BAA0B,QAAQ,EAAE,CAAC,CAAC,CAAC;YAC/D,CAAC;iBAAM,CAAC;gBACN,yBAAyB;gBACzB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,2BAA2B,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC;gBACrE,IAAI,CAAC;oBACH,IAAA,wBAAQ,EACN,kBAAkB,OAAO,CAAC,IAAI,uFAAuF,EACrH,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAChE,CAAC;oBACF,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,kCAAkC,SAAS,EAAE,CAAC,CAAC,CAAC;gBACxE,CAAC;gBAAC,OAAO,CAAM,EAAE,CAAC;oBAChB,mDAAmD;oBACnD,IAAI,CAAC;wBACH,MAAM,QAAQ,GAAG,IAAA,wBAAQ,EAAC,uBAAuB,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;wBACxF,IAAA,wBAAQ,EACN,iBAAiB,QAAQ,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,GAAG,EAC1D,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAClC,CAAC;wBACF,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,+BAA+B,SAAS,EAAE,CAAC,CAAC,CAAC;oBACrE,CAAC;oBAAC,MAAM,CAAC;wBACP,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;wBAC3E,OAAO;oBACT,CAAC;gBACH,CAAC;YACH,CAAC;YAED,8BAA8B;YAC9B,MAAM,KAAK,GAAG,IAAA,4BAAoB,GAAE,CAAC;YACrC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,kCAAkC,CAAC,CAAC,CAAC;gBAC9D,OAAO;YACT,CAAC;YAED,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC;YAC5E,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;YAE/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU;oBAAE,SAAS;gBAE9D,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,aAAa,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;gBAExD,mBAAmB;gBACnB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,oBAAoB,CAAC,CAAC;gBACzE,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;gBAC1C,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;gBAC1C,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC,CAAC;gBAE7D,6BAA6B;gBAC7B,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;oBACjD,IAAI,CAAC;wBACH,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;wBAC5D,IAAI,CAAC,QAAQ,CAAC,KAAK;4BAAE,QAAQ,CAAC,KAAK,GAAG,EAAE,CAAC;wBAEzC,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;wBACtD,MAAM,WAAW,GAAG,GAAG,KAAK,GAAG,QAAQ,GAAG,KAAK,IAAI,KAAK,GAAG,SAAS,GAAG,KAAK,EAAE,CAAC;wBAE/E,kDAAkD;wBAClD,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,YAAY;4BAAE,QAAQ,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;wBAChF,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;wBACxD,MAAM,YAAY,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC;wBACzF,IAAI,CAAC,YAAY,EAAE,CAAC;4BAClB,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;4BAC3E,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC,CAAC;wBACjE,CAAC;wBAED,yCAAyC;wBACzC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI;4BAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;wBAChE,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;wBAC/C,MAAM,WAAW,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC;wBACvF,IAAI,CAAC,WAAW,EAAE,CAAC;4BACjB,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;4BACvE,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC,CAAC;wBACzD,CAAC;wBAED,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;oBACvE,CAAC;oBAAC,MAAM,CAAC,CAAA,CAAC;gBACZ,CAAC;YACH,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC,CAAC;YAC5D,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,uDAAuD,CAAC,CAAC,CAAC;YAChF,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC,CAAC;YAC/E,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,8DAA8D,CAAC,CAAC,CAAC;YACvF,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,WAAW,SAAS,EAAE,CAAC,CAAC,CAAC;YAC/C,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC,CAAC;QAEvE,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,cAAc,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;YAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,+DAA+D;IAC/D,IAAI;SACD,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,yBAAyB,CAAC;SACtC,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,QAAQ,GAAG,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,uDAAuD,CAAC,CAAC,CAAC;YACnF,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,WAAW,QAAQ,EAAE,CAAC,CAAC,CAAC;QAE9C,mBAAmB;QACnB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAA,wBAAQ,EAAC,sBAAsB,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;YACjG,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC;YAC5C,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACnC,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC,CAAC;QACvD,CAAC;QAED,cAAc;QACd,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAChD,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CACxC,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,qBAAqB,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC5D,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;YAClE,MAAM,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC;YACzE,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,MAAM,GAAG,CAAC,CAAC,CAAC;QACjD,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACP,CAAC"}
|