@indexnetwork/cli 0.8.1 → 0.9.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.
Files changed (3) hide show
  1. package/README.md +110 -0
  2. package/dist/index.js +732 -26
  3. 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,101 @@ 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. The CLI automatically finds shared networks, gathers profiles and intents, then creates the introduction.
193
+
194
+ ```bash
195
+ # Introduce two users to each other
196
+ index opportunity discover --introduce <user-id-a> <user-id-b>
197
+
198
+ # Provide a reason for the introduction
199
+ index opportunity discover --introduce <user-id-a> <user-id-b> "both working on privacy-preserving ML"
200
+ ```
201
+
202
+ ### Scenario 4: Review and act
203
+
204
+ After discovery creates draft opportunities, review and accept/reject them.
205
+
206
+ ```bash
207
+ # List pending opportunities
208
+ index opportunity list --status pending
209
+
210
+ # See full details (reasoning, scores, mutual intents)
211
+ index opportunity show <id>
212
+
213
+ # Accept — starts a conversation thread
214
+ index opportunity accept <id>
215
+
216
+ # Or reject
217
+ index opportunity reject <id>
218
+ ```
219
+
120
220
  ## Options
121
221
 
122
222
  | Flag | Short | Description |
@@ -129,6 +229,13 @@ index network invite <id> user@email # Invite a user by email
129
229
  | `--status <status>` | | Filter opportunities by status |
130
230
  | `--limit <n>` | | Limit number of results |
131
231
  | `--prompt <text>` | `-p` | Network description (for `network create`) |
232
+ | `--title <text>` | | Network title (for `network update`) |
233
+ | `--name <name>` | | Display name (for `contact add`) |
234
+ | `--gmail` | | Import from Gmail (for `contact import`) |
235
+ | `--target <id>` | | Target user ID (for `opportunity discover`) |
236
+ | `--introduce <id>` | | Introduce two users (for `opportunity discover`) |
237
+ | `--objective <text>` | | Focus objective (for `scrape`) |
238
+ | `--json` | | Output raw JSON to stdout |
132
239
  | `--help` | `-h` | Show help |
133
240
  | `--version` | `-v` | Show version |
134
241
 
@@ -170,6 +277,9 @@ cli/
170
277
  intent.command.ts Intent (signal) subcommand handlers
171
278
  opportunity.command.ts Opportunity subcommand handlers
172
279
  network.command.ts Network subcommand handlers
280
+ contact.command.ts Contact subcommand handlers
281
+ scrape.command.ts URL scraping command handler
282
+ sync.command.ts Context sync command handler
173
283
  output/ Terminal formatting, colors, markdown renderer
174
284
  api.client.ts Typed HTTP client for the protocol API
175
285
  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 (positionals[1]) {
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
- console.log(INTENT_HELP);
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,84 +1515,330 @@ 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 List your opportunities
1364
- index opportunity list --status <s> Filter by status (pending|accepted|rejected|expired)
1365
- index opportunity list --limit <n> Limit results
1366
- index opportunity show <id> Show full opportunity details (accepts short ID)
1367
- index opportunity accept <id> Accept an opportunity (accepts short ID)
1368
- index opportunity reject <id> Reject an opportunity (accepts short 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
- console.log(OPPORTUNITY_HELP);
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
+ if (options.introduce) {
1692
+ const userA = options.introduce;
1693
+ const userB = options.positionals?.[0];
1694
+ if (!userB) {
1695
+ error("Usage: index opportunity discover --introduce <userA> <userB>", 1);
1696
+ return;
1697
+ }
1698
+ const hint = options.positionals?.slice(1).join(" ") || undefined;
1699
+ await discoverIntroduction(client, userA, userB, hint, options.json);
1700
+ } else if (options.target) {
1701
+ info("Discovering opportunities...");
1702
+ const result = await client.callTool("create_opportunities", {
1703
+ targetUserId: options.target,
1704
+ searchQuery: query
1705
+ });
1706
+ if (options.json) {
1707
+ console.log(JSON.stringify(result));
1708
+ return;
1709
+ }
1710
+ if (!result.success) {
1711
+ error(result.error ?? "Discovery failed", 1);
1712
+ return;
1713
+ }
1714
+ success("Discovery complete.");
1715
+ const data = result.data;
1716
+ if (data?.message)
1717
+ dim(` ${data.message}`);
1718
+ } else {
1719
+ info("Discovering opportunities...");
1720
+ const result = await client.callTool("create_opportunities", { searchQuery: query });
1721
+ if (options.json) {
1722
+ console.log(JSON.stringify(result));
1723
+ return;
1724
+ }
1725
+ if (!result.success) {
1726
+ error(result.error ?? "Discovery failed", 1);
1727
+ return;
1728
+ }
1729
+ success("Discovery complete.");
1730
+ const data = result.data;
1731
+ if (data?.message)
1732
+ dim(` ${data.message}`);
1733
+ }
1399
1734
  return;
1735
+ }
1400
1736
  default:
1401
1737
  error(`Unknown subcommand: ${subcommand}`, 1);
1402
1738
  return;
1403
1739
  }
