@indexnetwork/cli 0.13.3-rc.62.1 → 0.15.0-rc.64.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -4
- package/dist/index.js +70 -459
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -40,8 +40,7 @@ Words you will see elsewhere in this doc: **network** = a community you are in;
|
|
|
40
40
|
Authenticate with Index Network. Opens a browser window that uses your existing session (or a fresh OAuth flow) to call the session-only, fixed-shape CLI credential endpoint, which mints a 90-day API key while keeping CLI requests on the non-web compatibility surface.
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
|
-
index login # Browser-based auth
|
|
44
|
-
index login --token <jwt> # Legacy manual session token (skip browser)
|
|
43
|
+
index login # Browser-based auth
|
|
45
44
|
index login --api-url <url> # Custom server URL
|
|
46
45
|
```
|
|
47
46
|
|
|
@@ -49,7 +48,7 @@ Credentials are stored in `~/.index/credentials.json`. Current browser login exp
|
|
|
49
48
|
|
|
50
49
|
**Rolling deploy order:** v2 clients require the v2 web bridge and intentionally reject callbacks from older web deployments that cannot return the bound state. On dev, this CLI is an RC: wait for both the API and web deployments to succeed before testing v2 login. Do not relax state validation to make a new CLI work against old web.
|
|
51
50
|
|
|
52
|
-
|
|
51
|
+
The v1 login contract (`session_token` callback, Bearer API-key fallback, `--token` manual flow) is removed. Released v1 binaries and legacy `credentials.json` files without a key ID are treated as signed out; upgrade and run `index login`.
|
|
53
52
|
|
|
54
53
|
### `index logout`
|
|
55
54
|
|
|
@@ -205,7 +204,6 @@ index opportunity reject <id>
|
|
|
205
204
|
| -------------------- | ----- | --------------------------------------------------------------- |
|
|
206
205
|
| `--api-url <url>` | | Override API server (default: `https://protocol.index.network`) |
|
|
207
206
|
| `--app-url <url>` | | Override app URL for login (default: `https://index.network`) |
|
|
208
|
-
| `--token <token>` | `-t` | Provide bearer token directly |
|
|
209
207
|
| `--session <id>` | `-s` | Resume a specific chat session |
|
|
210
208
|
| `--archived` | | Include archived signals (intent list) |
|
|
211
209
|
| `--status <status>` | | Filter opportunities by status |
|
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@ import { spawn } from "node:child_process";
|
|
|
19
19
|
// package.json
|
|
20
20
|
var package_default = {
|
|
21
21
|
name: "@indexnetwork/cli",
|
|
22
|
-
version: "0.
|
|
22
|
+
version: "0.15.0",
|
|
23
23
|
description: "Command-line interface for Index Network",
|
|
24
24
|
license: "MIT",
|
|
25
25
|
type: "module",
|
|
@@ -39,10 +39,10 @@ var package_default = {
|
|
|
39
39
|
"publish:all": "bun scripts/publish.ts"
|
|
40
40
|
},
|
|
41
41
|
optionalDependencies: {
|
|
42
|
-
"@indexnetwork/cli-linux-x64": "0.
|
|
43
|
-
"@indexnetwork/cli-linux-arm64": "0.
|
|
44
|
-
"@indexnetwork/cli-darwin-x64": "0.
|
|
45
|
-
"@indexnetwork/cli-darwin-arm64": "0.
|
|
42
|
+
"@indexnetwork/cli-linux-x64": "0.15.0",
|
|
43
|
+
"@indexnetwork/cli-linux-arm64": "0.15.0",
|
|
44
|
+
"@indexnetwork/cli-darwin-x64": "0.15.0",
|
|
45
|
+
"@indexnetwork/cli-darwin-arm64": "0.15.0"
|
|
46
46
|
},
|
|
47
47
|
devDependencies: {
|
|
48
48
|
"@types/bun": "1.3.14"
|
|
@@ -54,7 +54,7 @@ var KNOWN_COMMANDS = new Set(["login", "logout", "profile", "intent", "opportuni
|
|
|
54
54
|
var OPPORTUNITY_SUBCOMMANDS = new Set(["list", "show", "accept", "reject"]);
|
|
55
55
|
var NEGOTIATION_SUBCOMMANDS = new Set(["list", "show"]);
|
|
56
56
|
var NETWORK_SUBCOMMANDS = new Set(["list", "create", "show", "join", "leave", "invite", "update", "delete"]);
|
|
57
|
-
var CONVERSATION_SUBCOMMANDS = new Set(["list", "with", "show", "send", "stream", "
|
|
57
|
+
var CONVERSATION_SUBCOMMANDS = new Set(["list", "with", "show", "send", "stream", "help"]);
|
|
58
58
|
function parseArgs(args) {
|
|
59
59
|
const result = {
|
|
60
60
|
command: "help",
|
|
@@ -66,13 +66,11 @@ function parseArgs(args) {
|
|
|
66
66
|
let commandIndex = -1;
|
|
67
67
|
for (let j = 0;j < args.length; j++) {
|
|
68
68
|
const a = args[j];
|
|
69
|
-
if (a === "--api-url" || a === "--app-url"
|
|
69
|
+
if (a === "--api-url" || a === "--app-url") {
|
|
70
70
|
if (a === "--api-url")
|
|
71
71
|
result.apiUrl = args[j + 1];
|
|
72
|
-
else if (a === "--app-url")
|
|
73
|
-
result.appUrl = args[j + 1];
|
|
74
72
|
else
|
|
75
|
-
result.
|
|
73
|
+
result.appUrl = args[j + 1];
|
|
76
74
|
j++;
|
|
77
75
|
} else if (a === "--help" || a === "-h") {
|
|
78
76
|
result.command = "help";
|
|
@@ -103,7 +101,6 @@ function parseArgs(args) {
|
|
|
103
101
|
result.list = true;
|
|
104
102
|
i++;
|
|
105
103
|
} else if (arg === "--session" || arg === "-s") {
|
|
106
|
-
result.sessionId = args[i + 1];
|
|
107
104
|
i += 2;
|
|
108
105
|
} else if (arg === "--api-url") {
|
|
109
106
|
result.apiUrl = args[i + 1];
|
|
@@ -111,9 +108,6 @@ function parseArgs(args) {
|
|
|
111
108
|
} else if (arg === "--app-url") {
|
|
112
109
|
result.appUrl = args[i + 1];
|
|
113
110
|
i += 2;
|
|
114
|
-
} else if (arg === "--token" || arg === "-t") {
|
|
115
|
-
result.token = args[i + 1];
|
|
116
|
-
i += 2;
|
|
117
111
|
} else if (arg === "--archived") {
|
|
118
112
|
result.archived = true;
|
|
119
113
|
i++;
|
|
@@ -241,8 +235,6 @@ function parseArgs(args) {
|
|
|
241
235
|
if (positionals.length > 0 && CONVERSATION_SUBCOMMANDS.has(positionals[0])) {
|
|
242
236
|
result.subcommand = positionals[0];
|
|
243
237
|
result.positionals = positionals.slice(1);
|
|
244
|
-
} else if (positionals.length > 0) {
|
|
245
|
-
result.message = positionals.join(" ");
|
|
246
238
|
}
|
|
247
239
|
}
|
|
248
240
|
return result;
|
|
@@ -280,6 +272,48 @@ function parseIntentArgs(positionals, result) {
|
|
|
280
272
|
}
|
|
281
273
|
}
|
|
282
274
|
|
|
275
|
+
// src/auth.store.ts
|
|
276
|
+
import { join } from "node:path";
|
|
277
|
+
import { homedir } from "node:os";
|
|
278
|
+
import { mkdir, readFile, writeFile, unlink } from "node:fs/promises";
|
|
279
|
+
var CREDENTIALS_FILE = "credentials.json";
|
|
280
|
+
|
|
281
|
+
class CredentialStore {
|
|
282
|
+
dir;
|
|
283
|
+
filePath;
|
|
284
|
+
constructor(dir) {
|
|
285
|
+
this.dir = dir ?? join(homedir(), ".index");
|
|
286
|
+
this.filePath = join(this.dir, CREDENTIALS_FILE);
|
|
287
|
+
}
|
|
288
|
+
async load() {
|
|
289
|
+
try {
|
|
290
|
+
const raw = await readFile(this.filePath, "utf-8");
|
|
291
|
+
const parsed = JSON.parse(raw);
|
|
292
|
+
if (parsed.token && parsed.apiUrl && parsed.authKind === "api_key" && parsed.keyId) {
|
|
293
|
+
return parsed;
|
|
294
|
+
}
|
|
295
|
+
return null;
|
|
296
|
+
} catch {
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
async save(credentials) {
|
|
301
|
+
await mkdir(this.dir, { recursive: true });
|
|
302
|
+
await writeFile(this.filePath, JSON.stringify(credentials, null, 2), {
|
|
303
|
+
mode: 384
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
async clear() {
|
|
307
|
+
try {
|
|
308
|
+
await unlink(this.filePath);
|
|
309
|
+
} catch (error) {
|
|
310
|
+
if (error.code === "ENOENT")
|
|
311
|
+
return;
|
|
312
|
+
throw error;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
283
317
|
// src/api.client.ts
|
|
284
318
|
class ApiError extends Error {
|
|
285
319
|
status;
|
|
@@ -301,27 +335,12 @@ function isEarlyAccessNetworkCreationError(error) {
|
|
|
301
335
|
class ApiClient {
|
|
302
336
|
baseUrl;
|
|
303
337
|
token;
|
|
304
|
-
|
|
305
|
-
constructor(baseUrl, token, authKind = "session") {
|
|
338
|
+
constructor(baseUrl, token) {
|
|
306
339
|
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
307
340
|
this.token = token;
|
|
308
|
-
this.authKind = authKind;
|
|
309
341
|
}
|
|
310
342
|
authHeaders() {
|
|
311
|
-
return
|
|
312
|
-
}
|
|
313
|
-
async listSessions() {
|
|
314
|
-
const res = await this.get("/api/chat/sessions");
|
|
315
|
-
const body = await res.json();
|
|
316
|
-
return body.sessions;
|
|
317
|
-
}
|
|
318
|
-
async mintCliApiKey(protocolVersion = 2) {
|
|
319
|
-
const res = await this.post("/api/auth/cli-credential", { protocolVersion });
|
|
320
|
-
const body = await res.json();
|
|
321
|
-
if (typeof body.key !== "string" || !body.key || typeof body.id !== "string" || !body.id || typeof body.expiresAt !== "string" || !body.expiresAt) {
|
|
322
|
-
throw new Error("CLI credential response did not include a key, key ID, and expiry");
|
|
323
|
-
}
|
|
324
|
-
return { key: body.key, keyId: body.id };
|
|
343
|
+
return { "x-api-key": this.token };
|
|
325
344
|
}
|
|
326
345
|
async revokeApiKey(keyId, targetKey = this.token) {
|
|
327
346
|
const res = await this.post("/api/auth/cli-credential/revoke", { keyId, targetKey });
|
|
@@ -363,23 +382,6 @@ class ApiClient {
|
|
|
363
382
|
});
|
|
364
383
|
return await res.json();
|
|
365
384
|
}
|
|
366
|
-
async streamChat(params) {
|
|
367
|
-
const res = await fetch(`${this.baseUrl}/api/chat/stream`, {
|
|
368
|
-
method: "POST",
|
|
369
|
-
headers: {
|
|
370
|
-
"Content-Type": "application/json",
|
|
371
|
-
...this.authHeaders()
|
|
372
|
-
},
|
|
373
|
-
body: JSON.stringify({
|
|
374
|
-
message: params.message,
|
|
375
|
-
...params.sessionId ? { sessionId: params.sessionId } : {}
|
|
376
|
-
})
|
|
377
|
-
});
|
|
378
|
-
if (!res.ok) {
|
|
379
|
-
await this.handleError(res);
|
|
380
|
-
}
|
|
381
|
-
return res;
|
|
382
|
-
}
|
|
383
385
|
async listIntents(options = {}) {
|
|
384
386
|
const body = {};
|
|
385
387
|
if (options.limit !== undefined)
|
|
@@ -603,23 +605,21 @@ class ApiClient {
|
|
|
603
605
|
}
|
|
604
606
|
}
|
|
605
607
|
|
|
608
|
+
// src/login.command.ts
|
|
609
|
+
import { randomBytes } from "node:crypto";
|
|
610
|
+
import { createServer } from "node:http";
|
|
611
|
+
|
|
606
612
|
// src/auth.lifecycle.ts
|
|
607
613
|
async function storeReplacementCredentials(store, previous, replacement, options = {}) {
|
|
608
614
|
await store.save(replacement);
|
|
609
|
-
if (previous
|
|
615
|
+
if (!previous)
|
|
610
616
|
return {};
|
|
611
|
-
if (
|
|
612
|
-
return {
|
|
613
|
-
warning: "Login succeeded, but the previous CLI API key has no exact revocation ID and may remain active. It should be removed in Index web settings."
|
|
614
|
-
};
|
|
615
|
-
}
|
|
616
|
-
if (replacement.authKind === "api_key" && replacement.keyId === previous.keyId) {
|
|
617
|
+
if (replacement.keyId === previous.keyId) {
|
|
617
618
|
return {};
|
|
618
619
|
}
|
|
619
|
-
const
|
|
620
|
-
const createClient = options.clientFactory ?? ((apiUrl, token, kind) => new ApiClient(apiUrl, token, kind));
|
|
620
|
+
const createClient = options.clientFactory ?? ((apiUrl, token) => new ApiClient(apiUrl, token));
|
|
621
621
|
try {
|
|
622
|
-
await createClient(replacement.apiUrl, replacement.token
|
|
622
|
+
await createClient(replacement.apiUrl, replacement.token).revokeApiKey(previous.keyId, previous.token);
|
|
623
623
|
return {};
|
|
624
624
|
} catch (error) {
|
|
625
625
|
const detail = error instanceof Error ? ` ${error.message}` : "";
|
|
@@ -629,51 +629,7 @@ async function storeReplacementCredentials(store, previous, replacement, options
|
|
|
629
629
|
}
|
|
630
630
|
}
|
|
631
631
|
|
|
632
|
-
// src/auth.store.ts
|
|
633
|
-
import { join } from "node:path";
|
|
634
|
-
import { homedir } from "node:os";
|
|
635
|
-
import { mkdir, readFile, writeFile, unlink } from "node:fs/promises";
|
|
636
|
-
var CREDENTIALS_FILE = "credentials.json";
|
|
637
|
-
|
|
638
|
-
class CredentialStore {
|
|
639
|
-
dir;
|
|
640
|
-
filePath;
|
|
641
|
-
constructor(dir) {
|
|
642
|
-
this.dir = dir ?? join(homedir(), ".index");
|
|
643
|
-
this.filePath = join(this.dir, CREDENTIALS_FILE);
|
|
644
|
-
}
|
|
645
|
-
async load() {
|
|
646
|
-
try {
|
|
647
|
-
const raw = await readFile(this.filePath, "utf-8");
|
|
648
|
-
const parsed = JSON.parse(raw);
|
|
649
|
-
if (parsed.token && parsed.apiUrl) {
|
|
650
|
-
return parsed;
|
|
651
|
-
}
|
|
652
|
-
return null;
|
|
653
|
-
} catch {
|
|
654
|
-
return null;
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
async save(credentials) {
|
|
658
|
-
await mkdir(this.dir, { recursive: true });
|
|
659
|
-
await writeFile(this.filePath, JSON.stringify(credentials, null, 2), {
|
|
660
|
-
mode: 384
|
|
661
|
-
});
|
|
662
|
-
}
|
|
663
|
-
async clear() {
|
|
664
|
-
try {
|
|
665
|
-
await unlink(this.filePath);
|
|
666
|
-
} catch (error) {
|
|
667
|
-
if (error.code === "ENOENT")
|
|
668
|
-
return;
|
|
669
|
-
throw error;
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
|
|
674
632
|
// src/login.command.ts
|
|
675
|
-
import { randomBytes } from "node:crypto";
|
|
676
|
-
import { createServer } from "node:http";
|
|
677
633
|
function closeServer(server) {
|
|
678
634
|
return new Promise((resolve) => {
|
|
679
635
|
let resolved = false;
|
|
@@ -728,7 +684,6 @@ async function handleLogin(apiUrl, appUrl, store, options = {}) {
|
|
|
728
684
|
stateConsumed = true;
|
|
729
685
|
const apiKey = url.searchParams.get("api_key");
|
|
730
686
|
const keyId = url.searchParams.get("key_id");
|
|
731
|
-
const sessionToken = url.searchParams.get("session_token");
|
|
732
687
|
if (apiKey && keyId) {
|
|
733
688
|
try {
|
|
734
689
|
const cleanup = await storeReplacementCredentials(store, previousCredentials, {
|
|
@@ -748,24 +703,6 @@ async function handleLogin(apiUrl, appUrl, store, options = {}) {
|
|
|
748
703
|
res.end(callbackHtml("CLI authorized", "You can close this window and return to the terminal.", true));
|
|
749
704
|
return;
|
|
750
705
|
}
|
|
751
|
-
if (!apiKey && sessionToken) {
|
|
752
|
-
try {
|
|
753
|
-
const cleanup = await storeReplacementCredentials(store, previousCredentials, {
|
|
754
|
-
token: sessionToken,
|
|
755
|
-
apiUrl: baseUrl,
|
|
756
|
-
authKind: "session"
|
|
757
|
-
}, { clientFactory: options.credentialClientFactory });
|
|
758
|
-
resolveCallback({ success: true, ...cleanup });
|
|
759
|
-
} catch {
|
|
760
|
-
resolveCallback({ success: false, error: "Failed to save CLI credentials." });
|
|
761
|
-
res.writeHead(500, { "Content-Type": "text/html" });
|
|
762
|
-
res.end(callbackHtml("Authorization failed", "CLI credentials could not be saved. Return to the terminal and try again."));
|
|
763
|
-
return;
|
|
764
|
-
}
|
|
765
|
-
res.writeHead(200, { "Content-Type": "text/html" });
|
|
766
|
-
res.end(callbackHtml("CLI authorized", "You can close this window and return to the terminal.", true));
|
|
767
|
-
return;
|
|
768
|
-
}
|
|
769
706
|
resolveCallback({
|
|
770
707
|
success: false,
|
|
771
708
|
error: apiKey ? "CLI API-key callback did not include its key ID." : "No CLI credential received in callback."
|
|
@@ -887,17 +824,7 @@ async function handleLogout(store, options = {}) {
|
|
|
887
824
|
if (!credentials) {
|
|
888
825
|
return { success: true, message: "Already logged out." };
|
|
889
826
|
}
|
|
890
|
-
|
|
891
|
-
await store.clear();
|
|
892
|
-
return { success: true, message: "Logged out. Session cleared." };
|
|
893
|
-
}
|
|
894
|
-
if (!credentials.keyId) {
|
|
895
|
-
return {
|
|
896
|
-
success: false,
|
|
897
|
-
warning: "Stored API-key credentials do not include a revocation ID and were retained. Remove the old key in Index web settings first, then delete the local credentials and sign in again."
|
|
898
|
-
};
|
|
899
|
-
}
|
|
900
|
-
const createClient = options.clientFactory ?? ((apiUrl, token) => new ApiClient(apiUrl, token, "api_key"));
|
|
827
|
+
const createClient = options.clientFactory ?? ((apiUrl, token) => new ApiClient(apiUrl, token));
|
|
901
828
|
try {
|
|
902
829
|
await createClient(credentials.apiUrl, credentials.token).revokeApiKey(credentials.keyId, credentials.token);
|
|
903
830
|
} catch (error) {
|
|
@@ -927,7 +854,6 @@ __export(exports_output, {
|
|
|
927
854
|
success: () => success,
|
|
928
855
|
stripAnsi: () => stripAnsi,
|
|
929
856
|
status: () => status,
|
|
930
|
-
sessionTable: () => sessionTable,
|
|
931
857
|
raw: () => raw,
|
|
932
858
|
profileCard: () => profileCard,
|
|
933
859
|
padTo: () => padTo,
|
|
@@ -1361,28 +1287,6 @@ function contactTable(contacts) {
|
|
|
1361
1287
|
console.log(` ${c.name.padEnd(nameWidth)} ${c.email}${ghost}`);
|
|
1362
1288
|
}
|
|
1363
1289
|
}
|
|
1364
|
-
function sessionTable(sessions) {
|
|
1365
|
-
if (sessions.length === 0) {
|
|
1366
|
-
dim(" No chat sessions found.");
|
|
1367
|
-
return;
|
|
1368
|
-
}
|
|
1369
|
-
const idWidth = 36;
|
|
1370
|
-
const titleWidth = 40;
|
|
1371
|
-
const dateWidth = 20;
|
|
1372
|
-
console.log(` ${BOLD}${"ID".padEnd(idWidth)} ${"Title".padEnd(titleWidth)} ${"Created".padEnd(dateWidth)}${RESET}`);
|
|
1373
|
-
console.log(` ${GRAY}${"-".repeat(idWidth)} ${"-".repeat(titleWidth)} ${"-".repeat(dateWidth)}${RESET}`);
|
|
1374
|
-
for (const s of sessions) {
|
|
1375
|
-
const title = (s.title ?? "(untitled)").slice(0, titleWidth);
|
|
1376
|
-
const date = new Date(s.createdAt).toLocaleDateString("en-US", {
|
|
1377
|
-
year: "numeric",
|
|
1378
|
-
month: "short",
|
|
1379
|
-
day: "numeric",
|
|
1380
|
-
hour: "2-digit",
|
|
1381
|
-
minute: "2-digit"
|
|
1382
|
-
});
|
|
1383
|
-
console.log(` ${GRAY}${s.id.padEnd(idWidth)}${RESET} ${title.padEnd(titleWidth)} ${GRAY}${date}${RESET}`);
|
|
1384
|
-
}
|
|
1385
|
-
}
|
|
1386
1290
|
function intentTable(intents) {
|
|
1387
1291
|
if (intents.length === 0) {
|
|
1388
1292
|
dim(" No signals found.");
|
|
@@ -2488,122 +2392,9 @@ async function networkInvite(client, id, email, json) {
|
|
|
2488
2392
|
}
|
|
2489
2393
|
|
|
2490
2394
|
// src/conversation.command.ts
|
|
2491
|
-
import { createInterface } from "node:readline/promises";
|
|
2492
|
-
async function renderSSEStream(response, callbacks) {
|
|
2493
|
-
const { onToken, onStatus, onToolActivity, onResponseReset } = callbacks;
|
|
2494
|
-
const result = {};
|
|
2495
|
-
if (!response.body) {
|
|
2496
|
-
result.error = "No response body";
|
|
2497
|
-
return result;
|
|
2498
|
-
}
|
|
2499
|
-
const reader = response.body.getReader();
|
|
2500
|
-
const decoder = new TextDecoder;
|
|
2501
|
-
let buffer = "";
|
|
2502
|
-
let insideToolCall = false;
|
|
2503
|
-
const toolDescriptions = new Map;
|
|
2504
|
-
try {
|
|
2505
|
-
while (true) {
|
|
2506
|
-
const { done, value } = await reader.read();
|
|
2507
|
-
if (done)
|
|
2508
|
-
break;
|
|
2509
|
-
buffer += decoder.decode(value, { stream: true });
|
|
2510
|
-
while (buffer.includes(`
|
|
2511
|
-
|
|
2512
|
-
`)) {
|
|
2513
|
-
const idx = buffer.indexOf(`
|
|
2514
|
-
|
|
2515
|
-
`);
|
|
2516
|
-
const raw2 = buffer.slice(0, idx);
|
|
2517
|
-
buffer = buffer.slice(idx + 2);
|
|
2518
|
-
for (const line of raw2.split(`
|
|
2519
|
-
`)) {
|
|
2520
|
-
if (!line.startsWith("data:"))
|
|
2521
|
-
continue;
|
|
2522
|
-
const jsonStr = line.slice("data:".length).trim();
|
|
2523
|
-
if (!jsonStr)
|
|
2524
|
-
continue;
|
|
2525
|
-
try {
|
|
2526
|
-
const event = JSON.parse(jsonStr);
|
|
2527
|
-
const type = event.type;
|
|
2528
|
-
switch (type) {
|
|
2529
|
-
case "token": {
|
|
2530
|
-
if (typeof event.content !== "string")
|
|
2531
|
-
break;
|
|
2532
|
-
if (insideToolCall)
|
|
2533
|
-
break;
|
|
2534
|
-
onToken(event.content);
|
|
2535
|
-
break;
|
|
2536
|
-
}
|
|
2537
|
-
case "status":
|
|
2538
|
-
if (onStatus && typeof event.message === "string") {
|
|
2539
|
-
onStatus(event.message);
|
|
2540
|
-
}
|
|
2541
|
-
break;
|
|
2542
|
-
case "tool_activity": {
|
|
2543
|
-
const phase = event.phase;
|
|
2544
|
-
const toolName = typeof event.toolName === "string" ? event.toolName : "";
|
|
2545
|
-
const desc = typeof event.description === "string" ? event.description : undefined;
|
|
2546
|
-
if (phase === "start") {
|
|
2547
|
-
insideToolCall = true;
|
|
2548
|
-
if (desc && toolName) {
|
|
2549
|
-
toolDescriptions.set(toolName, desc);
|
|
2550
|
-
}
|
|
2551
|
-
if (onToolActivity && desc) {
|
|
2552
|
-
onToolActivity(desc, "start");
|
|
2553
|
-
}
|
|
2554
|
-
} else if (phase === "end") {
|
|
2555
|
-
insideToolCall = false;
|
|
2556
|
-
const startDesc = toolName ? toolDescriptions.get(toolName) : undefined;
|
|
2557
|
-
if (onToolActivity) {
|
|
2558
|
-
onToolActivity(startDesc ?? desc ?? toolName, "end", event.success !== false);
|
|
2559
|
-
}
|
|
2560
|
-
if (toolName)
|
|
2561
|
-
toolDescriptions.delete(toolName);
|
|
2562
|
-
}
|
|
2563
|
-
break;
|
|
2564
|
-
}
|
|
2565
|
-
case "tool_start":
|
|
2566
|
-
insideToolCall = true;
|
|
2567
|
-
break;
|
|
2568
|
-
case "tool_end":
|
|
2569
|
-
insideToolCall = false;
|
|
2570
|
-
break;
|
|
2571
|
-
case "llm_start":
|
|
2572
|
-
insideToolCall = false;
|
|
2573
|
-
break;
|
|
2574
|
-
case "response_reset":
|
|
2575
|
-
result.response = undefined;
|
|
2576
|
-
if (onResponseReset) {
|
|
2577
|
-
onResponseReset(typeof event.reason === "string" ? event.reason : undefined);
|
|
2578
|
-
}
|
|
2579
|
-
break;
|
|
2580
|
-
case "done":
|
|
2581
|
-
result.sessionId = typeof event.sessionId === "string" ? event.sessionId : undefined;
|
|
2582
|
-
result.response = typeof event.response === "string" ? event.response : undefined;
|
|
2583
|
-
result.title = typeof event.title === "string" ? event.title : undefined;
|
|
2584
|
-
break;
|
|
2585
|
-
case "error":
|
|
2586
|
-
result.error = typeof event.message === "string" ? event.message : "Unknown stream error";
|
|
2587
|
-
break;
|
|
2588
|
-
default:
|
|
2589
|
-
break;
|
|
2590
|
-
}
|
|
2591
|
-
} catch {}
|
|
2592
|
-
}
|
|
2593
|
-
}
|
|
2594
|
-
}
|
|
2595
|
-
} finally {
|
|
2596
|
-
reader.releaseLock();
|
|
2597
|
-
}
|
|
2598
|
-
return result;
|
|
2599
|
-
}
|
|
2600
2395
|
var CONVERSATION_HELP = `
|
|
2601
2396
|
Conversation Commands:
|
|
2602
|
-
index conversation
|
|
2603
|
-
index conversation "message" One-shot message to the AI agent
|
|
2604
|
-
index conversation --session <id> Resume a specific chat session
|
|
2605
|
-
index conversation sessions List AI chat sessions
|
|
2606
|
-
index conversation list List all conversations (H2A + H2H)
|
|
2397
|
+
index conversation list List all conversations
|
|
2607
2398
|
index conversation with <user-id|key> Open or resume a DM with a user
|
|
2608
2399
|
index conversation show <id> Show messages (accepts short ID)
|
|
2609
2400
|
index conversation show <id> --limit <n> Limit number of messages
|
|
@@ -2612,21 +2403,10 @@ Conversation Commands:
|
|
|
2612
2403
|
`;
|
|
2613
2404
|
async function handleConversation(client, subcommand, positionals, options) {
|
|
2614
2405
|
if (!subcommand) {
|
|
2615
|
-
|
|
2616
|
-
error("`--json` requires an explicit conversation subcommand.", 1);
|
|
2617
|
-
return;
|
|
2618
|
-
}
|
|
2619
|
-
if (options?.message) {
|
|
2620
|
-
await chatOneShot(client, options.message, options.sessionId);
|
|
2621
|
-
} else {
|
|
2622
|
-
await chatRepl(client, options?.sessionId);
|
|
2623
|
-
}
|
|
2406
|
+
error("Agent chat is no longer available from the CLI. Use `index conversation list` " + "for your conversations, or chat in the Index app.", 1);
|
|
2624
2407
|
return;
|
|
2625
2408
|
}
|
|
2626
2409
|
switch (subcommand) {
|
|
2627
|
-
case "sessions":
|
|
2628
|
-
await chatSessionsList(client, options?.json);
|
|
2629
|
-
return;
|
|
2630
2410
|
case "list":
|
|
2631
2411
|
await conversationList(client, options?.json);
|
|
2632
2412
|
return;
|
|
@@ -2752,132 +2532,6 @@ async function conversationStream(client) {
|
|
|
2752
2532
|
reader.releaseLock();
|
|
2753
2533
|
}
|
|
2754
2534
|
}
|
|
2755
|
-
async function chatSessionsList(client, json) {
|
|
2756
|
-
const sessions = await client.listSessions();
|
|
2757
|
-
if (json) {
|
|
2758
|
-
console.log(JSON.stringify(sessions));
|
|
2759
|
-
return;
|
|
2760
|
-
}
|
|
2761
|
-
heading("Chat Sessions");
|
|
2762
|
-
sessionTable(sessions);
|
|
2763
|
-
console.log();
|
|
2764
|
-
}
|
|
2765
|
-
async function chatOneShot(client, message, sessionId) {
|
|
2766
|
-
const response = await client.streamChat({ message, sessionId });
|
|
2767
|
-
if (!response.ok) {
|
|
2768
|
-
handleStreamError(response);
|
|
2769
|
-
return;
|
|
2770
|
-
}
|
|
2771
|
-
const result = await streamToTerminal(response);
|
|
2772
|
-
if (result.error) {
|
|
2773
|
-
error(result.error, 1);
|
|
2774
|
-
return;
|
|
2775
|
-
}
|
|
2776
|
-
if (result.sessionId) {
|
|
2777
|
-
dim(`
|
|
2778
|
-
Session: ${result.sessionId}`);
|
|
2779
|
-
}
|
|
2780
|
-
}
|
|
2781
|
-
async function chatRepl(client, sessionId) {
|
|
2782
|
-
let currentSessionId = sessionId;
|
|
2783
|
-
chatHeader();
|
|
2784
|
-
const PROMPT_STR2 = PROMPT_STR;
|
|
2785
|
-
const rl = createInterface({
|
|
2786
|
-
input: process.stdin,
|
|
2787
|
-
output: process.stderr,
|
|
2788
|
-
terminal: true
|
|
2789
|
-
});
|
|
2790
|
-
rl.setPrompt(PROMPT_STR2);
|
|
2791
|
-
rl.prompt();
|
|
2792
|
-
try {
|
|
2793
|
-
for await (const line of rl) {
|
|
2794
|
-
const input = line.trim();
|
|
2795
|
-
if (!input) {
|
|
2796
|
-
rl.prompt();
|
|
2797
|
-
continue;
|
|
2798
|
-
}
|
|
2799
|
-
if (input === "exit" || input === "quit")
|
|
2800
|
-
break;
|
|
2801
|
-
const response = await client.streamChat({
|
|
2802
|
-
message: input,
|
|
2803
|
-
sessionId: currentSessionId
|
|
2804
|
-
});
|
|
2805
|
-
if (!response.ok) {
|
|
2806
|
-
if (response.status === 401) {
|
|
2807
|
-
error("Session expired. Run `index login` to re-authenticate.", 1);
|
|
2808
|
-
return;
|
|
2809
|
-
}
|
|
2810
|
-
const body = await response.json().catch(() => ({}));
|
|
2811
|
-
error(body.error ?? `HTTP ${response.status}`);
|
|
2812
|
-
rl.prompt();
|
|
2813
|
-
continue;
|
|
2814
|
-
}
|
|
2815
|
-
const result = await streamToTerminal(response);
|
|
2816
|
-
if (result.error) {
|
|
2817
|
-
error(result.error);
|
|
2818
|
-
}
|
|
2819
|
-
if (result.sessionId) {
|
|
2820
|
-
currentSessionId = result.sessionId;
|
|
2821
|
-
}
|
|
2822
|
-
process.stderr.write(`
|
|
2823
|
-
`);
|
|
2824
|
-
rl.prompt();
|
|
2825
|
-
}
|
|
2826
|
-
} finally {
|
|
2827
|
-
rl.close();
|
|
2828
|
-
}
|
|
2829
|
-
process.stderr.write(`
|
|
2830
|
-
`);
|
|
2831
|
-
dim("Goodbye!");
|
|
2832
|
-
}
|
|
2833
|
-
async function streamToTerminal(response) {
|
|
2834
|
-
let hasTokens = false;
|
|
2835
|
-
const md = new MarkdownRenderer;
|
|
2836
|
-
let lastToolDesc = "";
|
|
2837
|
-
const result = await renderSSEStream(response, {
|
|
2838
|
-
onToken(text) {
|
|
2839
|
-
if (!hasTokens) {
|
|
2840
|
-
clearStatus();
|
|
2841
|
-
hasTokens = true;
|
|
2842
|
-
}
|
|
2843
|
-
md.write(text);
|
|
2844
|
-
lastToolDesc = "";
|
|
2845
|
-
},
|
|
2846
|
-
onStatus(msg) {
|
|
2847
|
-
if (!hasTokens) {
|
|
2848
|
-
status(msg);
|
|
2849
|
-
}
|
|
2850
|
-
},
|
|
2851
|
-
onToolActivity(description, phase) {
|
|
2852
|
-
if (phase === "start") {
|
|
2853
|
-
const friendly = humanizeToolName(description);
|
|
2854
|
-
if (friendly === lastToolDesc)
|
|
2855
|
-
return;
|
|
2856
|
-
lastToolDesc = friendly;
|
|
2857
|
-
md.finalize();
|
|
2858
|
-
hasTokens = false;
|
|
2859
|
-
toolActivity(friendly);
|
|
2860
|
-
}
|
|
2861
|
-
},
|
|
2862
|
-
onResponseReset(reason) {
|
|
2863
|
-
md.reset(reason);
|
|
2864
|
-
hasTokens = false;
|
|
2865
|
-
}
|
|
2866
|
-
});
|
|
2867
|
-
md.finalize();
|
|
2868
|
-
clearStatus();
|
|
2869
|
-
if (hasTokens) {
|
|
2870
|
-
console.log();
|
|
2871
|
-
}
|
|
2872
|
-
return result;
|
|
2873
|
-
}
|
|
2874
|
-
async function handleStreamError(response) {
|
|
2875
|
-
if (response.status === 401) {
|
|
2876
|
-
error("Session expired or invalid. Run `index login` to re-authenticate.", 1);
|
|
2877
|
-
}
|
|
2878
|
-
const body = await response.json().catch(() => ({}));
|
|
2879
|
-
error(body.error ?? `HTTP ${response.status}`, 1);
|
|
2880
|
-
}
|
|
2881
2535
|
|
|
2882
2536
|
// src/contact.command.ts
|
|
2883
2537
|
var CONTACT_HELP = `
|
|
@@ -3113,7 +2767,6 @@ function helpRowCont(leftW, right) {
|
|
|
3113
2767
|
function renderHelp() {
|
|
3114
2768
|
const gsLefts = [
|
|
3115
2769
|
"index login",
|
|
3116
|
-
"index login --token <token>",
|
|
3117
2770
|
"index logout",
|
|
3118
2771
|
'index intent create "..."',
|
|
3119
2772
|
"index negotiation list",
|
|
@@ -3121,8 +2774,7 @@ function renderHelp() {
|
|
|
3121
2774
|
];
|
|
3122
2775
|
const gsLW = Math.max(...gsLefts.map((s) => s.length));
|
|
3123
2776
|
const formsLefts = [
|
|
3124
|
-
|
|
3125
|
-
"index conversation --session <id>",
|
|
2777
|
+
"index conversation list",
|
|
3126
2778
|
"index sync --json",
|
|
3127
2779
|
"index profile create",
|
|
3128
2780
|
"index profile update",
|
|
@@ -3149,8 +2801,6 @@ function renderHelp() {
|
|
|
3149
2801
|
const optLefts = [
|
|
3150
2802
|
"--api-url <url>",
|
|
3151
2803
|
"--app-url <url>",
|
|
3152
|
-
"--token <token>",
|
|
3153
|
-
"--session <id>",
|
|
3154
2804
|
"--archived",
|
|
3155
2805
|
"--status <status>",
|
|
3156
2806
|
"--limit <n>",
|
|
@@ -3174,15 +2824,13 @@ function renderHelp() {
|
|
|
3174
2824
|
`);
|
|
3175
2825
|
panel("getting started", [
|
|
3176
2826
|
helpRowCmd(gsLW, "index login", "authenticate via browser"),
|
|
3177
|
-
helpRowCmd(gsLW, "index login --token <token>", "authenticate with a bearer token"),
|
|
3178
2827
|
helpRowCmd(gsLW, "index logout", "clear stored session"),
|
|
3179
2828
|
helpRowCmd(gsLW, 'index intent create "..."', "describe what you're looking for"),
|
|
3180
2829
|
helpRowCmd(gsLW, "index negotiation list", "see agent debates in progress"),
|
|
3181
2830
|
helpRowCmd(gsLW, "index opportunity list", "see what was found for you")
|
|
3182
2831
|
]);
|
|
3183
2832
|
panel("common forms", [
|
|
3184
|
-
helpRowCmd(formsLW,
|
|
3185
|
-
helpRowCmd(formsLW, "index conversation --session <id>", "resume an agent chat session"),
|
|
2833
|
+
helpRowCmd(formsLW, "index conversation list", "list your conversations"),
|
|
3186
2834
|
helpRowCmd(formsLW, "index sync --json", "print synced context as JSON"),
|
|
3187
2835
|
"",
|
|
3188
2836
|
helpRowCmd(formsLW, "index profile create", "use social URL flags"),
|
|
@@ -3200,7 +2848,7 @@ function renderHelp() {
|
|
|
3200
2848
|
helpRowCmd(cmdLW, "negotiation", "list · show"),
|
|
3201
2849
|
"",
|
|
3202
2850
|
helpRowCmd(cmdLW, "profile", "show · sync · search · create · update"),
|
|
3203
|
-
helpRowCmd(cmdLW, "conversation", "
|
|
2851
|
+
helpRowCmd(cmdLW, "conversation", "list · with · show · send · stream"),
|
|
3204
2852
|
helpRowCmd(cmdLW, "network", "list · create · show · update · delete"),
|
|
3205
2853
|
helpRowCont(cmdLW, "join · leave · invite"),
|
|
3206
2854
|
helpRowCmd(cmdLW, "contact", "list · add · remove · import"),
|
|
@@ -3212,8 +2860,6 @@ function renderHelp() {
|
|
|
3212
2860
|
panel("options", [
|
|
3213
2861
|
helpRowDim(optLW, "--api-url <url>", "override API server URL"),
|
|
3214
2862
|
helpRowDim(optLW, "--app-url <url>", "override app URL for login"),
|
|
3215
|
-
helpRowDim(optLW, "--token <token>", "provide bearer token directly"),
|
|
3216
|
-
helpRowDim(optLW, "--session <id>", "resume a chat session"),
|
|
3217
2863
|
helpRowDim(optLW, "--archived", "include archived signals"),
|
|
3218
2864
|
helpRowDim(optLW, "--status <status>", "filter opportunities by status"),
|
|
3219
2865
|
helpRowDim(optLW, "--limit <n>", "limit number of results"),
|
|
@@ -3239,45 +2885,12 @@ async function requireAuth(apiUrlOverride) {
|
|
|
3239
2885
|
process.exit(1);
|
|
3240
2886
|
}
|
|
3241
2887
|
const apiUrl = apiUrlOverride ?? creds.apiUrl;
|
|
3242
|
-
|
|
3243
|
-
try {
|
|
3244
|
-
const sessionClient = new ApiClient(apiUrl, creds.token, "session");
|
|
3245
|
-
const { key, keyId } = await sessionClient.mintCliApiKey();
|
|
3246
|
-
const migrated = { token: key, apiUrl, authKind: "api_key", keyId };
|
|
3247
|
-
await store.save(migrated);
|
|
3248
|
-
return new ApiClient(apiUrl, migrated.token, migrated.authKind);
|
|
3249
|
-
} catch {
|
|
3250
|
-
error("Stored CLI credentials need to be refreshed. Run `index login` again.", 1);
|
|
3251
|
-
process.exit(1);
|
|
3252
|
-
}
|
|
3253
|
-
}
|
|
3254
|
-
return new ApiClient(apiUrl, creds.token, creds.authKind);
|
|
2888
|
+
return new ApiClient(apiUrl, creds.token);
|
|
3255
2889
|
}
|
|
3256
|
-
async function runLogin(apiUrlOverride, appUrlOverride
|
|
2890
|
+
async function runLogin(apiUrlOverride, appUrlOverride) {
|
|
3257
2891
|
const store = new CredentialStore;
|
|
3258
2892
|
const apiUrl = apiUrlOverride ?? DEFAULT_API_URL;
|
|
3259
2893
|
const appUrl = appUrlOverride ?? DEFAULT_APP_URL;
|
|
3260
|
-
if (manualToken) {
|
|
3261
|
-
const previousCredentials = await store.load();
|
|
3262
|
-
try {
|
|
3263
|
-
const sessionClient = new ApiClient(apiUrl, manualToken, "session");
|
|
3264
|
-
const user = await sessionClient.getMe();
|
|
3265
|
-
const { key, keyId } = await sessionClient.mintCliApiKey();
|
|
3266
|
-
const cleanup = await storeReplacementCredentials(store, previousCredentials, {
|
|
3267
|
-
token: key,
|
|
3268
|
-
apiUrl,
|
|
3269
|
-
authKind: "api_key",
|
|
3270
|
-
keyId
|
|
3271
|
-
});
|
|
3272
|
-
success(`Logged in as ${user.name} (${user.email})`);
|
|
3273
|
-
if (cleanup.warning)
|
|
3274
|
-
warn(cleanup.warning);
|
|
3275
|
-
} catch {
|
|
3276
|
-
error("Could not exchange that session token. Run `index login` instead.", 1);
|
|
3277
|
-
process.exitCode = 1;
|
|
3278
|
-
}
|
|
3279
|
-
return;
|
|
3280
|
-
}
|
|
3281
2894
|
info(`Authenticating with ${apiUrl}...`);
|
|
3282
2895
|
const { authUrl, callbackPromise } = await handleLogin(apiUrl, appUrl, store);
|
|
3283
2896
|
info("Opening browser for authentication...");
|
|
@@ -3308,7 +2921,7 @@ async function runLogin(apiUrlOverride, appUrlOverride, manualToken) {
|
|
|
3308
2921
|
try {
|
|
3309
2922
|
const creds = await store.load();
|
|
3310
2923
|
if (creds) {
|
|
3311
|
-
const client = new ApiClient(creds.apiUrl, creds.token
|
|
2924
|
+
const client = new ApiClient(creds.apiUrl, creds.token);
|
|
3312
2925
|
const user = await client.getMe();
|
|
3313
2926
|
success(`Logged in as ${user.name} (${user.email})`);
|
|
3314
2927
|
}
|
|
@@ -3343,7 +2956,7 @@ async function main() {
|
|
|
3343
2956
|
error(`Unknown command: ${args.unknown}`, 1);
|
|
3344
2957
|
return;
|
|
3345
2958
|
case "login":
|
|
3346
|
-
await runLogin(args.apiUrl, args.appUrl
|
|
2959
|
+
await runLogin(args.apiUrl, args.appUrl);
|
|
3347
2960
|
return;
|
|
3348
2961
|
case "logout":
|
|
3349
2962
|
await runLogout();
|
|
@@ -3398,8 +3011,6 @@ async function main() {
|
|
|
3398
3011
|
case "conversation":
|
|
3399
3012
|
await handleConversation(client, args.subcommand, args.positionals ?? [], {
|
|
3400
3013
|
limit: args.limit,
|
|
3401
|
-
sessionId: args.sessionId,
|
|
3402
|
-
message: args.message,
|
|
3403
3014
|
json: args.json
|
|
3404
3015
|
});
|
|
3405
3016
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@indexnetwork/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0-rc.64.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.
|
|
24
|
-
"@indexnetwork/cli-linux-arm64": "0.
|
|
25
|
-
"@indexnetwork/cli-darwin-x64": "0.
|
|
26
|
-
"@indexnetwork/cli-darwin-arm64": "0.
|
|
23
|
+
"@indexnetwork/cli-linux-x64": "0.15.0-rc.64.1",
|
|
24
|
+
"@indexnetwork/cli-linux-arm64": "0.15.0-rc.64.1",
|
|
25
|
+
"@indexnetwork/cli-darwin-x64": "0.15.0-rc.64.1",
|
|
26
|
+
"@indexnetwork/cli-darwin-arm64": "0.15.0-rc.64.1"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/bun": "1.3.14"
|