intent-hub 0.1.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/.claude/settings.local.json +7 -0
- package/.turbo/cache/019f5ae385027cb1-meta.json +1 -0
- package/.turbo/cache/019f5ae385027cb1.tar.zst +0 -0
- package/.turbo/cache/040af6112a552a64-meta.json +1 -0
- package/.turbo/cache/040af6112a552a64.tar.zst +0 -0
- package/.turbo/cache/11195eac3ca5c6ce-meta.json +1 -0
- package/.turbo/cache/11195eac3ca5c6ce.tar.zst +0 -0
- package/.turbo/cache/13d11166efdf11cf-meta.json +1 -0
- package/.turbo/cache/13d11166efdf11cf.tar.zst +0 -0
- package/.turbo/cache/19af1af3b136706c-meta.json +1 -0
- package/.turbo/cache/19af1af3b136706c.tar.zst +0 -0
- package/.turbo/cache/1d33efac91c05b50-meta.json +1 -0
- package/.turbo/cache/1d33efac91c05b50.tar.zst +0 -0
- package/.turbo/cache/200b85a612af2d13-meta.json +1 -0
- package/.turbo/cache/200b85a612af2d13.tar.zst +0 -0
- package/.turbo/cache/210308c9ea929858-meta.json +1 -0
- package/.turbo/cache/210308c9ea929858.tar.zst +0 -0
- package/.turbo/cache/38df8e44c617835e-meta.json +1 -0
- package/.turbo/cache/38df8e44c617835e.tar.zst +0 -0
- package/.turbo/cache/3e449de5ef60a7a0-meta.json +1 -0
- package/.turbo/cache/3e449de5ef60a7a0.tar.zst +0 -0
- package/.turbo/cache/51ff024a97c2b4f5-meta.json +1 -0
- package/.turbo/cache/51ff024a97c2b4f5.tar.zst +0 -0
- package/.turbo/cache/54bc756eeebb377a-meta.json +1 -0
- package/.turbo/cache/54bc756eeebb377a.tar.zst +0 -0
- package/.turbo/cache/5ed6a840acafc873-meta.json +1 -0
- package/.turbo/cache/5ed6a840acafc873.tar.zst +0 -0
- package/.turbo/cache/6702dc24e5ca3c2e-meta.json +1 -0
- package/.turbo/cache/6702dc24e5ca3c2e.tar.zst +0 -0
- package/.turbo/cache/725c72cf71ea854f-meta.json +1 -0
- package/.turbo/cache/725c72cf71ea854f.tar.zst +0 -0
- package/.turbo/cache/7344ca28d348037a-meta.json +1 -0
- package/.turbo/cache/7344ca28d348037a.tar.zst +0 -0
- package/.turbo/cache/748fb444cdc0b78c-meta.json +1 -0
- package/.turbo/cache/748fb444cdc0b78c.tar.zst +0 -0
- package/.turbo/cache/789677c36fe7fb98-meta.json +1 -0
- package/.turbo/cache/789677c36fe7fb98.tar.zst +0 -0
- package/.turbo/cache/89ff6c6f38dd4a18-meta.json +1 -0
- package/.turbo/cache/89ff6c6f38dd4a18.tar.zst +0 -0
- package/.turbo/cache/8dbc92d00de0c92e-meta.json +1 -0
- package/.turbo/cache/8dbc92d00de0c92e.tar.zst +0 -0
- package/.turbo/cache/8eb03f40082b9441-meta.json +1 -0
- package/.turbo/cache/8eb03f40082b9441.tar.zst +0 -0
- package/.turbo/cache/9157134d4b916017-meta.json +1 -0
- package/.turbo/cache/9157134d4b916017.tar.zst +0 -0
- package/.turbo/cache/94219ffd32b48e93-meta.json +1 -0
- package/.turbo/cache/94219ffd32b48e93.tar.zst +0 -0
- package/.turbo/cache/95c1d160b4fa84eb-meta.json +1 -0
- package/.turbo/cache/95c1d160b4fa84eb.tar.zst +0 -0
- package/.turbo/cache/998833ea02dfb225-meta.json +1 -0
- package/.turbo/cache/998833ea02dfb225.tar.zst +0 -0
- package/.turbo/cache/a5974ef6ade3eb90-meta.json +1 -0
- package/.turbo/cache/a5974ef6ade3eb90.tar.zst +0 -0
- package/.turbo/cache/aab811809257decb-meta.json +1 -0
- package/.turbo/cache/aab811809257decb.tar.zst +0 -0
- package/.turbo/cache/ab2f82a54da854fd-meta.json +1 -0
- package/.turbo/cache/ab2f82a54da854fd.tar.zst +0 -0
- package/.turbo/cache/abbf4d95d62a7303-meta.json +1 -0
- package/.turbo/cache/abbf4d95d62a7303.tar.zst +0 -0
- package/.turbo/cache/af4441f519f9ce50-meta.json +1 -0
- package/.turbo/cache/af4441f519f9ce50.tar.zst +0 -0
- package/.turbo/cache/b9b85aaaf03d00a6-meta.json +1 -0
- package/.turbo/cache/b9b85aaaf03d00a6.tar.zst +0 -0
- package/.turbo/cache/cd58ee8721bbfed7-meta.json +1 -0
- package/.turbo/cache/cd58ee8721bbfed7.tar.zst +0 -0
- package/.turbo/cache/d285e48b8afa30b5-meta.json +1 -0
- package/.turbo/cache/d285e48b8afa30b5.tar.zst +0 -0
- package/.turbo/cache/d33e90229142acce-meta.json +1 -0
- package/.turbo/cache/d33e90229142acce.tar.zst +0 -0
- package/.turbo/cache/d57839a0d3b04540-meta.json +1 -0
- package/.turbo/cache/d57839a0d3b04540.tar.zst +0 -0
- package/.turbo/cache/d8554ef2c8b6e5eb-meta.json +1 -0
- package/.turbo/cache/d8554ef2c8b6e5eb.tar.zst +0 -0
- package/.turbo/cache/dc7375b51290e102-meta.json +1 -0
- package/.turbo/cache/dc7375b51290e102.tar.zst +0 -0
- package/.turbo/cache/e5310fe547fdbf0a-meta.json +1 -0
- package/.turbo/cache/e5310fe547fdbf0a.tar.zst +0 -0
- package/.turbo/cache/f12bb5f2f188758d-meta.json +1 -0
- package/.turbo/cache/f12bb5f2f188758d.tar.zst +0 -0
- package/.turbo/cache/f2db5af0c0b4d23f-meta.json +1 -0
- package/.turbo/cache/f2db5af0c0b4d23f.tar.zst +0 -0
- package/.turbo/cache/f8935ade01a88cd7-meta.json +1 -0
- package/.turbo/cache/f8935ade01a88cd7.tar.zst +0 -0
- package/.turbo/cache/f982b8dd966f823a-meta.json +1 -0
- package/.turbo/cache/f982b8dd966f823a.tar.zst +0 -0
- package/.turbo/cache/f9d4036dd350ba1a-meta.json +1 -0
- package/.turbo/cache/f9d4036dd350ba1a.tar.zst +0 -0
- package/README.md +661 -0
- package/README_ko.md +577 -0
- package/bun.lock +135 -0
- package/package.json +26 -0
- package/packages/agent/.turbo/turbo-build.log +5 -0
- package/packages/agent/.turbo/turbo-typecheck.log +1 -0
- package/packages/agent/dist/connection/hub-client.d.ts +33 -0
- package/packages/agent/dist/connection/hub-client.d.ts.map +1 -0
- package/packages/agent/dist/connection/index.d.ts +2 -0
- package/packages/agent/dist/connection/index.d.ts.map +1 -0
- package/packages/agent/dist/hooks/index.d.ts +3 -0
- package/packages/agent/dist/hooks/index.d.ts.map +1 -0
- package/packages/agent/dist/hooks/intent-hub-hooks.d.ts +47 -0
- package/packages/agent/dist/hooks/intent-hub-hooks.d.ts.map +1 -0
- package/packages/agent/dist/index.d.ts +6 -0
- package/packages/agent/dist/index.d.ts.map +1 -0
- package/packages/agent/dist/index.js +3315 -0
- package/packages/agent/dist/plugin/index.d.ts +3 -0
- package/packages/agent/dist/plugin/index.d.ts.map +1 -0
- package/packages/agent/dist/plugin/intent-hub-plugin.d.ts +54 -0
- package/packages/agent/dist/plugin/intent-hub-plugin.d.ts.map +1 -0
- package/packages/agent/package.json +32 -0
- package/packages/agent/src/connection/hub-client.ts +152 -0
- package/packages/agent/src/connection/index.ts +1 -0
- package/packages/agent/src/hooks/index.ts +2 -0
- package/packages/agent/src/hooks/intent-hub-hooks.ts +245 -0
- package/packages/agent/src/index.ts +5 -0
- package/packages/agent/src/plugin/index.ts +2 -0
- package/packages/agent/src/plugin/intent-hub-plugin.ts +153 -0
- package/packages/agent/tsconfig.json +9 -0
- package/packages/hub/.turbo/turbo-build.log +6 -0
- package/packages/hub/.turbo/turbo-typecheck.log +1 -0
- package/packages/hub/dist/api/dashboard.d.ts +17 -0
- package/packages/hub/dist/api/dashboard.d.ts.map +1 -0
- package/packages/hub/dist/cli.d.ts +3 -0
- package/packages/hub/dist/cli.d.ts.map +1 -0
- package/packages/hub/dist/cli.js +7719 -0
- package/packages/hub/dist/core/conflict-detector.d.ts +36 -0
- package/packages/hub/dist/core/conflict-detector.d.ts.map +1 -0
- package/packages/hub/dist/core/index.d.ts +7 -0
- package/packages/hub/dist/core/index.d.ts.map +1 -0
- package/packages/hub/dist/core/intent-analyzer.d.ts +8 -0
- package/packages/hub/dist/core/intent-analyzer.d.ts.map +1 -0
- package/packages/hub/dist/core/lock-manager.d.ts +13 -0
- package/packages/hub/dist/core/lock-manager.d.ts.map +1 -0
- package/packages/hub/dist/core/orchestrator.d.ts +46 -0
- package/packages/hub/dist/core/orchestrator.d.ts.map +1 -0
- package/packages/hub/dist/index.d.ts +9 -0
- package/packages/hub/dist/index.d.ts.map +1 -0
- package/packages/hub/dist/index.js +4686 -0
- package/packages/hub/dist/llm/index.d.ts +7 -0
- package/packages/hub/dist/llm/index.d.ts.map +1 -0
- package/packages/hub/dist/llm/negotiation-engine.d.ts +40 -0
- package/packages/hub/dist/llm/negotiation-engine.d.ts.map +1 -0
- package/packages/hub/dist/llm/provider.d.ts +46 -0
- package/packages/hub/dist/llm/provider.d.ts.map +1 -0
- package/packages/hub/dist/llm/smart-analyzer.d.ts +20 -0
- package/packages/hub/dist/llm/smart-analyzer.d.ts.map +1 -0
- package/packages/hub/dist/server/hub-server.d.ts +35 -0
- package/packages/hub/dist/server/hub-server.d.ts.map +1 -0
- package/packages/hub/dist/server/index.d.ts +5 -0
- package/packages/hub/dist/server/index.d.ts.map +1 -0
- package/packages/hub/dist/server/message-handler.d.ts +18 -0
- package/packages/hub/dist/server/message-handler.d.ts.map +1 -0
- package/packages/hub/dist/server/smart-hub-server.d.ts +43 -0
- package/packages/hub/dist/server/smart-hub-server.d.ts.map +1 -0
- package/packages/hub/dist/state/index.d.ts +2 -0
- package/packages/hub/dist/state/index.d.ts.map +1 -0
- package/packages/hub/dist/state/session-manager.d.ts +19 -0
- package/packages/hub/dist/state/session-manager.d.ts.map +1 -0
- package/packages/hub/dist/tunnel/index.d.ts +14 -0
- package/packages/hub/dist/tunnel/index.d.ts.map +1 -0
- package/packages/hub/package.json +54 -0
- package/packages/hub/src/api/dashboard.ts +261 -0
- package/packages/hub/src/cli.ts +193 -0
- package/packages/hub/src/core/conflict-detector.ts +138 -0
- package/packages/hub/src/core/index.ts +6 -0
- package/packages/hub/src/core/intent-analyzer.ts +112 -0
- package/packages/hub/src/core/lock-manager.ts +95 -0
- package/packages/hub/src/core/orchestrator.ts +255 -0
- package/packages/hub/src/index.ts +8 -0
- package/packages/hub/src/llm/index.ts +17 -0
- package/packages/hub/src/llm/negotiation-engine.ts +297 -0
- package/packages/hub/src/llm/provider.ts +175 -0
- package/packages/hub/src/llm/smart-analyzer.ts +169 -0
- package/packages/hub/src/server/hub-server.ts +219 -0
- package/packages/hub/src/server/index.ts +4 -0
- package/packages/hub/src/server/message-handler.ts +111 -0
- package/packages/hub/src/server/smart-hub-server.ts +374 -0
- package/packages/hub/src/state/index.ts +1 -0
- package/packages/hub/src/state/session-manager.ts +59 -0
- package/packages/hub/src/tunnel/index.ts +153 -0
- package/packages/hub/tsconfig.json +9 -0
- package/packages/shared/.turbo/turbo-build.log +5 -0
- package/packages/shared/.turbo/turbo-typecheck.log +1 -0
- package/packages/shared/dist/index.d.ts +3 -0
- package/packages/shared/dist/index.d.ts.map +1 -0
- package/packages/shared/dist/index.js +50 -0
- package/packages/shared/dist/types/domain.d.ts +50 -0
- package/packages/shared/dist/types/domain.d.ts.map +1 -0
- package/packages/shared/dist/types/index.d.ts +4 -0
- package/packages/shared/dist/types/index.d.ts.map +1 -0
- package/packages/shared/dist/types/intent.d.ts +24 -0
- package/packages/shared/dist/types/intent.d.ts.map +1 -0
- package/packages/shared/dist/types/message.d.ts +151 -0
- package/packages/shared/dist/types/message.d.ts.map +1 -0
- package/packages/shared/dist/utils/id.d.ts +6 -0
- package/packages/shared/dist/utils/id.d.ts.map +1 -0
- package/packages/shared/dist/utils/index.d.ts +3 -0
- package/packages/shared/dist/utils/index.d.ts.map +1 -0
- package/packages/shared/dist/utils/message.d.ts +5 -0
- package/packages/shared/dist/utils/message.d.ts.map +1 -0
- package/packages/shared/package.json +33 -0
- package/packages/shared/src/index.ts +2 -0
- package/packages/shared/src/types/domain.ts +57 -0
- package/packages/shared/src/types/index.ts +3 -0
- package/packages/shared/src/types/intent.ts +34 -0
- package/packages/shared/src/types/message.ts +188 -0
- package/packages/shared/src/utils/id.ts +21 -0
- package/packages/shared/src/utils/index.ts +2 -0
- package/packages/shared/src/utils/message.ts +30 -0
- package/packages/shared/tsconfig.json +9 -0
- package/scripts/test-e2e.ts +194 -0
- package/scripts/test-mvp2.ts +167 -0
- package/scripts/test-mvp3.ts +405 -0
- package/tsconfig.json +19 -0
- package/turbo.json +22 -0
package/README.md
ADDED
|
@@ -0,0 +1,661 @@
|
|
|
1
|
+
# Intent Hub
|
|
2
|
+
|
|
3
|
+
**Team-based LLM Coordination Platform with Semantic Conflict Resolution**
|
|
4
|
+
|
|
5
|
+
> When multiple developers use AI coding agents simultaneously, code conflicts happen. Intent Hub solves this by coordinating LLM agents at the **semantic level** - before conflicts occur.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
╔═══════════════════════════════════════════════════════════════╗
|
|
9
|
+
║ ██╗███╗ ██╗████████╗███████╗███╗ ██╗████████╗ ║
|
|
10
|
+
║ ██║████╗ ██║╚══██╔══╝██╔════╝████╗ ██║╚══██╔══╝ ║
|
|
11
|
+
║ ██║██╔██╗ ██║ ██║ █████╗ ██╔██╗ ██║ ██║ ║
|
|
12
|
+
║ ██║██║╚██╗██║ ██║ ██╔══╝ ██║╚██╗██║ ██║ ║
|
|
13
|
+
║ ██║██║ ╚████║ ██║ ███████╗██║ ╚████║ ██║ ║
|
|
14
|
+
║ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ║
|
|
15
|
+
║ HUB ║
|
|
16
|
+
╚═══════════════════════════════════════════════════════════════╝
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
[English](README.md) | [한국어](README_ko.md)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Table of Contents
|
|
24
|
+
|
|
25
|
+
- [The Problem](#the-problem)
|
|
26
|
+
- [The Solution](#the-solution)
|
|
27
|
+
- [Quick Start](#quick-start)
|
|
28
|
+
- [Installation Guide for LLM Agents](#installation-guide-for-llm-agents)
|
|
29
|
+
- [Team Collaboration Guide](#team-collaboration-guide)
|
|
30
|
+
- [Integration](#integration)
|
|
31
|
+
- [How It Works](#how-it-works)
|
|
32
|
+
- [Configuration](#configuration)
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## The Problem
|
|
37
|
+
|
|
38
|
+
In modern teams using AI coding assistants (Cursor, GitHub Copilot, OpenCode, etc.):
|
|
39
|
+
|
|
40
|
+
- **Alice** asks her AI to "implement OAuth login"
|
|
41
|
+
- **Bob** asks his AI to "add session management"
|
|
42
|
+
- Both AIs modify `src/auth/*` simultaneously
|
|
43
|
+
- **Result**: Merge conflicts, lost work, frustration
|
|
44
|
+
|
|
45
|
+
Traditional file-level locks don't work because:
|
|
46
|
+
1. AI agents don't know about each other
|
|
47
|
+
2. Semantic overlap isn't always file-based
|
|
48
|
+
3. "auth" and "session" might not touch the same files but are conceptually related
|
|
49
|
+
|
|
50
|
+
## The Solution
|
|
51
|
+
|
|
52
|
+
Intent Hub introduces **Semantic Locks** - locking at the domain level (`auth`, `payment`, `user`) rather than file level.
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
┌─────────────┐ WebSocket ┌─────────────┐
|
|
56
|
+
│ Alice's │◄──────────────────►│ │
|
|
57
|
+
│ AI Agent │ │ Intent │
|
|
58
|
+
├─────────────┤ │ Hub │
|
|
59
|
+
│ Bob's │◄──────────────────►│ Server │
|
|
60
|
+
│ AI Agent │ │ │
|
|
61
|
+
├─────────────┤ │ (Central │
|
|
62
|
+
│ Carol's │◄──────────────────►│ Coord) │
|
|
63
|
+
│ AI Agent │ │ │
|
|
64
|
+
└─────────────┘ └─────────────┘
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Key Features
|
|
68
|
+
|
|
69
|
+
- **Smart Intent Analysis**: LLM-powered understanding of what each developer intends to do
|
|
70
|
+
- **Semantic Domain Locking**: Lock conceptual areas, not just files
|
|
71
|
+
- **LLM Negotiation**: When conflicts occur, AI agents can negotiate solutions
|
|
72
|
+
- **Auto-Resolution**: Compatible changes proceed automatically
|
|
73
|
+
- **Human Escalation**: Incompatible changes prompt developers for decisions
|
|
74
|
+
|
|
75
|
+
## Quick Start
|
|
76
|
+
|
|
77
|
+
### 🚀 Live Share Mode (Recommended for Teams)
|
|
78
|
+
|
|
79
|
+
**Like VS Code Live Share** - one person hosts, others join with a link. No network setup needed!
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# 1. Install
|
|
83
|
+
git clone https://github.com/your-org/intent-hub.git && cd intent-hub
|
|
84
|
+
bun install && bun run build
|
|
85
|
+
|
|
86
|
+
# 2. Start with Live Share mode
|
|
87
|
+
bun run packages/hub/dist/cli.js --share --llm=openai
|
|
88
|
+
|
|
89
|
+
# Output:
|
|
90
|
+
# ╔═══════════════════════════════════════════════════════════════╗
|
|
91
|
+
# ║ 🔗 SHARE YOUR SESSION ║
|
|
92
|
+
# ╠═══════════════════════════════════════════════════════════════╣
|
|
93
|
+
# ║ Team members can connect using: ║
|
|
94
|
+
# ║ wss://intent-hub-a1b2c3d4.loca.lt ║
|
|
95
|
+
# ╚═══════════════════════════════════════════════════════════════╝
|
|
96
|
+
|
|
97
|
+
# 3. Share the URL with your team!
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
That's it! Team members connect to the shared URL - no firewall/NAT configuration needed.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
### Prerequisites
|
|
105
|
+
|
|
106
|
+
- [Bun](https://bun.sh/) v1.1.0 or later
|
|
107
|
+
- Node.js 20+ (for compatibility)
|
|
108
|
+
|
|
109
|
+
### Installation
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
git clone https://github.com/your-org/intent-hub.git
|
|
113
|
+
cd intent-hub
|
|
114
|
+
bun install
|
|
115
|
+
bun run build
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Start the Hub Server
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
# 🌐 Live Share mode (for remote teams)
|
|
122
|
+
bun run packages/hub/dist/cli.js --share
|
|
123
|
+
|
|
124
|
+
# 🏠 Local mode (same network only)
|
|
125
|
+
bun run packages/hub/dist/cli.js
|
|
126
|
+
|
|
127
|
+
# With OpenAI
|
|
128
|
+
OPENAI_API_KEY=sk-xxx bun run packages/hub/dist/cli.js --share --llm=openai
|
|
129
|
+
|
|
130
|
+
# With Anthropic
|
|
131
|
+
ANTHROPIC_API_KEY=sk-ant-xxx bun run packages/hub/dist/cli.js --llm=anthropic
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Server Options
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
Usage:
|
|
138
|
+
intent-hub [options]
|
|
139
|
+
|
|
140
|
+
Options:
|
|
141
|
+
--port=<number> Port to listen on (default: 9876)
|
|
142
|
+
--host=<string> Host to bind to (default: 0.0.0.0)
|
|
143
|
+
--mode=<mode> Server mode: simple | smart (default: smart)
|
|
144
|
+
--llm=<provider> LLM provider: openai | anthropic | mock (default: mock)
|
|
145
|
+
--api-key=<key> API key for LLM provider (or use env vars)
|
|
146
|
+
--no-negotiate Disable auto-negotiation
|
|
147
|
+
--dashboard Enable web dashboard
|
|
148
|
+
--share Enable Live Share mode (public URL, no network setup)
|
|
149
|
+
--tunnel=<provider> Tunnel: auto | localtunnel | cloudflared (default: auto)
|
|
150
|
+
--help Show help message
|
|
151
|
+
|
|
152
|
+
Environment Variables:
|
|
153
|
+
OPENAI_API_KEY OpenAI API key
|
|
154
|
+
ANTHROPIC_API_KEY Anthropic API key
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Installation Guide for LLM Agents
|
|
160
|
+
|
|
161
|
+
> This section is a reference guide for AI coding agents (Claude Code, OpenCode, Cursor, etc.) when installing Intent Hub.
|
|
162
|
+
|
|
163
|
+
### Quick Install (npx)
|
|
164
|
+
|
|
165
|
+
**Just one command to start a shared session:**
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
# Start Intent Hub with Live Share (recommended)
|
|
169
|
+
npx intent-hub --share
|
|
170
|
+
|
|
171
|
+
# With OpenAI for smart analysis
|
|
172
|
+
OPENAI_API_KEY=sk-xxx npx intent-hub --share --llm=openai
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
That's it! Share the outputted URL with your team.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
### Step 0: Check Environment with User
|
|
180
|
+
|
|
181
|
+
Ask the user:
|
|
182
|
+
- **LLM provider**: OpenAI API key? Anthropic API key? Or just test with mock?
|
|
183
|
+
|
|
184
|
+
### Step 1: Start Hub Server
|
|
185
|
+
|
|
186
|
+
**Option A: npx (Recommended - No installation needed):**
|
|
187
|
+
```bash
|
|
188
|
+
# Quick start with Live Share
|
|
189
|
+
npx intent-hub --share
|
|
190
|
+
|
|
191
|
+
# With OpenAI
|
|
192
|
+
OPENAI_API_KEY=sk-xxx npx intent-hub --share --llm=openai
|
|
193
|
+
|
|
194
|
+
# With Anthropic
|
|
195
|
+
ANTHROPIC_API_KEY=sk-ant-xxx npx intent-hub --share --llm=anthropic
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**Option B: Global install:**
|
|
199
|
+
```bash
|
|
200
|
+
npm install -g intent-hub
|
|
201
|
+
intent-hub --share --llm=openai
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Option C: From source:**
|
|
205
|
+
```bash
|
|
206
|
+
git clone https://github.com/anthropic-for-korea/intent-hub.git
|
|
207
|
+
cd intent-hub && bun install && bun run build
|
|
208
|
+
bun run packages/hub/dist/cli.js --share
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Step 2: Share the URL
|
|
212
|
+
|
|
213
|
+
When server starts with `--share`, it outputs:
|
|
214
|
+
```
|
|
215
|
+
╔═══════════════════════════════════════════════════════════════╗
|
|
216
|
+
║ 🔗 SHARE YOUR SESSION ║
|
|
217
|
+
╠═══════════════════════════════════════════════════════════════╣
|
|
218
|
+
║ Team members can connect using: ║
|
|
219
|
+
║ wss://intent-hub-a1b2c3d4.loca.lt ║
|
|
220
|
+
╚═══════════════════════════════════════════════════════════════╝
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Copy and share this URL with your team!
|
|
224
|
+
|
|
225
|
+
### Step 3: Connect Agent Client
|
|
226
|
+
|
|
227
|
+
Each team member's AI agent connects using:
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
import { HubClient } from '@anthropic-for-korea/intent-hub-agent';
|
|
231
|
+
|
|
232
|
+
const client = new HubClient({
|
|
233
|
+
hubUrl: 'wss://intent-hub-a1b2c3d4.loca.lt', // Shared URL
|
|
234
|
+
userId: 'unique-user-id',
|
|
235
|
+
username: 'Username',
|
|
236
|
+
projectPath: '/path/to/project',
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
client.connect();
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Troubleshooting
|
|
243
|
+
|
|
244
|
+
| Symptom | Cause | Solution |
|
|
245
|
+
|---------|-------|----------|
|
|
246
|
+
| Connection failed | Server not running | Run `npx intent-hub --share` |
|
|
247
|
+
| Tunnel error | Network issue | Try `--tunnel=cloudflared` if you have cloudflared installed |
|
|
248
|
+
| LLM error | No API key | Set `OPENAI_API_KEY` or `ANTHROPIC_API_KEY` env var |
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Team Collaboration Guide
|
|
253
|
+
|
|
254
|
+
### Using Intent Hub as a Team
|
|
255
|
+
|
|
256
|
+
Intent Hub delivers its true value when the entire team uses it together.
|
|
257
|
+
|
|
258
|
+
#### Architecture
|
|
259
|
+
|
|
260
|
+
```
|
|
261
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
262
|
+
│ Team Server │
|
|
263
|
+
│ ┌────────────────────────────────────────────────────────┐ │
|
|
264
|
+
│ │ Intent Hub Server │ │
|
|
265
|
+
│ │ (ws://team-server:9876) │ │
|
|
266
|
+
│ └────────────────────────────────────────────────────────┘ │
|
|
267
|
+
└──────────────────────────────────────────────────────────────┘
|
|
268
|
+
▲
|
|
269
|
+
│ WebSocket
|
|
270
|
+
┌───────────────────┼───────────────────┐
|
|
271
|
+
│ │ │
|
|
272
|
+
▼ ▼ ▼
|
|
273
|
+
┌──────────┐ ┌──────────┐ ┌──────────┐
|
|
274
|
+
│ Dev A │ │ Dev B │ │ Dev C │
|
|
275
|
+
│ Claude │ │ OpenCode │ │ Cursor │
|
|
276
|
+
│ Code │ │ │ │ │
|
|
277
|
+
└──────────┘ └──────────┘ └──────────┘
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
#### Setup Method
|
|
281
|
+
|
|
282
|
+
**1. Run Hub on Team Server:**
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
# Run in background on team server
|
|
286
|
+
nohup bun run packages/hub/dist/cli.js \
|
|
287
|
+
--llm=openai \
|
|
288
|
+
--dashboard \
|
|
289
|
+
--host=0.0.0.0 \
|
|
290
|
+
> intent-hub.log 2>&1 &
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**2. Configure Each Developer's AI Agent:**
|
|
294
|
+
|
|
295
|
+
Developers can simply ask their AI agent (Claude Code, OpenCode, Cursor, etc.):
|
|
296
|
+
|
|
297
|
+
> "Connect to Intent Hub. The hub server address is ws://team-server:9876, and my name is [username]."
|
|
298
|
+
|
|
299
|
+
Or add to project config file:
|
|
300
|
+
|
|
301
|
+
```json
|
|
302
|
+
// .intent-hub.json (create in project root)
|
|
303
|
+
{
|
|
304
|
+
"hubUrl": "ws://team-server:9876",
|
|
305
|
+
"autoConnect": true
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
#### How to Request Installation via LLM
|
|
310
|
+
|
|
311
|
+
Tell your team members:
|
|
312
|
+
|
|
313
|
+
> **"Tell your Claude Code / OpenCode / Cursor this:"**
|
|
314
|
+
>
|
|
315
|
+
> "Install Intent Hub client and connect to ws://team-server:9876.
|
|
316
|
+
> My userId is 'my-unique-id' and name is 'John Doe'.
|
|
317
|
+
> GitHub: https://github.com/your-org/intent-hub"
|
|
318
|
+
|
|
319
|
+
The AI agent will automatically:
|
|
320
|
+
1. Install required packages
|
|
321
|
+
2. Create config files
|
|
322
|
+
3. Connect to hub server
|
|
323
|
+
4. Run tests
|
|
324
|
+
|
|
325
|
+
#### Collaboration Workflow
|
|
326
|
+
|
|
327
|
+
```
|
|
328
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
329
|
+
│ Collaboration Scenario │
|
|
330
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
331
|
+
│ │
|
|
332
|
+
│ 1. Alice: "Implement OAuth login" │
|
|
333
|
+
│ └─> Intent Hub: Lock acquired for auth/oauth ✓ │
|
|
334
|
+
│ │
|
|
335
|
+
│ 2. Bob: "Add session management" │
|
|
336
|
+
│ └─> Intent Hub: Conflict detected in auth domain! │
|
|
337
|
+
│ └─> Notify Bob's AI: "Alice is working on auth. │
|
|
338
|
+
│ Please work on something else or wait." │
|
|
339
|
+
│ │
|
|
340
|
+
│ 3. Carol: "Refactor payment system" │
|
|
341
|
+
│ └─> Intent Hub: Lock acquired for payment ✓ │
|
|
342
|
+
│ (Unrelated to auth, can proceed simultaneously) │
|
|
343
|
+
│ │
|
|
344
|
+
│ 4. Alice completes work │
|
|
345
|
+
│ └─> Intent Hub: Release auth/oauth lock │
|
|
346
|
+
│ └─> Notify Bob's AI: "auth is now available" │
|
|
347
|
+
│ │
|
|
348
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
#### Recommended Setup by Team Size
|
|
352
|
+
|
|
353
|
+
| Team Size | Server Location | LLM Setting | Notes |
|
|
354
|
+
|-----------|----------------|-------------|-------|
|
|
355
|
+
| 1-3 | Local (one developer) | Mock or OpenAI | Simple setup |
|
|
356
|
+
| 4-10 | Dedicated team server | OpenAI or Anthropic | Stable connection needed |
|
|
357
|
+
| 10+ | Cloud (AWS/GCP) | OpenAI + HA | Production-level |
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
## Integration
|
|
362
|
+
|
|
363
|
+
### With OpenCode (Hooks)
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
import { createIntentHubHooks } from '@intent-hub/agent';
|
|
367
|
+
|
|
368
|
+
const hooks = createIntentHubHooks({
|
|
369
|
+
hubUrl: 'ws://localhost:9876',
|
|
370
|
+
userId: 'alice',
|
|
371
|
+
username: 'Alice',
|
|
372
|
+
projectPath: '/path/to/project',
|
|
373
|
+
onNotification: (event, data) => {
|
|
374
|
+
console.log(`[IntentHub] ${event}:`, data);
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
// In your AI agent's tool hooks:
|
|
379
|
+
// Pre-tool hook - check if action is allowed
|
|
380
|
+
const result = await hooks.preToolUse({
|
|
381
|
+
toolName: 'edit',
|
|
382
|
+
toolInput: { filePath: 'src/auth/login.ts', content: '...' },
|
|
383
|
+
sessionId: 'session-123',
|
|
384
|
+
userId: 'alice',
|
|
385
|
+
username: 'Alice',
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
if (!result.allow) {
|
|
389
|
+
console.log(result.message); // Domain locked by another user
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// When user submits a prompt
|
|
393
|
+
const promptResult = await hooks.onUserPromptSubmit('Add OAuth login with Google');
|
|
394
|
+
if (promptResult.message) {
|
|
395
|
+
console.log(promptResult.message); // Warning about locked domains
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Programmatic Usage
|
|
400
|
+
|
|
401
|
+
```typescript
|
|
402
|
+
import { HubClient } from '@intent-hub/agent';
|
|
403
|
+
|
|
404
|
+
const client = new HubClient({
|
|
405
|
+
hubUrl: 'ws://localhost:9876',
|
|
406
|
+
userId: 'alice',
|
|
407
|
+
username: 'Alice',
|
|
408
|
+
projectPath: '/path/to/project',
|
|
409
|
+
onConnected: (sessionId) => {
|
|
410
|
+
console.log('Connected:', sessionId);
|
|
411
|
+
},
|
|
412
|
+
onMessage: (message) => {
|
|
413
|
+
switch (message.type) {
|
|
414
|
+
case 'hub:lock:acquired':
|
|
415
|
+
console.log('Lock acquired for domains:', message.payload.domains);
|
|
416
|
+
break;
|
|
417
|
+
case 'hub:lock:blocked':
|
|
418
|
+
console.log('Blocked by:', message.payload.blockedBy);
|
|
419
|
+
break;
|
|
420
|
+
case 'hub:negotiation:start':
|
|
421
|
+
console.log('Negotiation started with:', message.payload.participants);
|
|
422
|
+
break;
|
|
423
|
+
case 'hub:decision:required':
|
|
424
|
+
console.log('Decision needed:', message.payload.question);
|
|
425
|
+
break;
|
|
426
|
+
}
|
|
427
|
+
},
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
client.connect();
|
|
431
|
+
|
|
432
|
+
// Submit intent when user gives a prompt
|
|
433
|
+
client.submitIntent('Implement Google OAuth login');
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
## Architecture
|
|
437
|
+
|
|
438
|
+
```
|
|
439
|
+
intent-hub/
|
|
440
|
+
├── packages/
|
|
441
|
+
│ ├── shared/ # Shared types & utilities
|
|
442
|
+
│ │ └── src/
|
|
443
|
+
│ │ ├── types/ # Intent, Domain, Message types
|
|
444
|
+
│ │ └── utils/ # ID generation, message helpers
|
|
445
|
+
│ │
|
|
446
|
+
│ ├── hub/ # Central Hub Server
|
|
447
|
+
│ │ └── src/
|
|
448
|
+
│ │ ├── server/ # WebSocket server
|
|
449
|
+
│ │ ├── core/ # Lock manager, conflict detector, orchestrator
|
|
450
|
+
│ │ ├── llm/ # LLM provider, analyzer, negotiation engine
|
|
451
|
+
│ │ └── state/ # Session management
|
|
452
|
+
│ │
|
|
453
|
+
│ └── agent/ # Client-side Agent Library
|
|
454
|
+
│ └── src/
|
|
455
|
+
│ ├── connection/ # Hub client
|
|
456
|
+
│ ├── plugin/ # Plugin interface
|
|
457
|
+
│ └── hooks/ # OpenCode hooks
|
|
458
|
+
│
|
|
459
|
+
├── scripts/
|
|
460
|
+
│ ├── test-e2e.ts # End-to-end tests
|
|
461
|
+
│ └── test-mvp2.ts # LLM negotiation tests
|
|
462
|
+
│
|
|
463
|
+
└── turbo.json # Turborepo config
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
## How It Works
|
|
467
|
+
|
|
468
|
+
### 1. Intent Submission
|
|
469
|
+
|
|
470
|
+
When a developer gives their AI a task:
|
|
471
|
+
```
|
|
472
|
+
User: "Add Google OAuth login"
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
The agent submits this intent to Intent Hub:
|
|
476
|
+
```typescript
|
|
477
|
+
client.submitIntent('Add Google OAuth login');
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### 2. Smart Analysis
|
|
481
|
+
|
|
482
|
+
Intent Hub analyzes the intent using LLM:
|
|
483
|
+
```json
|
|
484
|
+
{
|
|
485
|
+
"domain": "auth",
|
|
486
|
+
"subdomain": "oauth",
|
|
487
|
+
"affectedFiles": ["src/auth/oauth.ts", "src/auth/providers/google.ts"],
|
|
488
|
+
"semanticTags": ["login", "oauth", "google", "authentication"],
|
|
489
|
+
"estimatedScope": "medium"
|
|
490
|
+
}
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### 3. Conflict Detection
|
|
494
|
+
|
|
495
|
+
The system checks for semantic conflicts:
|
|
496
|
+
|
|
497
|
+
| Scenario | Result |
|
|
498
|
+
|----------|--------|
|
|
499
|
+
| No overlap | **Approved** - proceed immediately |
|
|
500
|
+
| Same domain, different subdomain | **Warning** - may proceed with caution |
|
|
501
|
+
| Same domain, same subdomain | **Blocked** or **Negotiation** |
|
|
502
|
+
|
|
503
|
+
### 4. Resolution
|
|
504
|
+
|
|
505
|
+
**Auto-Approved:**
|
|
506
|
+
```
|
|
507
|
+
Alice: auth/oauth ✓
|
|
508
|
+
Carol: payment ✓ (different domain)
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
**Blocked:**
|
|
512
|
+
```
|
|
513
|
+
Alice: auth/oauth ✓
|
|
514
|
+
Bob: auth/session ⚠️ (same domain - blocked until Alice finishes)
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
**Negotiation (when enabled):**
|
|
518
|
+
```
|
|
519
|
+
Alice: auth/oauth
|
|
520
|
+
Bob: auth/session
|
|
521
|
+
→ LLMs discuss and propose: "Alice works on OAuth first, Bob does session after"
|
|
522
|
+
→ Both users notified of the plan
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
## Message Protocol
|
|
526
|
+
|
|
527
|
+
### Agent → Hub
|
|
528
|
+
|
|
529
|
+
| Message | Description |
|
|
530
|
+
|---------|-------------|
|
|
531
|
+
| `agent:connect` | Initial connection with user info |
|
|
532
|
+
| `agent:intent:submit` | Submit a new intent (user prompt) |
|
|
533
|
+
| `agent:decision` | User's decision on a conflict |
|
|
534
|
+
|
|
535
|
+
### Hub → Agent
|
|
536
|
+
|
|
537
|
+
| Message | Description |
|
|
538
|
+
|---------|-------------|
|
|
539
|
+
| `hub:connected` | Connection confirmed with session ID |
|
|
540
|
+
| `hub:intent:received` | Intent acknowledged |
|
|
541
|
+
| `hub:intent:analyzed` | Analysis complete with domain info |
|
|
542
|
+
| `hub:lock:acquired` | Lock granted, proceed with work |
|
|
543
|
+
| `hub:lock:blocked` | Lock denied, wait or work elsewhere |
|
|
544
|
+
| `hub:negotiation:start` | Negotiation started with another user |
|
|
545
|
+
| `hub:negotiation:resolved` | Negotiation complete with plan |
|
|
546
|
+
| `hub:decision:required` | User input needed |
|
|
547
|
+
|
|
548
|
+
### Broadcasts
|
|
549
|
+
|
|
550
|
+
| Message | Description |
|
|
551
|
+
|---------|-------------|
|
|
552
|
+
| `broadcast:user:joined` | New user connected |
|
|
553
|
+
| `broadcast:user:left` | User disconnected |
|
|
554
|
+
| `broadcast:lock:update` | Lock status changed |
|
|
555
|
+
|
|
556
|
+
## Development
|
|
557
|
+
|
|
558
|
+
### Build
|
|
559
|
+
|
|
560
|
+
```bash
|
|
561
|
+
bun install
|
|
562
|
+
bun run build
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
### Development Mode
|
|
566
|
+
|
|
567
|
+
```bash
|
|
568
|
+
# Watch mode for hub
|
|
569
|
+
bun run dev:hub
|
|
570
|
+
|
|
571
|
+
# Watch mode for agent
|
|
572
|
+
bun run dev:agent
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### Run Tests
|
|
576
|
+
|
|
577
|
+
```bash
|
|
578
|
+
# E2E test (basic flow)
|
|
579
|
+
bun run scripts/test-e2e.ts
|
|
580
|
+
|
|
581
|
+
# MVP2 test (LLM negotiation)
|
|
582
|
+
bun run scripts/test-mvp2.ts
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
### Type Check
|
|
586
|
+
|
|
587
|
+
```bash
|
|
588
|
+
bun run typecheck
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
## Configuration
|
|
592
|
+
|
|
593
|
+
### Hub Server Configuration
|
|
594
|
+
|
|
595
|
+
```typescript
|
|
596
|
+
interface SmartHubServerOptions {
|
|
597
|
+
port: number; // WebSocket port
|
|
598
|
+
host?: string; // Bind address (default: 0.0.0.0)
|
|
599
|
+
llmProvider: LLMProvider; // OpenAI, Anthropic, or Mock
|
|
600
|
+
orchestratorConfig?: {
|
|
601
|
+
useLLMAnalysis?: boolean; // Use LLM for intent analysis
|
|
602
|
+
autoNegotiate?: boolean; // Auto-negotiate conflicts
|
|
603
|
+
conflictThreshold?: 'low' | 'medium' | 'high';
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
### Agent Configuration
|
|
609
|
+
|
|
610
|
+
```typescript
|
|
611
|
+
interface IntentHubHooksConfig {
|
|
612
|
+
hubUrl: string; // WebSocket URL to hub
|
|
613
|
+
userId: string; // Unique user identifier
|
|
614
|
+
username: string; // Display name
|
|
615
|
+
projectPath: string; // Project root path
|
|
616
|
+
autoConnect?: boolean; // Connect on creation (default: true)
|
|
617
|
+
onNotification?: (event: string, data: unknown) => void;
|
|
618
|
+
}
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
## Semantic Domains
|
|
622
|
+
|
|
623
|
+
Intent Hub automatically categorizes work into semantic domains:
|
|
624
|
+
|
|
625
|
+
| Domain | Triggers |
|
|
626
|
+
|--------|----------|
|
|
627
|
+
| `auth` | `/auth/`, `login`, `oauth`, `session`, `jwt` |
|
|
628
|
+
| `user` | `/user/`, `profile`, `account` |
|
|
629
|
+
| `payment` | `/payment/`, `checkout`, `stripe`, `billing` |
|
|
630
|
+
| `api` | `/api/`, `route`, `endpoint` |
|
|
631
|
+
| `ui` | `.tsx`, `.jsx`, `/component` |
|
|
632
|
+
| `database` | `/db/`, `migration`, `schema` |
|
|
633
|
+
| `config` | `config`, `.env` |
|
|
634
|
+
| `test` | `.test.`, `.spec.`, `/test/` |
|
|
635
|
+
|
|
636
|
+
Custom domains can be configured based on your project structure.
|
|
637
|
+
|
|
638
|
+
## Roadmap
|
|
639
|
+
|
|
640
|
+
- [x] **MVP 1**: Basic domain locking
|
|
641
|
+
- [x] **MVP 2**: LLM-powered intent analysis & negotiation
|
|
642
|
+
- [x] **MVP 3**: OpenCode integration hooks
|
|
643
|
+
- [ ] **MVP 4**: Web dashboard for team visibility
|
|
644
|
+
- [ ] **MVP 5**: History & analytics
|
|
645
|
+
- [ ] **MVP 6**: VS Code extension
|
|
646
|
+
|
|
647
|
+
## Contributing
|
|
648
|
+
|
|
649
|
+
1. Fork the repository
|
|
650
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
651
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
652
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
653
|
+
5. Open a Pull Request
|
|
654
|
+
|
|
655
|
+
## License
|
|
656
|
+
|
|
657
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
658
|
+
|
|
659
|
+
---
|
|
660
|
+
|
|
661
|
+
Built with love by the Intent Hub team. Because AI collaboration should be as smooth as human collaboration (or better).
|