1404
1740
  }
1405
- async function opportunityList(client, status2, limit) {
1741
+ async function opportunityList(client, status2, limit, json) {
1406
1742
  const opportunities = await client.listOpportunities({ status: status2, limit });
1743
+ if (json) {
1744
+ console.log(JSON.stringify(opportunities));
1745
+ return;
1746
+ }
1407
1747
  heading("Opportunities");
1408
1748
  opportunityTable(opportunities);
1409
1749
  console.log();
1410
1750
  }
1411
- async function opportunityShow(client, id) {
1751
+ async function opportunityShow(client, id, json) {
1412
1752
  const opportunity = await client.getOpportunity(id);
1753
+ if (json) {
1754
+ console.log(JSON.stringify(opportunity));
1755
+ return;
1756
+ }
1413
1757
  opportunityCard(opportunity);
1414
1758
  }
1415
- async function opportunityStatusUpdate(client, id, status2) {
1416
- await client.updateOpportunityStatus(id, status2);
1759
+ async function opportunityStatusUpdate(client, id, status2, json) {
1760
+ const result = await client.updateOpportunityStatus(id, status2);
1761
+ if (json) {
1762
+ console.log(JSON.stringify(result));
1763
+ return;
1764
+ }
1417
1765
  const label = status2 === "accepted" ? "accepted" : "rejected";
1418
1766
  success(`Opportunity ${label}.`);
1419
1767
  }
1768
+ async function discoverIntroduction(client, userA, userB, hint, json) {
1769
+ info("Gathering data for introduction...");
1770
+ const [membershipsA, membershipsB] = await Promise.all([
1771
+ client.callTool("read_index_memberships", { userId: userA }),
1772
+ client.callTool("read_index_memberships", { userId: userB })
1773
+ ]);
1774
+ if (!membershipsA.success || !membershipsB.success) {
1775
+ const err = membershipsA.error ?? membershipsB.error ?? "Failed to read memberships";
1776
+ if (json) {
1777
+ console.log(JSON.stringify({ success: false, error: err }));
1778
+ return;
1779
+ }
1780
+ error(err, 1);
1781
+ return;
1782
+ }
1783
+ const indexesA = membershipsA.data?.memberships ?? membershipsA.data?.indexes ?? [];
1784
+ const indexesB = membershipsB.data?.memberships ?? membershipsB.data?.indexes ?? [];
1785
+ const idsA = new Set(indexesA.map((m) => m.indexId));
1786
+ const shared = indexesB.filter((m) => idsA.has(m.indexId));
1787
+ if (shared.length === 0) {
1788
+ const err = "No shared indexes found between these users. They must be members of at least one common network.";
1789
+ if (json) {
1790
+ console.log(JSON.stringify({ success: false, error: err }));
1791
+ return;
1792
+ }
1793
+ error(err, 1);
1794
+ return;
1795
+ }
1796
+ const sharedIndexId = shared[0].indexId;
1797
+ dim(` Found shared network: ${sharedIndexId}`);
1798
+ const [profileA, profileB, intentsA, intentsB] = await Promise.all([
1799
+ client.callTool("read_user_profiles", { userId: userA }),
1800
+ client.callTool("read_user_profiles", { userId: userB }),
1801
+ client.callTool("read_intents", { userId: userA, indexId: sharedIndexId }),
1802
+ client.callTool("read_intents", { userId: userB, indexId: sharedIndexId })
1803
+ ]);
1804
+ const extractProfile = (result2) => {
1805
+ if (!result2.success || !result2.data)
1806
+ return;
1807
+ const d = result2.data;
1808
+ if (d.profile)
1809
+ return d.profile;
1810
+ const profiles = d.profiles;
1811
+ return profiles?.[0]?.profile;
1812
+ };
1813
+ const extractIntents = (result2) => {
1814
+ if (!result2.success || !result2.data)
1815
+ return;
1816
+ const d = result2.data;
1817
+ return d.intents?.map((i) => ({ intentId: i.intentId ?? i.id ?? "", payload: i.payload, summary: i.summary }));
1818
+ };
1819
+ const entities = [
1820
+ { userId: userA, profile: extractProfile(profileA), intents: extractIntents(intentsA), indexId: sharedIndexId },
1821
+ { userId: userB, profile: extractProfile(profileB), intents: extractIntents(intentsB), indexId: sharedIndexId }
1822
+ ];
1823
+ dim(" Profiles and intents gathered. Creating introduction...");
1824
+ const result = await client.callTool("create_opportunities", {
1825
+ partyUserIds: [userA, userB],
1826
+ entities,
1827
+ ...hint ? { hint } : {}
1828
+ });
1829
+ if (json) {
1830
+ console.log(JSON.stringify(result));
1831
+ return;
1832
+ }
1833
+ if (!result.success) {
1834
+ error(result.error ?? "Introduction failed", 1);
1835
+ return;
1836
+ }
1837
+ success("Introduction created.");
1838
+ const data = result.data;
1839
+ if (data?.message)
1840
+ dim(` ${data.message}`);
1841
+ }
1420
1842
 
1421
1843
  // src/network.command.ts
1422
1844
  var NETWORK_HELP = `
@@ -1425,6 +1847,9 @@ Network Commands:
1425
1847
  index network create <name> Create a new network
1426
1848
  index network create <name> --prompt Create with a description
1427
1849
  index network show <id|key> Show network details and members
1850
+ index network update <id> [--title <t>] [--prompt <p>]
1851
+ Update a network
1852
+ index network delete <id> Delete a network
1428
1853
  index network join <id|key> Join a public network
1429
1854
  index network leave <id|key> Leave a network
1430
1855
  index network invite <id|key> <email> Invite a user by email
@@ -1450,6 +1875,12 @@ async function handleNetwork(client, subcommand, positionals, options) {
1450
1875
  case "leave":
1451
1876
  await networkLeave(client, positionals[0]);
1452
1877
  return;
1878
+ case "update":
1879
+ await networkUpdate(client, positionals[0], options);
1880
+ return;
1881
+ case "delete":
1882
+ await networkDelete(client, positionals[0]);
1883
+ return;
1453
1884
  case "invite":
1454
1885
  await networkInvite(client, positionals[0], positionals[1]);
1455
1886
  return;
@@ -1505,6 +1936,39 @@ async function networkLeave(client, id) {
1505
1936
  await client.leaveNetwork(id);
1506
1937
  success("Left network.");
1507
1938
  }
1939
+ async function networkUpdate(client, id, options) {
1940
+ if (!id) {
1941
+ error("Usage: index network update <id> [--title <t>] [--prompt <p>]", 1);
1942
+ return;
1943
+ }
1944
+ const settings = {};
1945
+ if (options.title)
1946
+ settings.title = options.title;
1947
+ if (options.prompt)
1948
+ settings.prompt = options.prompt;
1949
+ if (Object.keys(settings).length === 0) {
1950
+ error("Provide at least --title or --prompt. Usage: index network update <id> [--title <t>] [--prompt <p>]", 1);
1951
+ return;
1952
+ }
1953
+ const result = await client.callTool("update_index", { indexId: id, settings });
1954
+ if (!result.success) {
1955
+ error(result.error ?? "Network update failed", 1);
1956
+ return;
1957
+ }
1958
+ success("Network updated.");
1959
+ }
1960
+ async function networkDelete(client, id) {
1961
+ if (!id) {
1962
+ error("Usage: index network delete <id>", 1);
1963
+ return;
1964
+ }
1965
+ const result = await client.callTool("delete_index", { indexId: id });
1966
+ if (!result.success) {
1967
+ error(result.error ?? "Network deletion failed", 1);
1968
+ return;
1969
+ }
1970
+ success("Network deleted.");
1971
+ }
1508
1972
  async function networkInvite(client, id, email) {
1509
1973
  if (!id || !email) {
1510
1974
  error("Usage: index network invite <id> <email>", 1);
@@ -1891,6 +2355,175 @@ async function handleStreamError(response) {
1891
2355
  error(body.error ?? `HTTP ${response.status}`, 1);
1892
2356
  }
1893
2357
 
2358
+ // src/contact.command.ts
2359
+ var CONTACT_HELP = `
2360
+ Usage:
2361
+ index contact list List your contacts
2362
+ index contact add <email> [--name <n>] Add a contact by email
2363
+ index contact remove <email> Remove a contact
2364
+ index contact import --gmail Import contacts from Gmail
2365
+ `;
2366
+ async function handleContact(client, subcommand, positionals, options) {
2367
+ if (!subcommand) {
2368
+ if (options.json) {
2369
+ console.log(JSON.stringify({ error: "No subcommand provided" }));
2370
+ } else {
2371
+ console.log(CONTACT_HELP);
2372
+ }
2373
+ return;
2374
+ }
2375
+ switch (subcommand) {
2376
+ case "list": {
2377
+ const result = await client.callTool("list_contacts", {});
2378
+ if (options.json) {
2379
+ console.log(JSON.stringify(result));
2380
+ return;
2381
+ }
2382
+ if (!result.success) {
2383
+ error(result.error ?? "Failed to list contacts", 1);
2384
+ return;
2385
+ }
2386
+ const data = result.data;
2387
+ heading("Contacts");
2388
+ contactTable(data.contacts);
2389
+ dim(`
2390
+ ${data.count} contact${data.count !== 1 ? "s" : ""}`);
2391
+ console.log();
2392
+ return;
2393
+ }
2394
+ case "add": {
2395
+ const email = positionals[0];
2396
+ if (!email) {
2397
+ error("Missing email. Usage: index contact add <email>", 1);
2398
+ return;
2399
+ }
2400
+ const result = await client.callTool("add_contact", { email, name: options.name });
2401
+ if (options.json) {
2402
+ console.log(JSON.stringify(result));
2403
+ return;
2404
+ }
2405
+ if (!result.success) {
2406
+ error(result.error ?? "Failed to add contact", 1);
2407
+ return;
2408
+ }
2409
+ const data = result.data;
2410
+ success(data.message);
2411
+ return;
2412
+ }
2413
+ case "remove": {
2414
+ const email = positionals[0];
2415
+ if (!email) {
2416
+ error("Missing email. Usage: index contact remove <email>", 1);
2417
+ return;
2418
+ }
2419
+ const listResult = await client.callTool("list_contacts", {});
2420
+ if (!listResult.success) {
2421
+ error("Failed to resolve contact", 1);
2422
+ return;
2423
+ }
2424
+ const contacts = listResult.data.contacts;
2425
+ const match = contacts.find((c) => c.email.toLowerCase() === email.toLowerCase());
2426
+ if (!match) {
2427
+ error(`No contact found with email: ${email}`, 1);
2428
+ return;
2429
+ }
2430
+ const result = await client.callTool("remove_contact", { contactUserId: match.userId });
2431
+ if (options.json) {
2432
+ console.log(JSON.stringify(result));
2433
+ return;
2434
+ }
2435
+ if (!result.success) {
2436
+ error(result.error ?? "Failed to remove contact", 1);
2437
+ return;
2438
+ }
2439
+ success(`Removed ${email} from contacts.`);
2440
+ return;
2441
+ }
2442
+ case "import": {
2443
+ if (options.gmail) {
2444
+ const result = await client.callTool("import_gmail_contacts", {});
2445
+ if (options.json) {
2446
+ console.log(JSON.stringify(result));
2447
+ return;
2448
+ }
2449
+ if (!result.success) {
2450
+ error(result.error ?? "Failed to import Gmail contacts", 1);
2451
+ return;
2452
+ }
2453
+ const data = result.data;
2454
+ success(data.message);
2455
+ } else {
2456
+ error("Specify import source: --gmail", 1);
2457
+ }
2458
+ return;
2459
+ }
2460
+ default: {
2461
+ if (options.json) {
2462
+ console.log(JSON.stringify({ error: `Unknown subcommand: ${subcommand}` }));
2463
+ } else {
2464
+ error(`Unknown subcommand: ${subcommand}`);
2465
+ console.log(CONTACT_HELP);
2466
+ }
2467
+ return;
2468
+ }
2469
+ }
2470
+ }
2471
+
2472
+ // src/scrape.command.ts
2473
+ async function handleScrape(client, positionals, options) {
2474
+ const url = positionals[0];
2475
+ if (!url) {
2476
+ error("Usage: index scrape <url> [--objective <text>]", 1);
2477
+ return;
2478
+ }
2479
+ info(`Scraping ${url}...`);
2480
+ const result = await client.callTool("scrape_url", { url, objective: options.objective });
2481
+ if (options.json) {
2482
+ console.log(JSON.stringify(result));
2483
+ return;
2484
+ }
2485
+ if (!result.success) {
2486
+ error(result.error ?? "Scrape failed", 1);
2487
+ return;
2488
+ }
2489
+ const data = result.data;
2490
+ heading(`Content from ${data.url}`);
2491
+ console.log(data.content);
2492
+ dim(`
2493
+ ${data.contentLength} characters extracted`);
2494
+ console.log();
2495
+ }
2496
+
2497
+ // src/sync.command.ts
2498
+ import { mkdirSync, writeFileSync } from "node:fs";
2499
+ import { homedir as homedir2 } from "node:os";
2500
+ import { join as join2 } from "node:path";
2501
+ async function handleSync(client, options) {
2502
+ if (!options.json)
2503
+ info("Syncing context...");
2504
+ const [profile, networks, intents, contacts] = await Promise.all([
2505
+ client.callTool("read_user_profiles", {}),
2506
+ client.callTool("read_indexes", {}),
2507
+ client.callTool("read_intents", {}),
2508
+ client.callTool("list_contacts", {})
2509
+ ]);
2510
+ const context = {
2511
+ syncedAt: new Date().toISOString(),
2512
+ profile: profile.success ? profile.data : null,
2513
+ networks: networks.success ? networks.data : null,
2514
+ intents: intents.success ? intents.data : null,
2515
+ contacts: contacts.success ? contacts.data : null
2516
+ };
2517
+ if (options.json) {
2518
+ console.log(JSON.stringify(context));
2519
+ return;
2520
+ }
2521
+ const dir = join2(homedir2(), ".index");
2522
+ mkdirSync(dir, { recursive: true, mode: 448 });
2523
+ writeFileSync(join2(dir, "context.json"), JSON.stringify(context, null, 2), { mode: 384 });
2524
+ success("Context synced to ~/.index/context.json");
2525
+ }
2526
+
1894
2527
  // src/main.ts
1895
2528
  var DEFAULT_API_URL = "https://protocol.index.network";
1896
2529
  var DEFAULT_APP_URL = "https://index.network";
@@ -1914,22 +2547,43 @@ Usage:
1914
2547
  index profile Show your profile
1915
2548
  index profile show <user-id> Show another user's profile
1916
2549
  index profile sync Regenerate your profile
2550
+ index profile search <query> Search user profiles
2551
+ index profile create [--linkedin <url>] [--github <url>] [--twitter <url>]
2552
+ Create your profile from social URLs
2553
+ index profile update <action> [--details <text>]
2554
+ Update your profile
1917
2555
  index intent list [--archived] [--limit <n>] List your signals
1918
2556
  index intent show <id> Show signal details
1919
2557
  index intent create <content> Create a signal from natural language
2558
+ index intent update <id> <content> Update a signal's description
1920
2559
  index intent archive <id> Archive a signal
2560
+ index intent link <id> <network-id> Link a signal to a network
2561
+ index intent unlink <id> <network-id> Unlink a signal from a network
2562
+ index intent links <id> Show linked networks for a signal
1921
2563
  index opportunity list List your opportunities
1922
2564
  index opportunity list --status <s> Filter by status (pending|accepted|rejected|expired)
1923
2565
  index opportunity list --limit <n> Limit results
1924
2566
  index opportunity show <id> Show full opportunity details
1925
2567
  index opportunity accept <id> Accept an opportunity
1926
2568
  index opportunity reject <id> Reject an opportunity
2569
+ index opportunity discover <query> Discover opportunities by search query
1927
2570
  index network list List your networks
1928
2571
  index network create <name> Create a new network
1929
2572
  index network show <id> Show network details and members
2573
+ index network update <id> [--title <t>] [--prompt <p>]
2574
+ Update a network
2575
+ index network delete <id> Delete a network
1930
2576
  index network join <id> Join a public network
1931
2577
  index network leave <id> Leave a network
1932
2578
  index network invite <id> <email> Invite a user by email
2579
+ index contact list List your contacts
2580
+ index contact add <email> Add a contact by email
2581
+ index contact remove <email> Remove a contact
2582
+ index contact import --gmail Import contacts from Gmail
2583
+ index scrape <url> Extract content from a URL
2584
+ index onboarding complete Mark onboarding as complete
2585
+ index sync Sync context to ~/.index/context.json
2586
+ index sync --json Output synced context to stdout
1933
2587
  index --help Show this help message
1934
2588
  index --version Show version
1935
2589
 
@@ -1941,6 +2595,17 @@ Options:
1941
2595
  --archived Include archived signals (intent list)
1942
2596
  --status <status> Filter opportunities by status
1943
2597
  --limit <n> Limit number of results
2598
+ --json Output raw JSON instead of formatted text
2599
+ --name <name> Name for contact add
2600
+ --gmail Import source flag for contact import
2601
+ --objective <text> Objective for scrape command
2602
+ --target <uid> Target user for opportunity discover
2603
+ --introduce <uid> Source user for introduction discovery
2604
+ --linkedin <url> LinkedIn URL for profile create
2605
+ --github <url> GitHub URL for profile create
2606
+ --twitter <url> Twitter URL for profile create
2607
+ --title <text> Title for network update
2608
+ --details <text> Details for profile update
1944
2609
  `;
1945
2610
  async function requireAuth(apiUrlOverride) {
1946
2611
  const store = new CredentialStore;
@@ -2023,26 +2688,39 @@ async function main() {
2023
2688
  const client = await requireAuth(args.apiUrl);
2024
2689
  switch (args.command) {
2025
2690
  case "profile":
2026
- await handleProfile(client, args.subcommand, args.userId ? [args.userId] : []);
2691
+ await handleProfile(client, args.subcommand, args.subcommand === "search" || args.subcommand === "update" ? args.positionals ?? [] : args.userId ? [args.userId] : [], {
2692
+ json: args.json,
2693
+ linkedin: args.linkedin,
2694
+ github: args.github,
2695
+ twitter: args.twitter,
2696
+ details: args.details
2697
+ });
2027
2698
  return;
2028
2699
  case "intent":
2029
2700
  await handleIntent(client, args.subcommand, {
2030
2701
  intentId: args.intentId,
2031
2702
  intentContent: args.intentContent,
2032
2703
  archived: args.archived,
2033
- limit: args.limit
2704
+ limit: args.limit,
2705
+ json: args.json,
2706
+ targetId: args.targetId
2034
2707
  });
2035
2708
  return;
2036
2709
  case "opportunity":
2037
2710
  await handleOpportunity(client, args.subcommand, {
2038
2711
  targetId: args.targetId,
2039
2712
  status: args.status,
2040
- limit: args.limit
2713
+ limit: args.limit,
2714
+ json: args.json,
2715
+ positionals: args.positionals,
2716
+ target: args.target,
2717
+ introduce: args.introduce
2041
2718
  });
2042
2719
  return;
2043
2720
  case "network":
2044
2721
  await handleNetwork(client, args.subcommand, args.positionals ?? [], {
2045
- prompt: args.prompt
2722
+ prompt: args.prompt,
2723
+ title: args.title
2046
2724
  });
2047
2725
  return;
2048
2726
  case "conversation":
@@ -2052,6 +2730,34 @@ async function main() {
2052
2730
  message: args.message
2053
2731
  });
2054
2732
  return;
2733
+ case "contact":
2734
+ await handleContact(client, args.subcommand, args.positionals ?? [], {
2735
+ json: args.json,
2736
+ name: args.name,
2737
+ gmail: args.gmail
2738
+ });
2739
+ return;
2740
+ case "scrape":
2741
+ await handleScrape(client, args.positionals ?? [], {
2742
+ json: args.json,
2743
+ objective: args.objective
2744
+ });
2745
+ return;
2746
+ case "onboarding":
2747
+ if (args.subcommand === "complete") {
2748
+ const result = await client.callTool("complete_onboarding", {});
2749
+ if (!result.success) {
2750
+ error(result.error ?? "Onboarding completion failed", 1);
2751
+ } else {
2752
+ success("Onboarding completed.");
2753
+ }
2754
+ } else {
2755
+ error("Usage: index onboarding complete", 1);
2756
+ }
2757
+ return;
2758
+ case "sync":
2759
+ await handleSync(client, { json: args.json });
2760
+ return;
2055
2761
  }
2056
2762
  }
2057
2763
  main().catch((err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indexnetwork/cli",
3
- "version": "0.8.1",
3
+ "version": "0.9.1",
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.8.1",
24
- "@indexnetwork/cli-linux-arm64": "0.8.1",
25
- "@indexnetwork/cli-darwin-x64": "0.8.1",
26
- "@indexnetwork/cli-darwin-arm64": "0.8.1"
23
+ "@indexnetwork/cli-linux-x64": "0.9.1",
24
+ "@indexnetwork/cli-linux-arm64": "0.9.1",
25
+ "@indexnetwork/cli-darwin-x64": "0.9.1",
26
+ "@indexnetwork/cli-darwin-arm64": "0.9.1"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/bun": "latest"