@indexnetwork/cli 0.7.0 → 0.8.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 +61 -45
  2. package/dist/index.js +51 -32
  3. package/package.json +7 -6
package/README.md CHANGED
@@ -2,20 +2,29 @@
2
2
 
3
3
  Command-line interface for [Index Network](https://index.network). Chat with the AI agent, manage signals, and discover opportunities — all from your terminal.
4
4
 
5
- > **Status: v0.5.0**
6
- > Supports `login`, `chat`, `profile`, `intent` (signal management), `opportunity`, and `network` commands.
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g @indexnetwork/cli
9
+ ```
7
10
 
8
11
  ## Quick Start
9
12
 
10
13
  ```bash
11
- # Build the binary
12
- bun run build
13
-
14
14
  # Authenticate (opens browser)
15
- ./dist/index login
15
+ index login
16
+
17
+ # Chat with the AI agent (interactive REPL)
18
+ index conversation
16
19
 
17
- # Start chatting
18
- ./dist/index conversation
20
+ # One-shot message
21
+ index conversation "What opportunities do I have?"
22
+
23
+ # Browse your signals
24
+ index intent list
25
+
26
+ # Review pending opportunities
27
+ index opportunity list
19
28
  ```
20
29
 
21
30
  ## Commands
@@ -40,19 +49,6 @@ Clear stored credentials.
40
49
  index logout
41
50
  ```
42
51
 
43
- ### `index intent`
44
-
45
- Manage your signals (intents). Create signals from natural language, list active signals, view details, and archive signals you no longer need.
46
-
47
- ```bash
48
- index intent list # List active signals
49
- index intent list --archived # Include archived signals
50
- index intent list --limit 5 # Limit to 5 results
51
- index intent show <id> # Show full signal details
52
- index intent create "Looking for a CTO" # Create from natural language
53
- index intent archive <id> # Archive a signal
54
- ```
55
-
56
52
  ### `index conversation`
57
53
 
58
54
  Unified conversation command for AI agent chat and human-to-human messaging. Supports streaming responses, inline markdown formatting, tool call indicators, and special blocks (signal proposals, opportunities).
@@ -79,6 +75,19 @@ index profile show <user-id> # Show another user's profile
79
75
  index profile sync # Regenerate your profile
80
76
  ```
81
77
 
78
+ ### `index intent`
79
+
80
+ Manage your signals (intents). Create signals from natural language, list active signals, view details, and archive signals you no longer need.
81
+
82
+ ```bash
83
+ index intent list # List active signals
84
+ index intent list --archived # Include archived signals
85
+ index intent list --limit 5 # Limit to 5 results
86
+ index intent show <id> # Show full signal details
87
+ index intent create "Looking for a CTO" # Create from natural language
88
+ index intent archive <id> # Archive a signal
89
+ ```
90
+
82
91
  ### `index opportunity`
83
92
 
84
93
  Browse and manage discovered opportunities.
@@ -94,8 +103,6 @@ index opportunity reject <id> # Reject an opportunity
94
103
 
95
104
  Status values: `pending`, `accepted`, `rejected`, `expired`.
96
105
 
97
- The `show` command displays a detailed card with parties (including valency roles: Helper, Seeker, Peer), reasoning, confidence, and presentation text.
98
-
99
106
  ### `index network`
100
107
 
101
108
  Manage networks (communities). List, create, join, leave, and invite members.
@@ -110,15 +117,14 @@ index network leave <id> # Leave a network
110
117
  index network invite <id> user@email # Invite a user by email
111
118
  ```
112
119
 
113
-
114
120
  ## Options
115
121
 
116
122
  | Flag | Short | Description |
117
123
  |------|-------|-------------|
118
- | `--api-url <url>` | | Override API server (default: `http://localhost:3000`) |
124
+ | `--api-url <url>` | | Override API server (default: `https://protocol.index.network`) |
125
+ | `--app-url <url>` | | Override app URL for login (default: `https://index.network`) |
119
126
  | `--token <token>` | `-t` | Provide bearer token directly |
120
127
  | `--session <id>` | `-s` | Resume a specific chat session |
121
- | `--list` | `-l` | List chat sessions |
122
128
  | `--archived` | | Include archived signals (intent list) |
123
129
  | `--status <status>` | | Filter opportunities by status |
124
130
  | `--limit <n>` | | Limit number of results |
@@ -130,34 +136,44 @@ index network invite <id> user@email # Invite a user by email
130
136
 
131
137
  ```bash
132
138
  # Run directly with Bun (no build step)
133
- bun src/main.ts chat
139
+ bun src/main.ts conversation
140
+
141
+ # Build for all platforms
142
+ bun run build
134
143
 
135
- # Build a standalone binary
136
- bun run build # outputs to dist/index
144
+ # Build for current platform only (fast dev builds)
145
+ bun scripts/build.ts --current
137
146
 
138
147
  # Run tests
139
148
  bun test
149
+
150
+ # Dry-run publish
151
+ bun scripts/publish.ts --dry-run
140
152
  ```
141
153
 
142
154
  ### Project Structure
143
155
 
144
156
  ```
145
157
  cli/
158
+ bin/
159
+ index.cjs Bin shim (resolves platform binary or JS fallback)
160
+ npm/
161
+ {os}-{arch}/ Platform-specific packages with precompiled binaries
162
+ scripts/
163
+ build.ts Cross-compilation build script
164
+ publish.ts npm publish orchestration
146
165
  src/
147
- main.ts Entry point, command routing
148
- login.command.ts OAuth flow with local callback server
149
- conversation.command.ts H2A agent chat + H2H messaging + SSE stream parser
150
- network.command.ts Network subcommand handlers
151
- output.ts Terminal formatting, colors, markdown renderer
152
- api.client.ts Typed HTTP client for the protocol API
153
- auth.store.ts Credential persistence (~/.index/credentials.json)
154
- args.parser.ts CLI argument parser (Bun-native parseArgs)
155
- sse.parser.ts Server-Sent Events parser
166
+ main.ts Entry point, command routing
167
+ login.command.ts OAuth flow with local callback server
168
+ conversation.command.ts H2A agent chat + H2H messaging + SSE stream parser
169
+ profile.command.ts Profile subcommand handlers
170
+ intent.command.ts Intent (signal) subcommand handlers
171
+ opportunity.command.ts Opportunity subcommand handlers
172
+ network.command.ts Network subcommand handlers
173
+ output/ Terminal formatting, colors, markdown renderer
174
+ api.client.ts Typed HTTP client for the protocol API
175
+ auth.store.ts Credential persistence (~/.index/credentials.json)
176
+ args.parser.ts CLI argument parser
177
+ sse.parser.ts Server-Sent Events parser
178
+ types.ts Shared type definitions
156
179
  ```
157
-
158
- ## Roadmap
159
-
160
- Commands planned for future iterations:
161
-
162
- - ~~`index network` — Manage indexes and memberships~~ (shipped!)
163
- - ~~`index conversation` — H2H and A2A messaging~~ (shipped!)
package/dist/index.js CHANGED
@@ -265,7 +265,10 @@ class ApiClient {
265
265
  async listNetworks() {
266
266
  const res = await this.get("/api/indexes");
267
267
  const body = await res.json();
268
- return body.indexes;
268
+ return body.indexes.map((n) => ({
269
+ ...n,
270
+ joinPolicy: n.joinPolicy ?? n.permissions?.joinPolicy
271
+ }));
269
272
  }
270
273
  async createNetwork(title, prompt) {
271
274
  const res = await this.post("/api/indexes", {
@@ -278,7 +281,8 @@ class ApiClient {
278
281
  async getNetwork(id) {
279
282
  const res = await this.get(`/api/indexes/${id}`);
280
283
  const body = await res.json();
281
- return body.index;
284
+ const n = body.index;
285
+ return { ...n, joinPolicy: n.joinPolicy ?? n.permissions?.joinPolicy };
282
286
  }
283
287
  async getNetworkMembers(id) {
284
288
  const res = await this.get(`/api/indexes/${id}/members`);
@@ -937,13 +941,15 @@ function intentTable(intents) {
937
941
  dim(" No signals found.");
938
942
  return;
939
943
  }
940
- const descWidth = 50;
944
+ const idWidth = 8;
945
+ const descWidth = 44;
941
946
  const statusWidth = 10;
942
947
  const sourceWidth = 16;
943
948
  const dateWidth = 20;
944
- console.log(` ${BOLD}${"Signal".padEnd(descWidth)} ${"Status".padEnd(statusWidth)} ${"Source".padEnd(sourceWidth)} ${"Created".padEnd(dateWidth)}${RESET}`);
945
- console.log(` ${GRAY}${"-".repeat(descWidth)} ${"-".repeat(statusWidth)} ${"-".repeat(sourceWidth)} ${"-".repeat(dateWidth)}${RESET}`);
949
+ console.log(` ${BOLD}${"ID".padEnd(idWidth)} ${"Signal".padEnd(descWidth)} ${"Status".padEnd(statusWidth)} ${"Source".padEnd(sourceWidth)} ${"Created".padEnd(dateWidth)}${RESET}`);
950
+ console.log(` ${GRAY}${"-".repeat(idWidth)} ${"-".repeat(descWidth)} ${"-".repeat(statusWidth)} ${"-".repeat(sourceWidth)} ${"-".repeat(dateWidth)}${RESET}`);
946
951
  for (const intent of intents) {
952
+ const shortId = intent.id.slice(0, 8);
947
953
  const desc = (intent.summary ?? intent.payload).slice(0, descWidth);
948
954
  const status2 = (intent.status ?? "").padEnd(statusWidth);
949
955
  const source = (intent.sourceType ?? "-").padEnd(sourceWidth);
@@ -953,7 +959,7 @@ function intentTable(intents) {
953
959
  day: "numeric"
954
960
  });
955
961
  const sColor = intent.status === "ACTIVE" ? GREEN : GRAY;
956
- console.log(` ${desc.padEnd(descWidth)} ${sColor}${status2}${RESET} ${GRAY}${source}${RESET} ${GRAY}${date}${RESET}`);
962
+ console.log(` ${CYAN}${shortId}${RESET} ${desc.padEnd(descWidth)} ${sColor}${status2}${RESET} ${GRAY}${source}${RESET} ${GRAY}${date}${RESET}`);
957
963
  }
958
964
  }
959
965
  function intentCard(intent) {
@@ -1020,26 +1026,30 @@ function opportunityTable(opportunities) {
1020
1026
  dim(" No opportunities found.");
1021
1027
  return;
1022
1028
  }
1023
- const nameW = 24;
1024
- const catW = 20;
1029
+ const idW = 8;
1030
+ const nameW = 20;
1031
+ const catW = 18;
1025
1032
  const statusW = 10;
1026
1033
  const confW = 8;
1027
1034
  const dateW = 20;
1028
- process.stdout.write(` ${BOLD}${"Counterparty".padEnd(nameW)} ${"Category".padEnd(catW)} ${"Status".padEnd(statusW)} ${"Conf".padEnd(confW)} ${"Created".padEnd(dateW)}${RESET}
1035
+ process.stdout.write(` ${BOLD}${"ID".padEnd(idW)} ${"Counterparty".padEnd(nameW)} ${"Category".padEnd(catW)} ${"Status".padEnd(statusW)} ${"Conf".padEnd(confW)} ${"Created".padEnd(dateW)}${RESET}
1029
1036
  `);
1030
- process.stdout.write(` ${GRAY}${"-".repeat(nameW)} ${"-".repeat(catW)} ${"-".repeat(statusW)} ${"-".repeat(confW)} ${"-".repeat(dateW)}${RESET}
1037
+ process.stdout.write(` ${GRAY}${"-".repeat(idW)} ${"-".repeat(nameW)} ${"-".repeat(catW)} ${"-".repeat(statusW)} ${"-".repeat(confW)} ${"-".repeat(dateW)}${RESET}
1031
1038
  `);
1032
1039
  for (const opp of opportunities) {
1033
- const name = (opp.counterpartName ?? "Unknown").slice(0, nameW);
1040
+ const shortId = opp.id.slice(0, 8);
1041
+ const fallbackName = opp.actors?.[1]?.name ?? opp.actors?.find((a) => a.name)?.name;
1042
+ const name = (opp.counterpartName ?? fallbackName ?? "Unknown").slice(0, nameW);
1034
1043
  const category = (opp.interpretation?.category ?? "-").slice(0, catW);
1035
1044
  const st = opp.status.slice(0, statusW);
1036
- const conf = opp.interpretation?.confidence != null ? `${opp.interpretation.confidence}%` : "-";
1045
+ const rawConf = opp.interpretation?.confidence;
1046
+ const conf = rawConf != null ? `${Math.round(rawConf <= 1 ? rawConf * 100 : rawConf)}%` : "-";
1037
1047
  const date = opp.createdAt ? new Date(opp.createdAt).toLocaleDateString("en-US", {
1038
1048
  year: "numeric",
1039
1049
  month: "short",
1040
1050
  day: "numeric"
1041
1051
  }) : "-";
1042
- process.stdout.write(` ${name.padEnd(nameW)} ${GRAY}${category.padEnd(catW)}${RESET} ${statusColor(st)}${st.padEnd(statusW)}${RESET} ${GRAY}${conf.padEnd(confW)}${RESET} ${GRAY}${date.padEnd(dateW)}${RESET}
1052
+ process.stdout.write(` ${CYAN}${shortId}${RESET} ${name.padEnd(nameW)} ${GRAY}${category.padEnd(catW)}${RESET} ${statusColor(st)}${st.padEnd(statusW)}${RESET} ${GRAY}${conf.padEnd(confW)}${RESET} ${GRAY}${date.padEnd(dateW)}${RESET}
1043
1053
  `);
1044
1054
  }
1045
1055
  }
@@ -1128,14 +1138,16 @@ function networkTable(networks) {
1128
1138
  dim(" No networks found.");
1129
1139
  return;
1130
1140
  }
1131
- const titleW = 30;
1141
+ const keyW = 24;
1142
+ const titleW = 26;
1132
1143
  const membersW = 8;
1133
1144
  const roleW = 10;
1134
1145
  const policyW = 12;
1135
1146
  const dateW = 18;
1136
- console.log(` ${BOLD}${"Title".padEnd(titleW)} ${"Members".padEnd(membersW)} ${"Role".padEnd(roleW)} ${"Join Policy".padEnd(policyW)} ${"Created".padEnd(dateW)}${RESET}`);
1137
- console.log(` ${GRAY}${"-".repeat(titleW)} ${"-".repeat(membersW)} ${"-".repeat(roleW)} ${"-".repeat(policyW)} ${"-".repeat(dateW)}${RESET}`);
1147
+ console.log(` ${BOLD}${"Key".padEnd(keyW)} ${"Title".padEnd(titleW)} ${"Members".padEnd(membersW)} ${"Role".padEnd(roleW)} ${"Join Policy".padEnd(policyW)} ${"Created".padEnd(dateW)}${RESET}`);
1148
+ console.log(` ${GRAY}${"-".repeat(keyW)} ${"-".repeat(titleW)} ${"-".repeat(membersW)} ${"-".repeat(roleW)} ${"-".repeat(policyW)} ${"-".repeat(dateW)}${RESET}`);
1138
1149
  for (const n of networks) {
1150
+ const key = (n.key ?? n.id.slice(0, 8)).slice(0, keyW);
1139
1151
  const title = n.title.slice(0, titleW);
1140
1152
  const members = String(n.memberCount ?? "-");
1141
1153
  const role = n.role ?? "member";
@@ -1145,13 +1157,16 @@ function networkTable(networks) {
1145
1157
  month: "short",
1146
1158
  day: "numeric"
1147
1159
  }) : "-";
1148
- console.log(` ${title.padEnd(titleW)} ${members.padEnd(membersW)} ${role.padEnd(roleW)} ${policy.padEnd(policyW)} ${GRAY}${date}${RESET}`);
1160
+ console.log(` ${CYAN}${key.padEnd(keyW)}${RESET} ${title.padEnd(titleW)} ${members.padEnd(membersW)} ${role.padEnd(roleW)} ${policy.padEnd(policyW)} ${GRAY}${date}${RESET}`);
1149
1161
  }
1150
1162
  }
1151
1163
  function networkCard(network) {
1152
1164
  console.log();
1153
1165
  console.log(` ${BOLD}${network.title}${RESET}`);
1154
1166
  console.log(` ${GRAY}${"─".repeat(40)}${RESET}`);
1167
+ if (network.key) {
1168
+ console.log(` ${GRAY}Key:${RESET} ${CYAN}${network.key}${RESET}`);
1169
+ }
1155
1170
  console.log(` ${GRAY}ID:${RESET} ${network.id}`);
1156
1171
  if (network.prompt) {
1157
1172
  console.log(` ${GRAY}Prompt:${RESET} ${network.prompt}`);
@@ -1191,19 +1206,20 @@ function conversationTable(conversations) {
1191
1206
  dim(" No conversations found.");
1192
1207
  return;
1193
1208
  }
1194
- const idWidth = 36;
1195
- const participantsWidth = 40;
1209
+ const idWidth = 8;
1210
+ const participantsWidth = 46;
1196
1211
  const dateWidth = 20;
1197
1212
  console.log(` ${BOLD}${"ID".padEnd(idWidth)} ${"Participants".padEnd(participantsWidth)} ${"Created".padEnd(dateWidth)}${RESET}`);
1198
1213
  console.log(` ${GRAY}${"-".repeat(idWidth)} ${"-".repeat(participantsWidth)} ${"-".repeat(dateWidth)}${RESET}`);
1199
1214
  for (const c of conversations) {
1215
+ const shortId = c.id.slice(0, 8);
1200
1216
  const names = c.participants.map((p) => p.user?.name ?? p.participantId).join(", ").slice(0, participantsWidth);
1201
1217
  const date = new Date(c.createdAt).toLocaleDateString("en-US", {
1202
1218
  year: "numeric",
1203
1219
  month: "short",
1204
1220
  day: "numeric"
1205
1221
  });
1206
- console.log(` ${GRAY}${c.id.padEnd(idWidth)}${RESET} ${names.padEnd(participantsWidth)} ${GRAY}${date}${RESET}`);
1222
+ console.log(` ${CYAN}${shortId}${RESET} ${names.padEnd(participantsWidth)} ${GRAY}${date}${RESET}`);
1207
1223
  }
1208
1224
  }
1209
1225
  function conversationCard(conversation) {
@@ -1283,9 +1299,9 @@ async function profileSync(client) {
1283
1299
  var INTENT_HELP = `
1284
1300
  Usage:
1285
1301
  index intent list [--archived] [--limit <n>] List your signals
1286
- index intent show <id> Show signal details
1302
+ index intent show <id> Show signal details (accepts short ID)
1287
1303
  index intent create <content> Create a signal from text
1288
- index intent archive <id> Archive a signal
1304
+ index intent archive <id> Archive a signal (accepts short ID)
1289
1305
  `;
1290
1306
  async function handleIntent(client, subcommand, options) {
1291
1307
  if (!subcommand) {
@@ -1347,9 +1363,9 @@ Usage:
1347
1363
  index opportunity list List your opportunities
1348
1364
  index opportunity list --status <s> Filter by status (pending|accepted|rejected|expired)
1349
1365
  index opportunity list --limit <n> Limit results
1350
- index opportunity show <id> Show full opportunity details
1351
- index opportunity accept <id> Accept an opportunity
1352
- index opportunity reject <id> Reject an opportunity
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)
1353
1369
  `;
1354
1370
  async function handleOpportunity(client, subcommand, options) {
1355
1371
  if (!subcommand) {
@@ -1408,10 +1424,10 @@ Network Commands:
1408
1424
  index network list List your networks
1409
1425
  index network create <name> Create a new network
1410
1426
  index network create <name> --prompt Create with a description
1411
- index network show <id> Show network details and members
1412
- index network join <id> Join a public network
1413
- index network leave <id> Leave a network
1414
- index network invite <id> <email> Invite a user by email
1427
+ index network show <id|key> Show network details and members
1428
+ index network join <id|key> Join a public network
1429
+ index network leave <id|key> Leave a network
1430
+ index network invite <id|key> <email> Invite a user by email
1415
1431
  `;
1416
1432
  async function handleNetwork(client, subcommand, positionals, options) {
1417
1433
  if (!subcommand) {
@@ -1455,6 +1471,9 @@ async function networkCreate(client, name, prompt) {
1455
1471
  }
1456
1472
  const network = await client.createNetwork(name, prompt);
1457
1473
  success(`Network created: ${network.title}`);
1474
+ if (network.key) {
1475
+ dim(` Key: ${network.key}`);
1476
+ }
1458
1477
  dim(` ID: ${network.id}`);
1459
1478
  dim(` Join Policy: ${(network.joinPolicy ?? "invite_only").replace("_", " ")}`);
1460
1479
  }
@@ -1621,10 +1640,10 @@ Conversation Commands:
1621
1640
  index conversation --session <id> Resume a specific chat session
1622
1641
  index conversation sessions List AI chat sessions
1623
1642
  index conversation list List all conversations (H2A + H2H)
1624
- index conversation with <user-id> Open or resume a DM with a user
1625
- index conversation show <id> Show messages in a conversation
1643
+ index conversation with <user-id|key> Open or resume a DM with a user
1644
+ index conversation show <id> Show messages (accepts short ID)
1626
1645
  index conversation show <id> --limit <n> Limit number of messages
1627
- index conversation send <id> <message> Send a message
1646
+ index conversation send <id> <message> Send a message (accepts short ID)
1628
1647
  index conversation stream Listen for real-time events (SSE)
1629
1648
  `;
1630
1649
  async function handleConversation(client, subcommand, positionals, options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indexnetwork/cli",
3
- "version": "0.7.0",
3
+ "version": "0.8.1",
4
4
  "description": "Command-line interface for Index Network",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -9,7 +9,8 @@
9
9
  },
10
10
  "files": [
11
11
  "bin/",
12
- "dist/"
12
+ "dist/",
13
+ "README.md"
13
14
  ],
14
15
  "scripts": {
15
16
  "dev": "bun src/main.ts",
@@ -19,10 +20,10 @@
19
20
  "publish:all": "bun scripts/publish.ts"
20
21
  },
21
22
  "optionalDependencies": {
22
- "@indexnetwork/cli-linux-x64": "0.7.0",
23
- "@indexnetwork/cli-linux-arm64": "0.7.0",
24
- "@indexnetwork/cli-darwin-x64": "0.7.0",
25
- "@indexnetwork/cli-darwin-arm64": "0.7.0"
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"
26
27
  },
27
28
  "devDependencies": {
28
29
  "@types/bun": "latest"