@indexnetwork/cli 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +107 -0
- package/dist/index.js +641 -26
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -73,6 +73,9 @@ View user profiles and trigger profile regeneration.
|
|
|
73
73
|
index profile # Show your own profile
|
|
74
74
|
index profile show <user-id> # Show another user's profile
|
|
75
75
|
index profile sync # Regenerate your profile
|
|
76
|
+
index profile search <query> # Search profiles by name or keyword
|
|
77
|
+
index profile create # Generate profile from social links
|
|
78
|
+
index profile update <details> # Update profile details
|
|
76
79
|
```
|
|
77
80
|
|
|
78
81
|
### `index intent`
|
|
@@ -85,7 +88,11 @@ index intent list --archived # Include archived signals
|
|
|
85
88
|
index intent list --limit 5 # Limit to 5 results
|
|
86
89
|
index intent show <id> # Show full signal details
|
|
87
90
|
index intent create "Looking for a CTO" # Create from natural language
|
|
91
|
+
index intent update <id> "revised text" # Update a signal (runs full pipeline)
|
|
88
92
|
index intent archive <id> # Archive a signal
|
|
93
|
+
index intent link <id> <network-id> # Link a signal to a network
|
|
94
|
+
index intent unlink <id> <network-id> # Unlink a signal from a network
|
|
95
|
+
index intent links <id> # List networks linked to a signal
|
|
89
96
|
```
|
|
90
97
|
|
|
91
98
|
### `index opportunity`
|
|
@@ -99,6 +106,9 @@ index opportunity list --limit 5 # Limit results
|
|
|
99
106
|
index opportunity show <id> # Show full details
|
|
100
107
|
index opportunity accept <id> # Accept an opportunity
|
|
101
108
|
index opportunity reject <id> # Reject an opportunity
|
|
109
|
+
index opportunity discover "query" # Discover opportunities by search
|
|
110
|
+
index opportunity discover --target <id> # Discover with a specific user
|
|
111
|
+
index opportunity discover --introduce <a> <b> # Introduce two users
|
|
102
112
|
```
|
|
103
113
|
|
|
104
114
|
Status values: `pending`, `accepted`, `rejected`, `expired`.
|
|
@@ -112,11 +122,98 @@ index network list # List your networks
|
|
|
112
122
|
index network create "My Network" # Create a network
|
|
113
123
|
index network create "AI" --prompt "AI researchers" # Create with description
|
|
114
124
|
index network show <id> # Show details and members
|
|
125
|
+
index network update <id> --title "New Name" # Update a network
|
|
126
|
+
index network delete <id> # Delete a network
|
|
115
127
|
index network join <id> # Join a public network
|
|
116
128
|
index network leave <id> # Leave a network
|
|
117
129
|
index network invite <id> user@email # Invite a user by email
|
|
118
130
|
```
|
|
119
131
|
|
|
132
|
+
### `index contact`
|
|
133
|
+
|
|
134
|
+
Manage your contacts. Add, list, remove, or import contacts.
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
index contact list # List your contacts
|
|
138
|
+
index contact add user@email # Add a contact by email
|
|
139
|
+
index contact add user@email --name "Name" # Add with display name
|
|
140
|
+
index contact remove user@email # Remove a contact
|
|
141
|
+
index contact import --gmail # Import contacts from Gmail
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### `index scrape`
|
|
145
|
+
|
|
146
|
+
Scrape and extract content from a URL.
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
index scrape https://example.com # Scrape a URL
|
|
150
|
+
index scrape https://example.com --objective "..." # Scrape with focus
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### `index sync`
|
|
154
|
+
|
|
155
|
+
Sync all user context (profile, networks, intents, contacts) to a local file.
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
index sync # Sync to ~/.index/context.json
|
|
159
|
+
index sync --json # Output to stdout as JSON
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Examples: Opportunity Discovery
|
|
163
|
+
|
|
164
|
+
The `opportunity discover` command supports multiple modes for creating connections.
|
|
165
|
+
|
|
166
|
+
### Scenario 1: Search-based discovery
|
|
167
|
+
|
|
168
|
+
Find people whose intents match a search query. The protocol runs HyDE-powered semantic search across your networks.
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# Find collaborators for a project
|
|
172
|
+
index opportunity discover "looking for an AI engineer with privacy expertise"
|
|
173
|
+
|
|
174
|
+
# Scope discovery to a specific network
|
|
175
|
+
index opportunity discover "need a React developer" --target <network-id>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Scenario 2: Direct connection
|
|
179
|
+
|
|
180
|
+
Propose an opportunity with a specific person. Use when you already know who you want to connect with.
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
# First, find the user
|
|
184
|
+
index profile search "Jane Smith"
|
|
185
|
+
|
|
186
|
+
# Then create a direct opportunity with them
|
|
187
|
+
index opportunity discover "collaborate on open-source LLM tooling" --target <user-id>
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Scenario 3: Introduction
|
|
191
|
+
|
|
192
|
+
Introduce two people you think should connect. You become the introducer — both parties see you as the connector.
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
# Introduce two users to each other
|
|
196
|
+
index opportunity discover --introduce <user-id-a> <user-id-b>
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Scenario 4: Review and act
|
|
200
|
+
|
|
201
|
+
After discovery creates draft opportunities, review and accept/reject them.
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
# List pending opportunities
|
|
205
|
+
index opportunity list --status pending
|
|
206
|
+
|
|
207
|
+
# See full details (reasoning, scores, mutual intents)
|
|
208
|
+
index opportunity show <id>
|
|
209
|
+
|
|
210
|
+
# Accept — starts a conversation thread
|
|
211
|
+
index opportunity accept <id>
|
|
212
|
+
|
|
213
|
+
# Or reject
|
|
214
|
+
index opportunity reject <id>
|
|
215
|
+
```
|
|
216
|
+
|
|
120
217
|
## Options
|
|
121
218
|
|
|
122
219
|
| Flag | Short | Description |
|
|
@@ -129,6 +226,13 @@ index network invite <id> user@email # Invite a user by email
|
|
|
129
226
|
| `--status <status>` | | Filter opportunities by status |
|
|
130
227
|
| `--limit <n>` | | Limit number of results |
|
|
131
228
|
| `--prompt <text>` | `-p` | Network description (for `network create`) |
|
|
229
|
+
| `--title <text>` | | Network title (for `network update`) |
|
|
230
|
+
| `--name <name>` | | Display name (for `contact add`) |
|
|
231
|
+
| `--gmail` | | Import from Gmail (for `contact import`) |
|
|
232
|
+
| `--target <id>` | | Target user ID (for `opportunity discover`) |
|
|
233
|
+
| `--introduce <id>` | | Introduce two users (for `opportunity discover`) |
|
|
234
|
+
| `--objective <text>` | | Focus objective (for `scrape`) |
|
|
235
|
+
| `--json` | | Output raw JSON to stdout |
|
|
132
236
|
| `--help` | `-h` | Show help |
|
|
133
237
|
| `--version` | `-v` | Show version |
|
|
134
238
|
|
|
@@ -170,6 +274,9 @@ cli/
|
|
|
170
274
|
intent.command.ts Intent (signal) subcommand handlers
|
|
171
275
|
opportunity.command.ts Opportunity subcommand handlers
|
|
172
276
|
network.command.ts Network subcommand handlers
|
|
277
|
+
contact.command.ts Contact subcommand handlers
|
|
278
|
+
scrape.command.ts URL scraping command handler
|
|
279
|
+
sync.command.ts Context sync command handler
|
|
173
280
|
output/ Terminal formatting, colors, markdown renderer
|
|
174
281
|
api.client.ts Typed HTTP client for the protocol API
|
|
175
282
|
auth.store.ts Credential persistence (~/.index/credentials.json)
|
package/dist/index.js
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
import { execFile } from "node:child_process";
|
|
5
5
|
|
|
6
6
|
// src/args.parser.ts
|
|
7
|
-
var KNOWN_COMMANDS = new Set(["login", "logout", "profile", "intent", "opportunity", "network", "conversation", "help", "version"]);
|
|
8
|
-
var OPPORTUNITY_SUBCOMMANDS = new Set(["list", "show", "accept", "reject"]);
|
|
9
|
-
var NETWORK_SUBCOMMANDS = new Set(["list", "create", "show", "join", "leave", "invite"]);
|
|
7
|
+
var KNOWN_COMMANDS = new Set(["login", "logout", "profile", "intent", "opportunity", "network", "conversation", "contact", "scrape", "onboarding", "sync", "help", "version"]);
|
|
8
|
+
var OPPORTUNITY_SUBCOMMANDS = new Set(["list", "show", "accept", "reject", "discover"]);
|
|
9
|
+
var NETWORK_SUBCOMMANDS = new Set(["list", "create", "show", "join", "leave", "invite", "update", "delete"]);
|
|
10
10
|
var CONVERSATION_SUBCOMMANDS = new Set(["list", "with", "show", "send", "stream", "sessions", "help"]);
|
|
11
11
|
function parseArgs(args) {
|
|
12
12
|
const result = {
|
|
@@ -62,6 +62,39 @@ function parseArgs(args) {
|
|
|
62
62
|
} else if (arg === "--prompt" || arg === "-p") {
|
|
63
63
|
result.prompt = args[i + 1];
|
|
64
64
|
i += 2;
|
|
65
|
+
} else if (arg === "--json") {
|
|
66
|
+
result.json = true;
|
|
67
|
+
i++;
|
|
68
|
+
} else if (arg === "--name") {
|
|
69
|
+
result.name = args[i + 1];
|
|
70
|
+
i += 2;
|
|
71
|
+
} else if (arg === "--gmail") {
|
|
72
|
+
result.gmail = true;
|
|
73
|
+
i++;
|
|
74
|
+
} else if (arg === "--objective") {
|
|
75
|
+
result.objective = args[i + 1];
|
|
76
|
+
i += 2;
|
|
77
|
+
} else if (arg === "--target") {
|
|
78
|
+
result.target = args[i + 1];
|
|
79
|
+
i += 2;
|
|
80
|
+
} else if (arg === "--introduce") {
|
|
81
|
+
result.introduce = args[i + 1];
|
|
82
|
+
i += 2;
|
|
83
|
+
} else if (arg === "--linkedin") {
|
|
84
|
+
result.linkedin = args[i + 1];
|
|
85
|
+
i += 2;
|
|
86
|
+
} else if (arg === "--github") {
|
|
87
|
+
result.github = args[i + 1];
|
|
88
|
+
i += 2;
|
|
89
|
+
} else if (arg === "--twitter") {
|
|
90
|
+
result.twitter = args[i + 1];
|
|
91
|
+
i += 2;
|
|
92
|
+
} else if (arg === "--title") {
|
|
93
|
+
result.title = args[i + 1];
|
|
94
|
+
i += 2;
|
|
95
|
+
} else if (arg === "--details") {
|
|
96
|
+
result.details = args[i + 1];
|
|
97
|
+
i += 2;
|
|
65
98
|
} else if (arg.startsWith("--")) {
|
|
66
99
|
i++;
|
|
67
100
|
} else {
|
|
@@ -73,7 +106,9 @@ function parseArgs(args) {
|
|
|
73
106
|
const sub = positionals[0];
|
|
74
107
|
if (sub && OPPORTUNITY_SUBCOMMANDS.has(sub)) {
|
|
75
108
|
result.subcommand = sub;
|
|
76
|
-
if (
|
|
109
|
+
if (sub === "discover") {
|
|
110
|
+
result.positionals = positionals.slice(1);
|
|
111
|
+
} else if (positionals[1]) {
|
|
77
112
|
result.targetId = positionals[1];
|
|
78
113
|
}
|
|
79
114
|
}
|
|
@@ -88,8 +123,34 @@ function parseArgs(args) {
|
|
|
88
123
|
}
|
|
89
124
|
} else if (sub === "sync") {
|
|
90
125
|
result.subcommand = "sync";
|
|
126
|
+
} else if (sub === "search") {
|
|
127
|
+
result.subcommand = "search";
|
|
128
|
+
result.positionals = positionals.slice(1);
|
|
129
|
+
} else if (sub === "create") {
|
|
130
|
+
result.subcommand = "create";
|
|
131
|
+
} else if (sub === "update") {
|
|
132
|
+
result.subcommand = "update";
|
|
133
|
+
result.positionals = positionals.slice(1);
|
|
91
134
|
}
|
|
92
135
|
}
|
|
136
|
+
if (result.command === "onboarding" && positionals.length > 0) {
|
|
137
|
+
const sub = positionals[0];
|
|
138
|
+
if (sub === "complete") {
|
|
139
|
+
result.subcommand = "complete";
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (result.command === "contact") {
|
|
143
|
+
if (positionals.length > 0) {
|
|
144
|
+
const sub = positionals[0];
|
|
145
|
+
if (["list", "add", "remove", "import"].includes(sub)) {
|
|
146
|
+
result.subcommand = sub;
|
|
147
|
+
result.positionals = positionals.slice(1);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (result.command === "scrape") {
|
|
152
|
+
result.positionals = positionals;
|
|
153
|
+
}
|
|
93
154
|
if (result.command === "intent") {
|
|
94
155
|
parseIntentArgs(positionals, result);
|
|
95
156
|
}
|
|
@@ -111,7 +172,7 @@ function parseArgs(args) {
|
|
|
111
172
|
}
|
|
112
173
|
return result;
|
|
113
174
|
}
|
|
114
|
-
var INTENT_SUBCOMMANDS = new Set(["list", "show", "create", "archive"]);
|
|
175
|
+
var INTENT_SUBCOMMANDS = new Set(["list", "show", "create", "archive", "update", "link", "unlink", "links"]);
|
|
115
176
|
function parseIntentArgs(positionals, result) {
|
|
116
177
|
if (positionals.length === 0)
|
|
117
178
|
return;
|
|
@@ -123,6 +184,7 @@ function parseIntentArgs(positionals, result) {
|
|
|
123
184
|
switch (result.subcommand) {
|
|
124
185
|
case "show":
|
|
125
186
|
case "archive":
|
|
187
|
+
case "links":
|
|
126
188
|
result.intentId = rest[0];
|
|
127
189
|
break;
|
|
128
190
|
case "create":
|
|
@@ -130,6 +192,17 @@ function parseIntentArgs(positionals, result) {
|
|
|
130
192
|
result.intentContent = rest.join(" ");
|
|
131
193
|
}
|
|
132
194
|
break;
|
|
195
|
+
case "update":
|
|
196
|
+
result.intentId = rest[0];
|
|
197
|
+
if (rest.length > 1) {
|
|
198
|
+
result.intentContent = rest.slice(1).join(" ");
|
|
199
|
+
}
|
|
200
|
+
break;
|
|
201
|
+
case "link":
|
|
202
|
+
case "unlink":
|
|
203
|
+
result.intentId = rest[0];
|
|
204
|
+
result.targetId = rest[1];
|
|
205
|
+
break;
|
|
133
206
|
}
|
|
134
207
|
}
|
|
135
208
|
|
|
@@ -354,6 +427,10 @@ class ApiClient {
|
|
|
354
427
|
}
|
|
355
428
|
return res;
|
|
356
429
|
}
|
|
430
|
+
async callTool(toolName, query = {}) {
|
|
431
|
+
const res = await this.post(`/api/tools/${toolName}`, { query });
|
|
432
|
+
return await res.json();
|
|
433
|
+
}
|
|
357
434
|
async get(path) {
|
|
358
435
|
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
359
436
|
headers: {
|
|
@@ -914,6 +991,19 @@ function profileCard(data) {
|
|
|
914
991
|
console.log(output);
|
|
915
992
|
return output;
|
|
916
993
|
}
|
|
994
|
+
function contactTable(contacts) {
|
|
995
|
+
if (contacts.length === 0) {
|
|
996
|
+
console.log(" No contacts yet.");
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
999
|
+
const nameWidth = Math.max(6, ...contacts.map((c) => c.name.length));
|
|
1000
|
+
const header = ` ${"Name".padEnd(nameWidth)} Email`;
|
|
1001
|
+
console.log(`${BOLD}${header}${RESET}`);
|
|
1002
|
+
for (const c of contacts) {
|
|
1003
|
+
const ghost = c.isGhost ? ` ${DIM}(ghost)${RESET}` : "";
|
|
1004
|
+
console.log(` ${c.name.padEnd(nameWidth)} ${c.email}${ghost}`);
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
917
1007
|
function sessionTable(sessions) {
|
|
918
1008
|
if (sessions.length === 0) {
|
|
919
1009
|
dim(" No chat sessions found.");
|
|
@@ -1262,7 +1352,20 @@ function messageList(messages) {
|
|
|
1262
1352
|
}
|
|
1263
1353
|
}
|
|
1264
1354
|
// src/profile.command.ts
|
|
1265
|
-
async function handleProfile(client, subcommand, positionals) {
|
|
1355
|
+
async function handleProfile(client, subcommand, positionals, options = {}) {
|
|
1356
|
+
if (subcommand === "create") {
|
|
1357
|
+
await profileCreate(client, options);
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
if (subcommand === "update") {
|
|
1361
|
+
const action = positionals.join(" ");
|
|
1362
|
+
if (!action) {
|
|
1363
|
+
error("Usage: index profile update <action> [--details <text>]", 1);
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1366
|
+
await profileUpdate(client, action, options.details);
|
|
1367
|
+
return;
|
|
1368
|
+
}
|
|
1266
1369
|
if (subcommand === "sync") {
|
|
1267
1370
|
await profileSync(client);
|
|
1268
1371
|
return;
|
|
@@ -1276,6 +1379,35 @@ async function handleProfile(client, subcommand, positionals) {
|
|
|
1276
1379
|
await profileShow(client, userId);
|
|
1277
1380
|
return;
|
|
1278
1381
|
}
|
|
1382
|
+
if (subcommand === "search") {
|
|
1383
|
+
const query = positionals.join(" ");
|
|
1384
|
+
if (!query) {
|
|
1385
|
+
error("Usage: index profile search <query>", 1);
|
|
1386
|
+
return;
|
|
1387
|
+
}
|
|
1388
|
+
const result = await client.callTool("read_user_profiles", { query });
|
|
1389
|
+
if (options.json) {
|
|
1390
|
+
console.log(JSON.stringify(result));
|
|
1391
|
+
return;
|
|
1392
|
+
}
|
|
1393
|
+
if (!result.success) {
|
|
1394
|
+
error(result.error ?? "Search failed", 1);
|
|
1395
|
+
return;
|
|
1396
|
+
}
|
|
1397
|
+
const data = result.data;
|
|
1398
|
+
heading("Search Results");
|
|
1399
|
+
if (!data.profiles?.length) {
|
|
1400
|
+
dim(" No profiles found.");
|
|
1401
|
+
} else {
|
|
1402
|
+
for (const p of data.profiles) {
|
|
1403
|
+
console.log(` ${p.name} (${p.userId.slice(0, 8)})`);
|
|
1404
|
+
if (p.profile?.bio)
|
|
1405
|
+
dim(` ${p.profile.bio.slice(0, 100)}`);
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
console.log();
|
|
1409
|
+
return;
|
|
1410
|
+
}
|
|
1279
1411
|
await profileMe(client);
|
|
1280
1412
|
}
|
|
1281
1413
|
async function profileMe(client) {
|
|
@@ -1294,6 +1426,34 @@ async function profileSync(client) {
|
|
|
1294
1426
|
await client.syncProfile();
|
|
1295
1427
|
success("Profile regeneration triggered. It may take a moment to complete.");
|
|
1296
1428
|
}
|
|
1429
|
+
async function profileCreate(client, options) {
|
|
1430
|
+
info("Creating profile...");
|
|
1431
|
+
const query = { confirm: true };
|
|
1432
|
+
if (options.linkedin)
|
|
1433
|
+
query.linkedinUrl = options.linkedin;
|
|
1434
|
+
if (options.github)
|
|
1435
|
+
query.githubUrl = options.github;
|
|
1436
|
+
if (options.twitter)
|
|
1437
|
+
query.twitterUrl = options.twitter;
|
|
1438
|
+
const result = await client.callTool("create_user_profile", query);
|
|
1439
|
+
if (!result.success) {
|
|
1440
|
+
error(result.error ?? "Profile creation failed", 1);
|
|
1441
|
+
return;
|
|
1442
|
+
}
|
|
1443
|
+
success("Profile created.");
|
|
1444
|
+
}
|
|
1445
|
+
async function profileUpdate(client, action, details) {
|
|
1446
|
+
info("Updating profile...");
|
|
1447
|
+
const query = { action };
|
|
1448
|
+
if (details)
|
|
1449
|
+
query.details = details;
|
|
1450
|
+
const result = await client.callTool("update_user_profile", query);
|
|
1451
|
+
if (!result.success) {
|
|
1452
|
+
error(result.error ?? "Profile update failed", 1);
|
|
1453
|
+
return;
|
|
1454
|
+
}
|
|
1455
|
+
success("Profile updated.");
|
|
1456
|
+
}
|
|
1297
1457
|
|
|
1298
1458
|
// src/intent.command.ts
|
|
1299
1459
|
var INTENT_HELP = `
|
|
@@ -1301,11 +1461,19 @@ Usage:
|
|
|
1301
1461
|
index intent list [--archived] [--limit <n>] List your signals
|
|
1302
1462
|
index intent show <id> Show signal details (accepts short ID)
|
|
1303
1463
|
index intent create <content> Create a signal from text
|
|
1464
|
+
index intent update <id> <content> Update a signal's description
|
|
1304
1465
|
index intent archive <id> Archive a signal (accepts short ID)
|
|
1466
|
+
index intent link <id> <network-id> Link a signal to a network
|
|
1467
|
+
index intent unlink <id> <network-id> Unlink a signal from a network
|
|
1468
|
+
index intent links <id> Show linked networks for a signal
|
|
1305
1469
|
`;
|
|
1306
1470
|
async function handleIntent(client, subcommand, options) {
|
|
1307
1471
|
if (!subcommand) {
|
|
1308
|
-
|
|
1472
|
+
if (options.json) {
|
|
1473
|
+
console.log(JSON.stringify({ error: "No subcommand provided" }));
|
|
1474
|
+
} else {
|
|
1475
|
+
console.log(INTENT_HELP);
|
|
1476
|
+
}
|
|
1309
1477
|
return;
|
|
1310
1478
|
}
|
|
1311
1479
|
switch (subcommand) {
|
|
@@ -1314,6 +1482,10 @@ async function handleIntent(client, subcommand, options) {
|
|
|
1314
1482
|
archived: options.archived,
|
|
1315
1483
|
limit: options.limit
|
|
1316
1484
|
});
|
|
1485
|
+
if (options.json) {
|
|
1486
|
+
console.log(JSON.stringify(result));
|
|
1487
|
+
return;
|
|
1488
|
+
}
|
|
1317
1489
|
heading("Signals");
|
|
1318
1490
|
intentTable(result.intents);
|
|
1319
1491
|
if (result.pagination.total > 0) {
|
|
@@ -1329,6 +1501,10 @@ async function handleIntent(client, subcommand, options) {
|
|
|
1329
1501
|
return;
|
|
1330
1502
|
}
|
|
1331
1503
|
const intent = await client.getIntent(options.intentId);
|
|
1504
|
+
if (options.json) {
|
|
1505
|
+
console.log(JSON.stringify(intent));
|
|
1506
|
+
return;
|
|
1507
|
+
}
|
|
1332
1508
|
intentCard(intent);
|
|
1333
1509
|
return;
|
|
1334
1510
|
}
|
|
@@ -1339,81 +1515,236 @@ async function handleIntent(client, subcommand, options) {
|
|
|
1339
1515
|
}
|
|
1340
1516
|
info("Processing signal...");
|
|
1341
1517
|
const result = await client.processIntent(options.intentContent);
|
|
1518
|
+
if (options.json) {
|
|
1519
|
+
console.log(JSON.stringify(result));
|
|
1520
|
+
return;
|
|
1521
|
+
}
|
|
1342
1522
|
success("Signal processed successfully.");
|
|
1343
1523
|
if (result.message) {
|
|
1344
1524
|
dim(` ${result.message}`);
|
|
1345
1525
|
}
|
|
1346
1526
|
return;
|
|
1347
1527
|
}
|
|
1528
|
+
case "update": {
|
|
1529
|
+
if (!options.intentId) {
|
|
1530
|
+
error("Missing signal ID. Usage: index intent update <id> <content>", 1);
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1533
|
+
if (!options.intentContent) {
|
|
1534
|
+
error("Missing content. Usage: index intent update <id> <content>", 1);
|
|
1535
|
+
return;
|
|
1536
|
+
}
|
|
1537
|
+
info("Updating signal...");
|
|
1538
|
+
const result = await client.callTool("update_intent", {
|
|
1539
|
+
intentId: options.intentId,
|
|
1540
|
+
newDescription: options.intentContent
|
|
1541
|
+
});
|
|
1542
|
+
if (options.json) {
|
|
1543
|
+
console.log(JSON.stringify(result));
|
|
1544
|
+
return;
|
|
1545
|
+
}
|
|
1546
|
+
if (!result.success) {
|
|
1547
|
+
error(result.error ?? "Failed to update signal", 1);
|
|
1548
|
+
return;
|
|
1549
|
+
}
|
|
1550
|
+
success("Signal updated.");
|
|
1551
|
+
return;
|
|
1552
|
+
}
|
|
1348
1553
|
case "archive": {
|
|
1349
1554
|
if (!options.intentId) {
|
|
1350
1555
|
error("Missing signal ID. Usage: index intent archive <id>", 1);
|
|
1351
1556
|
return;
|
|
1352
1557
|
}
|
|
1353
1558
|
await client.archiveIntent(options.intentId);
|
|
1559
|
+
if (options.json) {
|
|
1560
|
+
console.log(JSON.stringify({ success: true }));
|
|
1561
|
+
return;
|
|
1562
|
+
}
|
|
1354
1563
|
success(`Signal ${options.intentId} archived.`);
|
|
1355
1564
|
return;
|
|
1356
1565
|
}
|
|
1566
|
+
case "link": {
|
|
1567
|
+
if (!options.intentId || !options.targetId) {
|
|
1568
|
+
error("Usage: index intent link <intent-id> <network-id>", 1);
|
|
1569
|
+
return;
|
|
1570
|
+
}
|
|
1571
|
+
const result = await client.callTool("create_intent_index", {
|
|
1572
|
+
intentId: options.intentId,
|
|
1573
|
+
indexId: options.targetId
|
|
1574
|
+
});
|
|
1575
|
+
if (options.json) {
|
|
1576
|
+
console.log(JSON.stringify(result));
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1579
|
+
if (!result.success) {
|
|
1580
|
+
error(result.error ?? "Failed to link signal", 1);
|
|
1581
|
+
return;
|
|
1582
|
+
}
|
|
1583
|
+
success("Signal linked to network.");
|
|
1584
|
+
return;
|
|
1585
|
+
}
|
|
1586
|
+
case "unlink": {
|
|
1587
|
+
if (!options.intentId || !options.targetId) {
|
|
1588
|
+
error("Usage: index intent unlink <intent-id> <network-id>", 1);
|
|
1589
|
+
return;
|
|
1590
|
+
}
|
|
1591
|
+
const result = await client.callTool("delete_intent_index", {
|
|
1592
|
+
intentId: options.intentId,
|
|
1593
|
+
indexId: options.targetId
|
|
1594
|
+
});
|
|
1595
|
+
if (options.json) {
|
|
1596
|
+
console.log(JSON.stringify(result));
|
|
1597
|
+
return;
|
|
1598
|
+
}
|
|
1599
|
+
if (!result.success) {
|
|
1600
|
+
error(result.error ?? "Failed to unlink signal", 1);
|
|
1601
|
+
return;
|
|
1602
|
+
}
|
|
1603
|
+
success("Signal unlinked from network.");
|
|
1604
|
+
return;
|
|
1605
|
+
}
|
|
1606
|
+
case "links": {
|
|
1607
|
+
if (!options.intentId) {
|
|
1608
|
+
error("Missing signal ID. Usage: index intent links <id>", 1);
|
|
1609
|
+
return;
|
|
1610
|
+
}
|
|
1611
|
+
const result = await client.callTool("read_intent_indexes", {
|
|
1612
|
+
intentId: options.intentId
|
|
1613
|
+
});
|
|
1614
|
+
if (options.json) {
|
|
1615
|
+
console.log(JSON.stringify(result));
|
|
1616
|
+
return;
|
|
1617
|
+
}
|
|
1618
|
+
if (!result.success) {
|
|
1619
|
+
error(result.error ?? "Failed to read linked networks", 1);
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1622
|
+
const data = result.data;
|
|
1623
|
+
heading("Linked Networks");
|
|
1624
|
+
if (!data.indexes?.length) {
|
|
1625
|
+
dim(" No linked networks.");
|
|
1626
|
+
} else {
|
|
1627
|
+
for (const idx of data.indexes) {
|
|
1628
|
+
const score = idx.relevancyScore !== undefined ? ` (${idx.relevancyScore.toFixed(2)})` : "";
|
|
1629
|
+
console.log(` ${idx.title} ${DIM}${idx.indexId.slice(0, 8)}${score}${RESET}`);
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
console.log();
|
|
1633
|
+
return;
|
|
1634
|
+
}
|
|
1357
1635
|
}
|
|
1358
1636
|
}
|
|
1359
1637
|
|
|
1360
1638
|
// src/opportunity.command.ts
|
|
1361
1639
|
var OPPORTUNITY_HELP = `
|
|
1362
1640
|
Usage:
|
|
1363
|
-
index opportunity list
|
|
1364
|
-
index opportunity list --status <s>
|
|
1365
|
-
index opportunity list --limit <n>
|
|
1366
|
-
index opportunity show <id>
|
|
1367
|
-
index opportunity accept <id>
|
|
1368
|
-
index opportunity reject <id>
|
|
1641
|
+
index opportunity list List your opportunities
|
|
1642
|
+
index opportunity list --status <s> Filter by status (pending|accepted|rejected|expired)
|
|
1643
|
+
index opportunity list --limit <n> Limit results
|
|
1644
|
+
index opportunity show <id> Show full opportunity details (accepts short ID)
|
|
1645
|
+
index opportunity accept <id> Accept an opportunity (accepts short ID)
|
|
1646
|
+
index opportunity reject <id> Reject an opportunity (accepts short ID)
|
|
1647
|
+
index opportunity discover <query> Discover opportunities by search query
|
|
1648
|
+
index opportunity discover --target <uid> <q> Discover for a specific user
|
|
1649
|
+
index opportunity discover --introduce <a> <b> Introduce two users
|
|
1369
1650
|
`;
|
|
1370
1651
|
async function handleOpportunity(client, subcommand, options) {
|
|
1371
1652
|
if (!subcommand) {
|
|
1372
|
-
|
|
1653
|
+
if (options.json) {
|
|
1654
|
+
console.log(JSON.stringify({ error: "No subcommand provided" }));
|
|
1655
|
+
} else {
|
|
1656
|
+
console.log(OPPORTUNITY_HELP);
|
|
1657
|
+
}
|
|
1373
1658
|
return;
|
|
1374
1659
|
}
|
|
1375
1660
|
switch (subcommand) {
|
|
1376
1661
|
case "list":
|
|
1377
|
-
await opportunityList(client, options.status, options.limit);
|
|
1662
|
+
await opportunityList(client, options.status, options.limit, options.json);
|
|
1378
1663
|
return;
|
|
1379
1664
|
case "show":
|
|
1380
1665
|
if (!options.targetId) {
|
|
1381
1666
|
error("Missing opportunity ID. Usage: index opportunity show <id>", 1);
|
|
1382
1667
|
return;
|
|
1383
1668
|
}
|
|
1384
|
-
await opportunityShow(client, options.targetId);
|
|
1669
|
+
await opportunityShow(client, options.targetId, options.json);
|
|
1385
1670
|
return;
|
|
1386
1671
|
case "accept":
|
|
1387
1672
|
if (!options.targetId) {
|
|
1388
1673
|
error("Missing opportunity ID. Usage: index opportunity accept <id>", 1);
|
|
1389
1674
|
return;
|
|
1390
1675
|
}
|
|
1391
|
-
await opportunityStatusUpdate(client, options.targetId, "accepted");
|
|
1676
|
+
await opportunityStatusUpdate(client, options.targetId, "accepted", options.json);
|
|
1392
1677
|
return;
|
|
1393
1678
|
case "reject":
|
|
1394
1679
|
if (!options.targetId) {
|
|
1395
1680
|
error("Missing opportunity ID. Usage: index opportunity reject <id>", 1);
|
|
1396
1681
|
return;
|
|
1397
1682
|
}
|
|
1398
|
-
await opportunityStatusUpdate(client, options.targetId, "rejected");
|
|
1683
|
+
await opportunityStatusUpdate(client, options.targetId, "rejected", options.json);
|
|
1684
|
+
return;
|
|
1685
|
+
case "discover": {
|
|
1686
|
+
const query = options.positionals?.join(" ");
|
|
1687
|
+
if (!query && !options.introduce) {
|
|
1688
|
+
error("Usage: index opportunity discover <query>", 1);
|
|
1689
|
+
return;
|
|
1690
|
+
}
|
|
1691
|
+
info("Discovering opportunities...");
|
|
1692
|
+
const toolQuery = {};
|
|
1693
|
+
if (options.introduce) {
|
|
1694
|
+
toolQuery.mode = "introduction";
|
|
1695
|
+
toolQuery.sourceUserId = options.introduce;
|
|
1696
|
+
toolQuery.targetUserId = options.positionals?.[0];
|
|
1697
|
+
} else if (options.target) {
|
|
1698
|
+
toolQuery.mode = "direct";
|
|
1699
|
+
toolQuery.targetUserId = options.target;
|
|
1700
|
+
toolQuery.searchQuery = query;
|
|
1701
|
+
} else {
|
|
1702
|
+
toolQuery.searchQuery = query;
|
|
1703
|
+
}
|
|
1704
|
+
const result = await client.callTool("create_opportunities", toolQuery);
|
|
1705
|
+
if (options.json) {
|
|
1706
|
+
console.log(JSON.stringify(result));
|
|
1707
|
+
return;
|
|
1708
|
+
}
|
|
1709
|
+
if (!result.success) {
|
|
1710
|
+
error(result.error ?? "Discovery failed", 1);
|
|
1711
|
+
return;
|
|
1712
|
+
}
|
|
1713
|
+
success("Discovery complete.");
|
|
1714
|
+
const data = result.data;
|
|
1715
|
+
if (data?.message)
|
|
1716
|
+
dim(` ${data.message}`);
|
|
1399
1717
|
return;
|
|
1718
|
+
}
|
|
1400
1719
|
default:
|
|
1401
1720
|
error(`Unknown subcommand: ${subcommand}`, 1);
|
|
1402
1721
|
return;
|
|
1403
1722
|
}
|
|
1404
1723
|
}
|
|
1405
|
-
async function opportunityList(client, status2, limit) {
|
|
1724
|
+
async function opportunityList(client, status2, limit, json) {
|
|
1406
1725
|
const opportunities = await client.listOpportunities({ status: status2, limit });
|
|
1726
|
+
if (json) {
|
|
1727
|
+
console.log(JSON.stringify(opportunities));
|
|
1728
|
+
return;
|
|
1729
|
+
}
|
|
1407
1730
|
heading("Opportunities");
|
|
1408
1731
|
opportunityTable(opportunities);
|
|
1409
1732
|
console.log();
|
|
1410
1733
|
}
|
|
1411
|
-
async function opportunityShow(client, id) {
|
|
1734
|
+
async function opportunityShow(client, id, json) {
|
|
1412
1735
|
const opportunity = await client.getOpportunity(id);
|
|
1736
|
+
if (json) {
|
|
1737
|
+
console.log(JSON.stringify(opportunity));
|
|
1738
|
+
return;
|
|
1739
|
+
}
|
|
1413
1740
|
opportunityCard(opportunity);
|
|
1414
1741
|
}
|
|
1415
|
-
async function opportunityStatusUpdate(client, id, status2) {
|
|
1416
|
-
await client.updateOpportunityStatus(id, status2);
|
|
1742
|
+
async function opportunityStatusUpdate(client, id, status2, json) {
|
|
1743
|
+
const result = await client.updateOpportunityStatus(id, status2);
|
|
1744
|
+
if (json) {
|
|
1745
|
+
console.log(JSON.stringify(result));
|
|
1746
|
+
return;
|
|
1747
|
+
}
|
|
1417
1748
|
const label = status2 === "accepted" ? "accepted" : "rejected";
|
|
1418
1749
|
success(`Opportunity ${label}.`);
|
|
1419
1750
|
}
|
|
@@ -1425,6 +1756,9 @@ Network Commands:
|
|
|
1425
1756
|
index network create <name> Create a new network
|
|
1426
1757
|
index network create <name> --prompt Create with a description
|
|
1427
1758
|
index network show <id|key> Show network details and members
|
|
1759
|
+
index network update <id> [--title <t>] [--prompt <p>]
|
|
1760
|
+
Update a network
|
|
1761
|
+
index network delete <id> Delete a network
|
|
1428
1762
|
index network join <id|key> Join a public network
|
|
1429
1763
|
index network leave <id|key> Leave a network
|
|
1430
1764
|
index network invite <id|key> <email> Invite a user by email
|
|
@@ -1450,6 +1784,12 @@ async function handleNetwork(client, subcommand, positionals, options) {
|
|
|
1450
1784
|
case "leave":
|
|
1451
1785
|
await networkLeave(client, positionals[0]);
|
|
1452
1786
|
return;
|
|
1787
|
+
case "update":
|
|
1788
|
+
await networkUpdate(client, positionals[0], options);
|
|
1789
|
+
return;
|
|
1790
|
+
case "delete":
|
|
1791
|
+
await networkDelete(client, positionals[0]);
|
|
1792
|
+
return;
|
|
1453
1793
|
case "invite":
|
|
1454
1794
|
await networkInvite(client, positionals[0], positionals[1]);
|
|
1455
1795
|
return;
|
|
@@ -1505,6 +1845,39 @@ async function networkLeave(client, id) {
|
|
|
1505
1845
|
await client.leaveNetwork(id);
|
|
1506
1846
|
success("Left network.");
|
|
1507
1847
|
}
|
|
1848
|
+
async function networkUpdate(client, id, options) {
|
|
1849
|
+
if (!id) {
|
|
1850
|
+
error("Usage: index network update <id> [--title <t>] [--prompt <p>]", 1);
|
|
1851
|
+
return;
|
|
1852
|
+
}
|
|
1853
|
+
const settings = {};
|
|
1854
|
+
if (options.title)
|
|
1855
|
+
settings.title = options.title;
|
|
1856
|
+
if (options.prompt)
|
|
1857
|
+
settings.prompt = options.prompt;
|
|
1858
|
+
if (Object.keys(settings).length === 0) {
|
|
1859
|
+
error("Provide at least --title or --prompt. Usage: index network update <id> [--title <t>] [--prompt <p>]", 1);
|
|
1860
|
+
return;
|
|
1861
|
+
}
|
|
1862
|
+
const result = await client.callTool("update_index", { indexId: id, settings });
|
|
1863
|
+
if (!result.success) {
|
|
1864
|
+
error(result.error ?? "Network update failed", 1);
|
|
1865
|
+
return;
|
|
1866
|
+
}
|
|
1867
|
+
success("Network updated.");
|
|
1868
|
+
}
|
|
1869
|
+
async function networkDelete(client, id) {
|
|
1870
|
+
if (!id) {
|
|
1871
|
+
error("Usage: index network delete <id>", 1);
|
|
1872
|
+
return;
|
|
1873
|
+
}
|
|
1874
|
+
const result = await client.callTool("delete_index", { indexId: id });
|
|
1875
|
+
if (!result.success) {
|
|
1876
|
+
error(result.error ?? "Network deletion failed", 1);
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1879
|
+
success("Network deleted.");
|
|
1880
|
+
}
|
|
1508
1881
|
async function networkInvite(client, id, email) {
|
|
1509
1882
|
if (!id || !email) {
|
|
1510
1883
|
error("Usage: index network invite <id> <email>", 1);
|
|
@@ -1891,6 +2264,175 @@ async function handleStreamError(response) {
|
|
|
1891
2264
|
error(body.error ?? `HTTP ${response.status}`, 1);
|
|
1892
2265
|
}
|
|
1893
2266
|
|
|
2267
|
+
// src/contact.command.ts
|
|
2268
|
+
var CONTACT_HELP = `
|
|
2269
|
+
Usage:
|
|
2270
|
+
index contact list List your contacts
|
|
2271
|
+
index contact add <email> [--name <n>] Add a contact by email
|
|
2272
|
+
index contact remove <email> Remove a contact
|
|
2273
|
+
index contact import --gmail Import contacts from Gmail
|
|
2274
|
+
`;
|
|
2275
|
+
async function handleContact(client, subcommand, positionals, options) {
|
|
2276
|
+
if (!subcommand) {
|
|
2277
|
+
if (options.json) {
|
|
2278
|
+
console.log(JSON.stringify({ error: "No subcommand provided" }));
|
|
2279
|
+
} else {
|
|
2280
|
+
console.log(CONTACT_HELP);
|
|
2281
|
+
}
|
|
2282
|
+
return;
|
|
2283
|
+
}
|
|
2284
|
+
switch (subcommand) {
|
|
2285
|
+
case "list": {
|
|
2286
|
+
const result = await client.callTool("list_contacts", {});
|
|
2287
|
+
if (options.json) {
|
|
2288
|
+
console.log(JSON.stringify(result));
|
|
2289
|
+
return;
|
|
2290
|
+
}
|
|
2291
|
+
if (!result.success) {
|
|
2292
|
+
error(result.error ?? "Failed to list contacts", 1);
|
|
2293
|
+
return;
|
|
2294
|
+
}
|
|
2295
|
+
const data = result.data;
|
|
2296
|
+
heading("Contacts");
|
|
2297
|
+
contactTable(data.contacts);
|
|
2298
|
+
dim(`
|
|
2299
|
+
${data.count} contact${data.count !== 1 ? "s" : ""}`);
|
|
2300
|
+
console.log();
|
|
2301
|
+
return;
|
|
2302
|
+
}
|
|
2303
|
+
case "add": {
|
|
2304
|
+
const email = positionals[0];
|
|
2305
|
+
if (!email) {
|
|
2306
|
+
error("Missing email. Usage: index contact add <email>", 1);
|
|
2307
|
+
return;
|
|
2308
|
+
}
|
|
2309
|
+
const result = await client.callTool("add_contact", { email, name: options.name });
|
|
2310
|
+
if (options.json) {
|
|
2311
|
+
console.log(JSON.stringify(result));
|
|
2312
|
+
return;
|
|
2313
|
+
}
|
|
2314
|
+
if (!result.success) {
|
|
2315
|
+
error(result.error ?? "Failed to add contact", 1);
|
|
2316
|
+
return;
|
|
2317
|
+
}
|
|
2318
|
+
const data = result.data;
|
|
2319
|
+
success(data.message);
|
|
2320
|
+
return;
|
|
2321
|
+
}
|
|
2322
|
+
case "remove": {
|
|
2323
|
+
const email = positionals[0];
|
|
2324
|
+
if (!email) {
|
|
2325
|
+
error("Missing email. Usage: index contact remove <email>", 1);
|
|
2326
|
+
return;
|
|
2327
|
+
}
|
|
2328
|
+
const listResult = await client.callTool("list_contacts", {});
|
|
2329
|
+
if (!listResult.success) {
|
|
2330
|
+
error("Failed to resolve contact", 1);
|
|
2331
|
+
return;
|
|
2332
|
+
}
|
|
2333
|
+
const contacts = listResult.data.contacts;
|
|
2334
|
+
const match = contacts.find((c) => c.email.toLowerCase() === email.toLowerCase());
|
|
2335
|
+
if (!match) {
|
|
2336
|
+
error(`No contact found with email: ${email}`, 1);
|
|
2337
|
+
return;
|
|
2338
|
+
}
|
|
2339
|
+
const result = await client.callTool("remove_contact", { contactUserId: match.userId });
|
|
2340
|
+
if (options.json) {
|
|
2341
|
+
console.log(JSON.stringify(result));
|
|
2342
|
+
return;
|
|
2343
|
+
}
|
|
2344
|
+
if (!result.success) {
|
|
2345
|
+
error(result.error ?? "Failed to remove contact", 1);
|
|
2346
|
+
return;
|
|
2347
|
+
}
|
|
2348
|
+
success(`Removed ${email} from contacts.`);
|
|
2349
|
+
return;
|
|
2350
|
+
}
|
|
2351
|
+
case "import": {
|
|
2352
|
+
if (options.gmail) {
|
|
2353
|
+
const result = await client.callTool("import_gmail_contacts", {});
|
|
2354
|
+
if (options.json) {
|
|
2355
|
+
console.log(JSON.stringify(result));
|
|
2356
|
+
return;
|
|
2357
|
+
}
|
|
2358
|
+
if (!result.success) {
|
|
2359
|
+
error(result.error ?? "Failed to import Gmail contacts", 1);
|
|
2360
|
+
return;
|
|
2361
|
+
}
|
|
2362
|
+
const data = result.data;
|
|
2363
|
+
success(data.message);
|
|
2364
|
+
} else {
|
|
2365
|
+
error("Specify import source: --gmail", 1);
|
|
2366
|
+
}
|
|
2367
|
+
return;
|
|
2368
|
+
}
|
|
2369
|
+
default: {
|
|
2370
|
+
if (options.json) {
|
|
2371
|
+
console.log(JSON.stringify({ error: `Unknown subcommand: ${subcommand}` }));
|
|
2372
|
+
} else {
|
|
2373
|
+
error(`Unknown subcommand: ${subcommand}`);
|
|
2374
|
+
console.log(CONTACT_HELP);
|
|
2375
|
+
}
|
|
2376
|
+
return;
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
|
|
2381
|
+
// src/scrape.command.ts
|
|
2382
|
+
async function handleScrape(client, positionals, options) {
|
|
2383
|
+
const url = positionals[0];
|
|
2384
|
+
if (!url) {
|
|
2385
|
+
error("Usage: index scrape <url> [--objective <text>]", 1);
|
|
2386
|
+
return;
|
|
2387
|
+
}
|
|
2388
|
+
info(`Scraping ${url}...`);
|
|
2389
|
+
const result = await client.callTool("scrape_url", { url, objective: options.objective });
|
|
2390
|
+
if (options.json) {
|
|
2391
|
+
console.log(JSON.stringify(result));
|
|
2392
|
+
return;
|
|
2393
|
+
}
|
|
2394
|
+
if (!result.success) {
|
|
2395
|
+
error(result.error ?? "Scrape failed", 1);
|
|
2396
|
+
return;
|
|
2397
|
+
}
|
|
2398
|
+
const data = result.data;
|
|
2399
|
+
heading(`Content from ${data.url}`);
|
|
2400
|
+
console.log(data.content);
|
|
2401
|
+
dim(`
|
|
2402
|
+
${data.contentLength} characters extracted`);
|
|
2403
|
+
console.log();
|
|
2404
|
+
}
|
|
2405
|
+
|
|
2406
|
+
// src/sync.command.ts
|
|
2407
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2408
|
+
import { homedir as homedir2 } from "node:os";
|
|
2409
|
+
import { join as join2 } from "node:path";
|
|
2410
|
+
async function handleSync(client, options) {
|
|
2411
|
+
if (!options.json)
|
|
2412
|
+
info("Syncing context...");
|
|
2413
|
+
const [profile, networks, intents, contacts] = await Promise.all([
|
|
2414
|
+
client.callTool("read_user_profiles", {}),
|
|
2415
|
+
client.callTool("read_indexes", {}),
|
|
2416
|
+
client.callTool("read_intents", {}),
|
|
2417
|
+
client.callTool("list_contacts", {})
|
|
2418
|
+
]);
|
|
2419
|
+
const context = {
|
|
2420
|
+
syncedAt: new Date().toISOString(),
|
|
2421
|
+
profile: profile.success ? profile.data : null,
|
|
2422
|
+
networks: networks.success ? networks.data : null,
|
|
2423
|
+
intents: intents.success ? intents.data : null,
|
|
2424
|
+
contacts: contacts.success ? contacts.data : null
|
|
2425
|
+
};
|
|
2426
|
+
if (options.json) {
|
|
2427
|
+
console.log(JSON.stringify(context));
|
|
2428
|
+
return;
|
|
2429
|
+
}
|
|
2430
|
+
const dir = join2(homedir2(), ".index");
|
|
2431
|
+
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
2432
|
+
writeFileSync(join2(dir, "context.json"), JSON.stringify(context, null, 2), { mode: 384 });
|
|
2433
|
+
success("Context synced to ~/.index/context.json");
|
|
2434
|
+
}
|
|
2435
|
+
|
|
1894
2436
|
// src/main.ts
|
|
1895
2437
|
var DEFAULT_API_URL = "https://protocol.index.network";
|
|
1896
2438
|
var DEFAULT_APP_URL = "https://index.network";
|
|
@@ -1914,22 +2456,43 @@ Usage:
|
|
|
1914
2456
|
index profile Show your profile
|
|
1915
2457
|
index profile show <user-id> Show another user's profile
|
|
1916
2458
|
index profile sync Regenerate your profile
|
|
2459
|
+
index profile search <query> Search user profiles
|
|
2460
|
+
index profile create [--linkedin <url>] [--github <url>] [--twitter <url>]
|
|
2461
|
+
Create your profile from social URLs
|
|
2462
|
+
index profile update <action> [--details <text>]
|
|
2463
|
+
Update your profile
|
|
1917
2464
|
index intent list [--archived] [--limit <n>] List your signals
|
|
1918
2465
|
index intent show <id> Show signal details
|
|
1919
2466
|
index intent create <content> Create a signal from natural language
|
|
2467
|
+
index intent update <id> <content> Update a signal's description
|
|
1920
2468
|
index intent archive <id> Archive a signal
|
|
2469
|
+
index intent link <id> <network-id> Link a signal to a network
|
|
2470
|
+
index intent unlink <id> <network-id> Unlink a signal from a network
|
|
2471
|
+
index intent links <id> Show linked networks for a signal
|
|
1921
2472
|
index opportunity list List your opportunities
|
|
1922
2473
|
index opportunity list --status <s> Filter by status (pending|accepted|rejected|expired)
|
|
1923
2474
|
index opportunity list --limit <n> Limit results
|
|
1924
2475
|
index opportunity show <id> Show full opportunity details
|
|
1925
2476
|
index opportunity accept <id> Accept an opportunity
|
|
1926
2477
|
index opportunity reject <id> Reject an opportunity
|
|
2478
|
+
index opportunity discover <query> Discover opportunities by search query
|
|
1927
2479
|
index network list List your networks
|
|
1928
2480
|
index network create <name> Create a new network
|
|
1929
2481
|
index network show <id> Show network details and members
|
|
2482
|
+
index network update <id> [--title <t>] [--prompt <p>]
|
|
2483
|
+
Update a network
|
|
2484
|
+
index network delete <id> Delete a network
|
|
1930
2485
|
index network join <id> Join a public network
|
|
1931
2486
|
index network leave <id> Leave a network
|
|
1932
2487
|
index network invite <id> <email> Invite a user by email
|
|
2488
|
+
index contact list List your contacts
|
|
2489
|
+
index contact add <email> Add a contact by email
|
|
2490
|
+
index contact remove <email> Remove a contact
|
|
2491
|
+
index contact import --gmail Import contacts from Gmail
|
|
2492
|
+
index scrape <url> Extract content from a URL
|
|
2493
|
+
index onboarding complete Mark onboarding as complete
|
|
2494
|
+
index sync Sync context to ~/.index/context.json
|
|
2495
|
+
index sync --json Output synced context to stdout
|
|
1933
2496
|
index --help Show this help message
|
|
1934
2497
|
index --version Show version
|
|
1935
2498
|
|
|
@@ -1941,6 +2504,17 @@ Options:
|
|
|
1941
2504
|
--archived Include archived signals (intent list)
|
|
1942
2505
|
--status <status> Filter opportunities by status
|
|
1943
2506
|
--limit <n> Limit number of results
|
|
2507
|
+
--json Output raw JSON instead of formatted text
|
|
2508
|
+
--name <name> Name for contact add
|
|
2509
|
+
--gmail Import source flag for contact import
|
|
2510
|
+
--objective <text> Objective for scrape command
|
|
2511
|
+
--target <uid> Target user for opportunity discover
|
|
2512
|
+
--introduce <uid> Source user for introduction discovery
|
|
2513
|
+
--linkedin <url> LinkedIn URL for profile create
|
|
2514
|
+
--github <url> GitHub URL for profile create
|
|
2515
|
+
--twitter <url> Twitter URL for profile create
|
|
2516
|
+
--title <text> Title for network update
|
|
2517
|
+
--details <text> Details for profile update
|
|
1944
2518
|
`;
|
|
1945
2519
|
async function requireAuth(apiUrlOverride) {
|
|
1946
2520
|
const store = new CredentialStore;
|
|
@@ -2023,26 +2597,39 @@ async function main() {
|
|
|
2023
2597
|
const client = await requireAuth(args.apiUrl);
|
|
2024
2598
|
switch (args.command) {
|
|
2025
2599
|
case "profile":
|
|
2026
|
-
await handleProfile(client, args.subcommand, args.userId ? [args.userId] : []
|
|
2600
|
+
await handleProfile(client, args.subcommand, args.subcommand === "search" || args.subcommand === "update" ? args.positionals ?? [] : args.userId ? [args.userId] : [], {
|
|
2601
|
+
json: args.json,
|
|
2602
|
+
linkedin: args.linkedin,
|
|
2603
|
+
github: args.github,
|
|
2604
|
+
twitter: args.twitter,
|
|
2605
|
+
details: args.details
|
|
2606
|
+
});
|
|
2027
2607
|
return;
|
|
2028
2608
|
case "intent":
|
|
2029
2609
|
await handleIntent(client, args.subcommand, {
|
|
2030
2610
|
intentId: args.intentId,
|
|
2031
2611
|
intentContent: args.intentContent,
|
|
2032
2612
|
archived: args.archived,
|
|
2033
|
-
limit: args.limit
|
|
2613
|
+
limit: args.limit,
|
|
2614
|
+
json: args.json,
|
|
2615
|
+
targetId: args.targetId
|
|
2034
2616
|
});
|
|
2035
2617
|
return;
|
|
2036
2618
|
case "opportunity":
|
|
2037
2619
|
await handleOpportunity(client, args.subcommand, {
|
|
2038
2620
|
targetId: args.targetId,
|
|
2039
2621
|
status: args.status,
|
|
2040
|
-
limit: args.limit
|
|
2622
|
+
limit: args.limit,
|
|
2623
|
+
json: args.json,
|
|
2624
|
+
positionals: args.positionals,
|
|
2625
|
+
target: args.target,
|
|
2626
|
+
introduce: args.introduce
|
|
2041
2627
|
});
|
|
2042
2628
|
return;
|
|
2043
2629
|
case "network":
|
|
2044
2630
|
await handleNetwork(client, args.subcommand, args.positionals ?? [], {
|
|
2045
|
-
prompt: args.prompt
|
|
2631
|
+
prompt: args.prompt,
|
|
2632
|
+
title: args.title
|
|
2046
2633
|
});
|
|
2047
2634
|
return;
|
|
2048
2635
|
case "conversation":
|
|
@@ -2052,6 +2639,34 @@ async function main() {
|
|
|
2052
2639
|
message: args.message
|
|
2053
2640
|
});
|
|
2054
2641
|
return;
|
|
2642
|
+
case "contact":
|
|
2643
|
+
await handleContact(client, args.subcommand, args.positionals ?? [], {
|
|
2644
|
+
json: args.json,
|
|
2645
|
+
name: args.name,
|
|
2646
|
+
gmail: args.gmail
|
|
2647
|
+
});
|
|
2648
|
+
return;
|
|
2649
|
+
case "scrape":
|
|
2650
|
+
await handleScrape(client, args.positionals ?? [], {
|
|
2651
|
+
json: args.json,
|
|
2652
|
+
objective: args.objective
|
|
2653
|
+
});
|
|
2654
|
+
return;
|
|
2655
|
+
case "onboarding":
|
|
2656
|
+
if (args.subcommand === "complete") {
|
|
2657
|
+
const result = await client.callTool("complete_onboarding", {});
|
|
2658
|
+
if (!result.success) {
|
|
2659
|
+
error(result.error ?? "Onboarding completion failed", 1);
|
|
2660
|
+
} else {
|
|
2661
|
+
success("Onboarding completed.");
|
|
2662
|
+
}
|
|
2663
|
+
} else {
|
|
2664
|
+
error("Usage: index onboarding complete", 1);
|
|
2665
|
+
}
|
|
2666
|
+
return;
|
|
2667
|
+
case "sync":
|
|
2668
|
+
await handleSync(client, { json: args.json });
|
|
2669
|
+
return;
|
|
2055
2670
|
}
|
|
2056
2671
|
}
|
|
2057
2672
|
main().catch((err) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@indexnetwork/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Command-line interface for Index Network",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
"publish:all": "bun scripts/publish.ts"
|
|
21
21
|
},
|
|
22
22
|
"optionalDependencies": {
|
|
23
|
-
"@indexnetwork/cli-linux-x64": "0.
|
|
24
|
-
"@indexnetwork/cli-linux-arm64": "0.
|
|
25
|
-
"@indexnetwork/cli-darwin-x64": "0.
|
|
26
|
-
"@indexnetwork/cli-darwin-arm64": "0.
|
|
23
|
+
"@indexnetwork/cli-linux-x64": "0.9.0",
|
|
24
|
+
"@indexnetwork/cli-linux-arm64": "0.9.0",
|
|
25
|
+
"@indexnetwork/cli-darwin-x64": "0.9.0",
|
|
26
|
+
"@indexnetwork/cli-darwin-arm64": "0.9.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/bun": "latest"
|