tylor-mcp 1.0.0 β 1.1.1
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/.npmrc.publish +1 -0
- package/README.md +165 -146
- package/bin/tylor.js +36 -2
- package/package.json +5 -2
- package/pytest.ini +2 -2
- package/scripts/dev-sync.js +113 -0
- package/server/config.py +8 -13
- package/server/storage/dynamo.py +33 -0
- package/server/storage/json_store.py +49 -2
- package/server/tools/agents.py +296 -11
- package/server/tools/executor.py +83 -12
- package/server/tools/harness.py +238 -31
- package/server/tools/help.py +21 -1
- package/server/tools/hooks.py +19 -6
- package/server/tools/registry.py +50 -3
- package/server/tools/security.py +303 -0
- package/server/tools/skill_installer.py +34 -1
- package/server/tools/summarizer.py +3 -1
- package/server/tools/tylor.py +11 -10
- package/server/ui_server.py +160 -11
- package/server/validate.py +29 -15
- package/skills/ecc-data/SKILL.md +32 -0
- package/skills/ecc-diagrams/SKILL.md +31 -0
- package/skills/ecc-pipeline/SKILL.md +31 -0
- package/skills/ecc-presentation/SKILL.md +31 -0
- package/skills/ecc-web/SKILL.md +31 -0
- package/skills/help-agent101/SKILL.md +1 -0
- package/skills/open-threads-ui/SKILL.md +33 -0
- package/skills/tylor-run/SKILL.md +61 -0
- package/ui/index.html +760 -889
- package/server/storage/tests/__init__.py +0 -0
- package/server/storage/tests/test_dynamo.py +0 -452
- package/server/storage/tests/test_json_store.py +0 -226
- package/server/storage/tests/test_opensearch.py +0 -270
- package/server/storage/tests/test_s3.py +0 -125
- package/server/tests/__init__.py +0 -0
- package/server/tests/test_install.py +0 -606
- package/server/tests/test_isolation.py +0 -90
- package/server/tests/test_ui_server.py +0 -385
- package/server/tests/test_ui_shader_background.py +0 -52
- package/server/tests/test_ui_story_6_3.py +0 -105
- package/server/tools/tests/__init__.py +0 -0
- package/server/tools/tests/test_agents.py +0 -246
- package/server/tools/tests/test_code_index.py +0 -108
- package/server/tools/tests/test_ecc_tools.py +0 -51
- package/server/tools/tests/test_executor.py +0 -584
- package/server/tools/tests/test_help_agent101.py +0 -149
- package/server/tools/tests/test_hooks.py +0 -124
- package/server/tools/tests/test_kill_thread.py +0 -125
- package/server/tools/tests/test_new_thread_list_threads.py +0 -293
- package/server/tools/tests/test_personas.py +0 -52
- package/server/tools/tests/test_recall_memory.py +0 -55
- package/server/tools/tests/test_registry_client.py +0 -308
- package/server/tools/tests/test_router.py +0 -263
- package/server/tools/tests/test_skill_installer.py +0 -174
- package/server/tools/tests/test_switch_thread.py +0 -163
- package/server/tools/tests/test_thread_command_skills.py +0 -54
- package/server/tools/tests/test_thread_resolver.py +0 -165
- package/server/tools/tests/test_tier1_schema.py +0 -296
package/.npmrc.publish
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}
|
package/README.md
CHANGED
|
@@ -1,146 +1,165 @@
|
|
|
1
|
-
<div align="center">
|
|
2
|
-
<img src="assets/tylor_logo.png" alt="Tylor Logo" width="150">
|
|
3
|
-
<h1>Tylor</h1>
|
|
4
|
-
<p><strong>The Tailor to Your Threads</strong></p>
|
|
5
|
-
<p><em>Give Claude Code persistent memory, laser-focused context, and an autonomous team of specialists.</em></p>
|
|
6
|
-
|
|
7
|
-
[](https://opensource.org/licenses/MIT)
|
|
8
|
-
[](#)
|
|
9
|
-
[](#)
|
|
10
|
-
[](#)
|
|
11
|
-
[](#)
|
|
12
|
-
</div>
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
Tylor transforms your Claude Code experience from a single-shot terminal interaction into a **persistent, intelligent workspace**.
|
|
17
|
-
|
|
18
|
-
Every time you open Claude Code, you normally start from zero. Tylor fixes that. It organizes your work into **threads**βisolated, named workspaces that survive restarts and reboots. It remembers every decision, every line of code, and every discussion, so you never have to repeat yourself.
|
|
19
|
-
|
|
20
|
-
**No database. No cloud account. No configuration. Just install and go.**
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## π¨ How It Works
|
|
25
|
-
|
|
26
|
-
<div align="center">
|
|
27
|
-
<img src="assets/tylor_threads_concept.png" alt="Tylor Threads Architecture" width="800">
|
|
28
|
-
<p><em>Tylor weaves parallel, persistent memory threads and orchestrates specialist sub-agents.</em></p>
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## β¨ Features
|
|
34
|
-
|
|
35
|
-
### π§ Persistent Memory
|
|
36
|
-
Tylor completely eliminates the "context reset." Shut down your computer, close your terminal, and come back a week laterβClaude will pick up exactly where you left off.
|
|
37
|
-
|
|
38
|
-
### ποΈ Context Isolation (Threads)
|
|
39
|
-
Work in parallel without context bleed. Discuss frontend components in a `Frontend` thread and database schemas in a `Backend` thread. By isolating context, token usage stays low, and Claude's focus stays incredibly sharp.
|
|
40
|
-
|
|
41
|
-
### π€ Intelligent Orchestration
|
|
42
|
-
You don't need to micromanage. Claude acts as the orchestrator. If you ask it to review architecture, it will dynamically load its `cto` persona. If you ask it to write a PRD, it natively invokes the `bmad` skill framework to get the job done.
|
|
43
|
-
|
|
44
|
-
### π Infinite Extensibility (Lazy-Loading)
|
|
45
|
-
Tylor is built on a production-hardened ADK-pattern harness. You can register hundreds of domain-specific ECC skills (like `ecc/web`, `ecc/data`) via the `/add-skill` command. Tylor **lazy-loads** only the tools required for the current prompt, giving you massive capability scaling without ever blowing up Claude's token context window.
|
|
46
|
-
|
|
47
|
-
### ποΈ Autonomous AFK Sandboxing
|
|
48
|
-
Declare a sandbox for your thread and let Claude work autonomously. Assign large, complex tasks and let Claude execute them while you step away from the keyboard.
|
|
49
|
-
|
|
50
|
-
### π Visual Dashboard
|
|
51
|
-
Monitor your entire workspace through a beautiful, locally hosted web UI. Track active threads, review past conversations, and watch autonomous agent progress in real-time.
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
## π Installation
|
|
56
|
-
|
|
57
|
-
Tylor installs seamlessly into your Claude Code, Claude Desktop, GitHub Copilot, Antigravity, or VSCode Claude extension environment. Requires Python 3.8+.
|
|
58
|
-
|
|
59
|
-
### β‘ Option 1: The One-Line Installer (Recommended)
|
|
60
|
-
|
|
61
|
-
If you have Node.js installed, you can configure Tylor instantly across all your clients without manually cloning the repository. Simply run:
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
npx tylor-mcp
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### π» Option 2: Manual Git Clone
|
|
68
|
-
|
|
69
|
-
**macOS / Linux / WSL:**
|
|
70
|
-
```bash
|
|
71
|
-
git clone https://github.com/GunjanGrunge/tylor ~/.claude/plugins/GunjanGrunge/tylor
|
|
72
|
-
python3 ~/.claude/plugins/GunjanGrunge/tylor/install.py
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
**Windows:**
|
|
76
|
-
```powershell
|
|
77
|
-
git clone https://github.com/GunjanGrunge/tylor %USERPROFILE%\.claude\plugins\GunjanGrunge\tylor
|
|
78
|
-
python %USERPROFILE%\.claude\plugins\GunjanGrunge\tylor\install.py
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### Step 3: Verify
|
|
82
|
-
|
|
83
|
-
1. Restart your Claude, GitHub Copilot, or Antigravity client completely (close the terminal/app and reopen it).
|
|
84
|
-
2. Type `/help-agent101` in your prompt (or use Copilot Chat / `/mcp show`).
|
|
85
|
-
3. If you see the capability index, Tylor is fully operational!
|
|
86
|
-
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
## πΉοΈ Quick Start
|
|
90
|
-
|
|
91
|
-
Creating your first persistent workflow is incredibly simple:
|
|
92
|
-
|
|
93
|
-
```text
|
|
94
|
-
/new-thread Authentication β Create a persistent workspace
|
|
95
|
-
/run we need to implement JWT based authentication
|
|
96
|
-
|
|
97
|
-
/new-thread Dashboard UI β Create an isolated UI thread
|
|
98
|
-
/run build a react dashboard with a sidebar
|
|
99
|
-
|
|
100
|
-
/switch-thread Authentication β Instantly switch context back to Auth
|
|
101
|
-
/run add refresh token logic
|
|
102
|
-
|
|
103
|
-
/list-threads β View your workspace status
|
|
104
|
-
/open-threads-ui β Launch the visual dashboard
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
---
|
|
108
|
-
|
|
109
|
-
## π οΈ Command Reference
|
|
110
|
-
|
|
111
|
-
Tylor exposes a suite of powerful commands directly within Claude:
|
|
112
|
-
|
|
113
|
-
| Command | Description |
|
|
114
|
-
|---|---|
|
|
115
|
-
| `/new-thread <name>` | Create a named thread and seamlessly switch future work into it. |
|
|
116
|
-
| `/switch-thread <name>` | Switch context to an existing thread (fuzzy matching supported). |
|
|
117
|
-
| `/list-threads` | Show all available threads alongside their status and activity. |
|
|
118
|
-
| `/kill-thread <name>` | Close a thread and dispatch asynchronous summarization. |
|
|
119
|
-
| `/recall` | Search through the deep semantic memory of your active thread. |
|
|
120
|
-
| `/add-skill` | Install a new skill package dynamically. |
|
|
121
|
-
| `/open-threads-ui` | Open the live, local thread visualizer UI in your browser. |
|
|
122
|
-
| `/set-sandbox <path>` | Declare specific filesystem roots for secure, autonomous execution. |
|
|
123
|
-
| `/afk-status` | Get real-time progress reports on current autonomous background tasks. |
|
|
124
|
-
|
|
125
|
-
> **Pro Tip:** You can also use shorthand aliases like `CT <name>` to create a thread or `SwThread <name>` to switch.
|
|
126
|
-
|
|
127
|
-
---
|
|
128
|
-
|
|
129
|
-
##
|
|
130
|
-
|
|
131
|
-
Tylor
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="assets/tylor_logo.png" alt="Tylor Logo" width="150">
|
|
3
|
+
<h1>Tylor</h1>
|
|
4
|
+
<p><strong>The Tailor to Your Threads</strong></p>
|
|
5
|
+
<p><em>Give Claude Code persistent memory, laser-focused context, and an autonomous team of specialists.</em></p>
|
|
6
|
+
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
[](#)
|
|
9
|
+
[](#)
|
|
10
|
+
[](#)
|
|
11
|
+
[](#)
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
Tylor transforms your Claude Code experience from a single-shot terminal interaction into a **persistent, intelligent workspace**.
|
|
17
|
+
|
|
18
|
+
Every time you open Claude Code, you normally start from zero. Tylor fixes that. It organizes your work into **threads**βisolated, named workspaces that survive restarts and reboots. It remembers every decision, every line of code, and every discussion, so you never have to repeat yourself.
|
|
19
|
+
|
|
20
|
+
**No database. No cloud account. No configuration. Just install and go.**
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## π¨ How It Works
|
|
25
|
+
|
|
26
|
+
<div align="center">
|
|
27
|
+
<img src="assets/tylor_threads_concept.png" alt="Tylor Threads Architecture" width="800">
|
|
28
|
+
<p><em>Tylor weaves parallel, persistent memory threads and orchestrates specialist sub-agents.</em></p>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## β¨ Features
|
|
34
|
+
|
|
35
|
+
### π§ Persistent Memory
|
|
36
|
+
Tylor completely eliminates the "context reset." Shut down your computer, close your terminal, and come back a week laterβClaude will pick up exactly where you left off.
|
|
37
|
+
|
|
38
|
+
### ποΈ Context Isolation (Threads)
|
|
39
|
+
Work in parallel without context bleed. Discuss frontend components in a `Frontend` thread and database schemas in a `Backend` thread. By isolating context, token usage stays low, and Claude's focus stays incredibly sharp.
|
|
40
|
+
|
|
41
|
+
### π€ Intelligent Orchestration
|
|
42
|
+
You don't need to micromanage. Claude acts as the orchestrator. If you ask it to review architecture, it will dynamically load its `cto` persona. If you ask it to write a PRD, it natively invokes the `bmad` skill framework to get the job done.
|
|
43
|
+
|
|
44
|
+
### π Infinite Extensibility (Lazy-Loading)
|
|
45
|
+
Tylor is built on a production-hardened ADK-pattern harness. You can register hundreds of domain-specific ECC skills (like `ecc/web`, `ecc/data`) via the `/add-skill` command. Tylor **lazy-loads** only the tools required for the current prompt, giving you massive capability scaling without ever blowing up Claude's token context window.
|
|
46
|
+
|
|
47
|
+
### ποΈ Autonomous AFK Sandboxing
|
|
48
|
+
Declare a sandbox for your thread and let Claude work autonomously. Assign large, complex tasks and let Claude execute them while you step away from the keyboard.
|
|
49
|
+
|
|
50
|
+
### π Visual Dashboard
|
|
51
|
+
Monitor your entire workspace through a beautiful, locally hosted web UI. Track active threads, review past conversations, and watch autonomous agent progress in real-time.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## π Installation
|
|
56
|
+
|
|
57
|
+
Tylor installs seamlessly into your Claude Code, Claude Desktop, GitHub Copilot, Antigravity, or VSCode Claude extension environment. Requires Python 3.8+.
|
|
58
|
+
|
|
59
|
+
### β‘ Option 1: The One-Line Installer (Recommended)
|
|
60
|
+
|
|
61
|
+
If you have Node.js installed, you can configure Tylor instantly across all your clients without manually cloning the repository. Simply run:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npx tylor-mcp
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### π» Option 2: Manual Git Clone
|
|
68
|
+
|
|
69
|
+
**macOS / Linux / WSL:**
|
|
70
|
+
```bash
|
|
71
|
+
git clone https://github.com/GunjanGrunge/tylor ~/.claude/plugins/GunjanGrunge/tylor
|
|
72
|
+
python3 ~/.claude/plugins/GunjanGrunge/tylor/install.py
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Windows:**
|
|
76
|
+
```powershell
|
|
77
|
+
git clone https://github.com/GunjanGrunge/tylor %USERPROFILE%\.claude\plugins\GunjanGrunge\tylor
|
|
78
|
+
python %USERPROFILE%\.claude\plugins\GunjanGrunge\tylor\install.py
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Step 3: Verify
|
|
82
|
+
|
|
83
|
+
1. Restart your Claude, GitHub Copilot, or Antigravity client completely (close the terminal/app and reopen it).
|
|
84
|
+
2. Type `/help-agent101` in your prompt (or use Copilot Chat / `/mcp show`).
|
|
85
|
+
3. If you see the capability index, Tylor is fully operational!
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## πΉοΈ Quick Start
|
|
90
|
+
|
|
91
|
+
Creating your first persistent workflow is incredibly simple:
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
/new-thread Authentication β Create a persistent workspace
|
|
95
|
+
/run we need to implement JWT based authentication
|
|
96
|
+
|
|
97
|
+
/new-thread Dashboard UI β Create an isolated UI thread
|
|
98
|
+
/run build a react dashboard with a sidebar
|
|
99
|
+
|
|
100
|
+
/switch-thread Authentication β Instantly switch context back to Auth
|
|
101
|
+
/run add refresh token logic
|
|
102
|
+
|
|
103
|
+
/list-threads β View your workspace status
|
|
104
|
+
/open-threads-ui β Launch the visual dashboard
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## π οΈ Command Reference
|
|
110
|
+
|
|
111
|
+
Tylor exposes a suite of powerful commands directly within Claude:
|
|
112
|
+
|
|
113
|
+
| Command | Description |
|
|
114
|
+
|---|---|
|
|
115
|
+
| `/new-thread <name>` | Create a named thread and seamlessly switch future work into it. |
|
|
116
|
+
| `/switch-thread <name>` | Switch context to an existing thread (fuzzy matching supported). |
|
|
117
|
+
| `/list-threads` | Show all available threads alongside their status and activity. |
|
|
118
|
+
| `/kill-thread <name>` | Close a thread and dispatch asynchronous summarization. |
|
|
119
|
+
| `/recall` | Search through the deep semantic memory of your active thread. |
|
|
120
|
+
| `/add-skill` | Install a new skill package dynamically. |
|
|
121
|
+
| `/open-threads-ui` | Open the live, local thread visualizer UI in your browser. |
|
|
122
|
+
| `/set-sandbox <path>` | Declare specific filesystem roots for secure, autonomous execution. |
|
|
123
|
+
| `/afk-status` | Get real-time progress reports on current autonomous background tasks. |
|
|
124
|
+
|
|
125
|
+
> **Pro Tip:** You can also use shorthand aliases like `CT <name>` to create a thread or `SwThread <name>` to switch.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## π Bumblebee Security Gate
|
|
130
|
+
|
|
131
|
+
Tylor now includes a default, plugin-wide security gate powered by Bumblebee. When a risky command is detectedβespecially package installs, extension installs, skill/package additions, or MCP config changesβTylor will initiate a read-only Bumblebee scan before the command runs.
|
|
132
|
+
|
|
133
|
+
- Enabled by default for any command pattern that looks like `pip install`, `npm install`, editor/extension installs, or skill/config setup.
|
|
134
|
+
- If Bumblebee is missing, Tylor will flag the command and surface clear guidance instead of executing it blindly.
|
|
135
|
+
- If Bumblebee detects risk, execution is blocked and the user sees actionable alternatives.
|
|
136
|
+
|
|
137
|
+
Suggested responses from the gate include:
|
|
138
|
+
|
|
139
|
+
- Install Bumblebee or set `BUMBLEBEE_PATH` if the CLI is not found.
|
|
140
|
+
- Run `bumblebee scan --json` manually before retrying.
|
|
141
|
+
- Disable the gate temporarily with `BUMBLEBEE_ENABLED=false` only if you understand the risk.
|
|
142
|
+
- Review package metadata, MCP config changes, and AI tool integrations before proceeding.
|
|
143
|
+
|
|
144
|
+
This layer applies across the plugin, regardless of which thread or persona is active.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## π Sub-Agents & Personas
|
|
149
|
+
|
|
150
|
+
Tylor comes pre-equipped with specialist sub-agents. Claude will **automatically invoke** these personas based on the nature of your queryβno manual intervention required.
|
|
151
|
+
|
|
152
|
+
* **`cto`**: System architecture, tradeoffs, platform strategy, and engineering standards.
|
|
153
|
+
* **`code_agent`**: Senior software engineer laser-focused on shipping robust code and tests.
|
|
154
|
+
* **`analyst`**: Market research, data synthesis, and technical decision support.
|
|
155
|
+
* **`ceo`**: Product strategy, roadmap prioritization, and stakeholder framing.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## π License
|
|
160
|
+
|
|
161
|
+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
|
162
|
+
|
|
163
|
+
<div align="center">
|
|
164
|
+
<p><em>Tylor β Tailoring the future of AI development.</em></p>
|
|
165
|
+
</div>
|
package/bin/tylor.js
CHANGED
|
@@ -1,7 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const { spawnSync } = require('child_process');
|
|
2
|
+
const { spawnSync, execSync } = require('child_process');
|
|
3
3
|
const path = require('path');
|
|
4
|
+
const https = require('https');
|
|
5
|
+
const fs = require('fs');
|
|
4
6
|
|
|
7
|
+
// ββ Update check ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
8
|
+
function checkForUpdate() {
|
|
9
|
+
try {
|
|
10
|
+
const pkgPath = path.join(__dirname, '..', 'package.json');
|
|
11
|
+
const localPkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
12
|
+
const localVersion = localPkg.version;
|
|
13
|
+
const pkgName = localPkg.name;
|
|
14
|
+
|
|
15
|
+
const url = `https://registry.npmjs.org/${pkgName}/latest`;
|
|
16
|
+
const req = https.get(url, { timeout: 3000 }, (res) => {
|
|
17
|
+
let data = '';
|
|
18
|
+
res.on('data', chunk => data += chunk);
|
|
19
|
+
res.on('end', () => {
|
|
20
|
+
try {
|
|
21
|
+
const latest = JSON.parse(data).version;
|
|
22
|
+
if (latest && latest !== localVersion) {
|
|
23
|
+
console.log('');
|
|
24
|
+
console.log(` β οΈ Update available: ${localVersion} β ${latest}`);
|
|
25
|
+
console.log(` Run: npm update -g ${pkgName} (or npx ${pkgName}@latest)`);
|
|
26
|
+
console.log('');
|
|
27
|
+
}
|
|
28
|
+
} catch (_) { /* silent */ }
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
req.on('error', () => { /* silent β offline or registry down */ });
|
|
32
|
+
req.on('timeout', () => { req.destroy(); });
|
|
33
|
+
} catch (_) { /* silent */ }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
checkForUpdate();
|
|
37
|
+
|
|
38
|
+
// ββ Installer βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
5
39
|
const installPy = path.join(__dirname, '..', 'install.py');
|
|
6
40
|
const args = process.argv.slice(2);
|
|
7
41
|
|
|
@@ -13,7 +47,7 @@ let result = spawnSync('python', [installPy, ...args], { stdio: 'inherit' });
|
|
|
13
47
|
// Fallback to `python3` if `python` fails (standard on macOS/Linux)
|
|
14
48
|
if (result.error || result.status !== 0) {
|
|
15
49
|
result = spawnSync('python3', [installPy, ...args], { stdio: 'inherit' });
|
|
16
|
-
|
|
50
|
+
|
|
17
51
|
if (result.error) {
|
|
18
52
|
console.error("β Failed to launch the Tylor installer. Please ensure Python 3.8+ is installed on your system.");
|
|
19
53
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tylor-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Give Claude Code persistent memory, laser-focused context, and an autonomous team of specialists.",
|
|
5
5
|
"main": "server/main.py",
|
|
6
6
|
"bin": {
|
|
@@ -20,5 +20,8 @@
|
|
|
20
20
|
"github-copilot"
|
|
21
21
|
],
|
|
22
22
|
"author": "Gunjan Grunge",
|
|
23
|
-
"license": "MIT"
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"scripts": {
|
|
25
|
+
"dev:sync": "node scripts/dev-sync.js"
|
|
26
|
+
}
|
|
24
27
|
}
|
package/pytest.ini
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
[pytest]
|
|
2
|
-
asyncio_mode = auto
|
|
1
|
+
[pytest]
|
|
2
|
+
asyncio_mode = auto
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* dev-sync.js β sync dev changes to the live installed server.
|
|
4
|
+
*
|
|
5
|
+
* Reads PYTHONPATH from ~/.claude/settings.json (written there by install.py),
|
|
6
|
+
* so it always targets the correct installed location regardless of npm version
|
|
7
|
+
* or _npx cache hash. No hardcoding.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* npm run dev:sync
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const os = require('os');
|
|
16
|
+
|
|
17
|
+
// ββ Find the installed server path from settings.json ββββββββββββββββββββββββ
|
|
18
|
+
|
|
19
|
+
function findInstalledPath() {
|
|
20
|
+
const candidates = [
|
|
21
|
+
path.join(os.homedir(), '.claude', 'settings.json'),
|
|
22
|
+
path.join(os.homedir(), 'AppData', 'Roaming', 'Claude', 'settings.json'),
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
for (const candidate of candidates) {
|
|
26
|
+
if (!fs.existsSync(candidate)) continue;
|
|
27
|
+
try {
|
|
28
|
+
const settings = JSON.parse(fs.readFileSync(candidate, 'utf8'));
|
|
29
|
+
const pythonpath =
|
|
30
|
+
settings?.mcpServers?.agent101?.env?.PYTHONPATH;
|
|
31
|
+
if (pythonpath && fs.existsSync(pythonpath)) {
|
|
32
|
+
return pythonpath;
|
|
33
|
+
}
|
|
34
|
+
} catch (_) { /* malformed β skip */ }
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ββ Files and directories to sync ββββββββββββββββββββββββββββββββββββββββββββ
|
|
40
|
+
|
|
41
|
+
const DEV_ROOT = path.join(__dirname, '..');
|
|
42
|
+
|
|
43
|
+
const SYNC_FILES = [
|
|
44
|
+
'server/tools/harness.py',
|
|
45
|
+
'server/tools/security.py',
|
|
46
|
+
'server/tools/executor.py',
|
|
47
|
+
'server/tools/registry.py',
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
const SYNC_DIRS = [
|
|
51
|
+
'skills',
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
// ββ Helpers βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
55
|
+
|
|
56
|
+
function copyFile(src, dst) {
|
|
57
|
+
fs.mkdirSync(path.dirname(dst), { recursive: true });
|
|
58
|
+
fs.copyFileSync(src, dst);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function syncDir(srcDir, dstDir) {
|
|
62
|
+
if (!fs.existsSync(srcDir)) return 0;
|
|
63
|
+
let count = 0;
|
|
64
|
+
for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
|
|
65
|
+
const srcPath = path.join(srcDir, entry.name);
|
|
66
|
+
const dstPath = path.join(dstDir, entry.name);
|
|
67
|
+
if (entry.isDirectory()) {
|
|
68
|
+
count += syncDir(srcPath, dstPath);
|
|
69
|
+
} else {
|
|
70
|
+
copyFile(srcPath, dstPath);
|
|
71
|
+
count++;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return count;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ββ Main ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
78
|
+
|
|
79
|
+
const installed = findInstalledPath();
|
|
80
|
+
|
|
81
|
+
if (!installed) {
|
|
82
|
+
console.error('β Could not find installed server path in ~/.claude/settings.json');
|
|
83
|
+
console.error(' Run: npx tylor-mcp to install first.');
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log(`π― Target: ${installed}\n`);
|
|
88
|
+
|
|
89
|
+
let total = 0;
|
|
90
|
+
|
|
91
|
+
for (const rel of SYNC_FILES) {
|
|
92
|
+
const src = path.join(DEV_ROOT, rel);
|
|
93
|
+
const dst = path.join(installed, rel);
|
|
94
|
+
if (!fs.existsSync(src)) {
|
|
95
|
+
console.warn(`β οΈ skip (not found): ${rel}`);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
copyFile(src, dst);
|
|
99
|
+
console.log(` β ${rel}`);
|
|
100
|
+
total++;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
for (const rel of SYNC_DIRS) {
|
|
104
|
+
const src = path.join(DEV_ROOT, rel);
|
|
105
|
+
const dst = path.join(installed, rel);
|
|
106
|
+
const n = syncDir(src, dst);
|
|
107
|
+
if (n > 0) {
|
|
108
|
+
console.log(` β ${rel}/ (${n} files)`);
|
|
109
|
+
total += n;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
console.log(`\nβ
${total} file(s) synced. Restart Claude Code to pick up changes.`);
|
package/server/config.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""
|
|
2
2
|
server/config.py β Agent101 server configuration.
|
|
3
|
-
Reads
|
|
3
|
+
Reads local storage settings and optional cloud provider settings.
|
|
4
4
|
Resolution order: env var β ~/.agent101/config.json β .env file β defaults.
|
|
5
|
-
|
|
5
|
+
Missing cloud settings are normal in local-first mode; startup never crashes.
|
|
6
6
|
"""
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
import json
|
|
@@ -57,6 +57,7 @@ def _load() -> dict:
|
|
|
57
57
|
cfg = {
|
|
58
58
|
"aws_profile": _get("AWS_PROFILE"),
|
|
59
59
|
"aws_access_key_id": _get("AWS_ACCESS_KEY_ID"),
|
|
60
|
+
"storage_mode": _get("AGENT101_STORAGE_MODE", default="local"),
|
|
60
61
|
"bedrock_region": _get("BEDROCK_REGION", default="us-east-1"),
|
|
61
62
|
"bedrock_opus_model": _get(
|
|
62
63
|
"BEDROCK_OPUS_MODEL",
|
|
@@ -69,19 +70,13 @@ def _load() -> dict:
|
|
|
69
70
|
"s3_bucket": _get("S3_BUCKET"),
|
|
70
71
|
"opensearch_host": _get("OPENSEARCH_HOST"),
|
|
71
72
|
"opensearch_port": _get("OPENSEARCH_PORT", default="9200"),
|
|
73
|
+
"bumblebee_enabled": str(_get("BUMBLEBEE_ENABLED", default="true")).strip().lower() in {"1", "true", "yes", "on"},
|
|
74
|
+
"bumblebee_path": _get("BUMBLEBEE_PATH"),
|
|
72
75
|
}
|
|
73
76
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
"ANTHROPIC_PLATFORM_AWS_API_KEY/ANTHROPIC_AWS_API_KEY not set β "
|
|
78
|
-
"token overflow fallback to Claude Platform on AWS is disabled"
|
|
79
|
-
)
|
|
80
|
-
if not cfg["opensearch_host"]:
|
|
81
|
-
logger.warning(
|
|
82
|
-
"OPENSEARCH_HOST not set β "
|
|
83
|
-
"semantic memory recall (recall_memory) will be unavailable until configured"
|
|
84
|
-
)
|
|
77
|
+
if cfg["storage_mode"] not in {"local", "aws"}:
|
|
78
|
+
logger.warning("Unknown AGENT101_STORAGE_MODE=%s; falling back to local mode", cfg["storage_mode"])
|
|
79
|
+
cfg["storage_mode"] = "local"
|
|
85
80
|
|
|
86
81
|
return cfg
|
|
87
82
|
|
package/server/storage/dynamo.py
CHANGED
|
@@ -187,6 +187,29 @@ class DynamoClient:
|
|
|
187
187
|
attributes["Task"] = task
|
|
188
188
|
return self.put_item(sk=sk, attributes=attributes)
|
|
189
189
|
|
|
190
|
+
def put_agent_event(
|
|
191
|
+
self,
|
|
192
|
+
thread_id: str,
|
|
193
|
+
agent_id: str,
|
|
194
|
+
event_type: str,
|
|
195
|
+
content: str,
|
|
196
|
+
persona: str | None = None,
|
|
197
|
+
) -> dict:
|
|
198
|
+
"""Persist a streamed sub-agent event for live UI replay."""
|
|
199
|
+
self._validate_agent_id(agent_id)
|
|
200
|
+
sk = f"THREAD#{thread_id}#AGENT#{agent_id}#EVENT#{_unique_event_suffix()}"
|
|
201
|
+
self._assert_thread_isolation(thread_id, sk)
|
|
202
|
+
attributes = {
|
|
203
|
+
"ThreadId": thread_id,
|
|
204
|
+
"AgentId": agent_id,
|
|
205
|
+
"Type": "agent_event",
|
|
206
|
+
"EventType": event_type,
|
|
207
|
+
"Content": content,
|
|
208
|
+
}
|
|
209
|
+
if persona:
|
|
210
|
+
attributes["Persona"] = persona
|
|
211
|
+
return self.put_item(sk=sk, attributes=attributes)
|
|
212
|
+
|
|
190
213
|
def put_agent_handoff(
|
|
191
214
|
self,
|
|
192
215
|
thread_id: str,
|
|
@@ -230,6 +253,16 @@ class DynamoClient:
|
|
|
230
253
|
items = self.query_thread(thread_id, f"THREAD#{thread_id}#AGENT#")
|
|
231
254
|
return [item for item in items if item.get("SK", "").endswith("#STATE")]
|
|
232
255
|
|
|
256
|
+
def query_agent_events(self, thread_id: str, agent_id: str | None = None) -> list:
|
|
257
|
+
"""Return streamed sub-agent events for one thread, optionally one agent."""
|
|
258
|
+
prefix = f"THREAD#{thread_id}#AGENT#"
|
|
259
|
+
if agent_id:
|
|
260
|
+
self._validate_agent_id(agent_id)
|
|
261
|
+
prefix = f"{prefix}{agent_id}#EVENT#"
|
|
262
|
+
items = self.query_thread(thread_id, prefix)
|
|
263
|
+
events = [item for item in items if "#EVENT#" in item.get("SK", "")]
|
|
264
|
+
return sorted(events, key=lambda item: item.get("SK", ""))
|
|
265
|
+
|
|
233
266
|
def get_thread_meta(self, thread_id: str) -> dict | None:
|
|
234
267
|
"""Return thread META item for the given thread_id."""
|
|
235
268
|
return self.get_item(thread_id, f"THREAD#{thread_id}#META")
|