@indexnetwork/cli 0.16.0-rc.65.1 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +181 -57
- package/dist/index.js +719 -1218
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,25 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __returnValue = (v) => v;
|
|
4
|
-
function __exportSetter(name, newValue) {
|
|
5
|
-
this[name] = __returnValue.bind(null, newValue);
|
|
6
|
-
}
|
|
7
|
-
var __export = (target, all) => {
|
|
8
|
-
for (var name in all)
|
|
9
|
-
__defProp(target, name, {
|
|
10
|
-
get: all[name],
|
|
11
|
-
enumerable: true,
|
|
12
|
-
configurable: true,
|
|
13
|
-
set: __exportSetter.bind(all, name)
|
|
14
|
-
});
|
|
15
|
-
};
|
|
16
2
|
|
|
17
3
|
// src/main.ts
|
|
18
4
|
import { spawn } from "node:child_process";
|
|
19
5
|
// package.json
|
|
20
6
|
var package_default = {
|
|
21
7
|
name: "@indexnetwork/cli",
|
|
22
|
-
version: "0.
|
|
8
|
+
version: "0.28.0",
|
|
23
9
|
description: "Command-line interface for Index Network",
|
|
24
10
|
license: "MIT",
|
|
25
11
|
type: "module",
|
|
@@ -39,10 +25,10 @@ var package_default = {
|
|
|
39
25
|
"publish:all": "bun scripts/publish.ts"
|
|
40
26
|
},
|
|
41
27
|
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.
|
|
28
|
+
"@indexnetwork/cli-linux-x64": "0.28.0",
|
|
29
|
+
"@indexnetwork/cli-linux-arm64": "0.28.0",
|
|
30
|
+
"@indexnetwork/cli-darwin-x64": "0.28.0",
|
|
31
|
+
"@indexnetwork/cli-darwin-arm64": "0.28.0"
|
|
46
32
|
},
|
|
47
33
|
devDependencies: {
|
|
48
34
|
"@types/bun": "1.3.14"
|
|
@@ -50,15 +36,15 @@ var package_default = {
|
|
|
50
36
|
};
|
|
51
37
|
|
|
52
38
|
// src/args.parser.ts
|
|
53
|
-
var KNOWN_COMMANDS = new Set(["login", "logout", "profile", "intent", "opportunity", "negotiation", "network", "conversation", "
|
|
54
|
-
var OPPORTUNITY_SUBCOMMANDS = new Set(["list", "show", "accept", "reject"]);
|
|
55
|
-
var NEGOTIATION_SUBCOMMANDS = new Set(["list", "show"]);
|
|
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", "help"]);
|
|
39
|
+
var KNOWN_COMMANDS = new Set(["docs", "agent", "login", "logout", "profile", "intent", "opportunity", "negotiation", "network", "conversation", "scrape", "onboarding", "sync", "help", "version"]);
|
|
40
|
+
var OPPORTUNITY_SUBCOMMANDS = new Set(["list", "show", "accept", "reject", "start-chat"]);
|
|
41
|
+
var NEGOTIATION_SUBCOMMANDS = new Set(["list", "show", "turn"]);
|
|
42
|
+
var NETWORK_SUBCOMMANDS = new Set(["list", "create", "show", "join", "leave", "invite", "update", "delete", "discover", "requests", "request-update", "request-dismiss"]);
|
|
43
|
+
var CONVERSATION_SUBCOMMANDS = new Set(["list", "with", "show", "send", "answer", "stream", "help"]);
|
|
58
44
|
function parseArgs(args) {
|
|
59
45
|
const result = {
|
|
60
46
|
command: "help",
|
|
61
|
-
|
|
47
|
+
json: args.includes("--json")
|
|
62
48
|
};
|
|
63
49
|
if (args.length === 0) {
|
|
64
50
|
return result;
|
|
@@ -67,6 +53,8 @@ function parseArgs(args) {
|
|
|
67
53
|
for (let j = 0;j < args.length; j++) {
|
|
68
54
|
const a = args[j];
|
|
69
55
|
if (a === "--api-url" || a === "--app-url") {
|
|
56
|
+
if (!args[j + 1] || args[j + 1].startsWith("--"))
|
|
57
|
+
throw new Error(`Missing value for ${a}`);
|
|
70
58
|
if (a === "--api-url")
|
|
71
59
|
result.apiUrl = args[j + 1];
|
|
72
60
|
else
|
|
@@ -78,7 +66,11 @@ function parseArgs(args) {
|
|
|
78
66
|
} else if (a === "--version" || a === "-v") {
|
|
79
67
|
result.command = "version";
|
|
80
68
|
return result;
|
|
81
|
-
} else if (
|
|
69
|
+
} else if (a === "--json") {
|
|
70
|
+
continue;
|
|
71
|
+
} else if (a.startsWith("-")) {
|
|
72
|
+
throw new Error(`Unknown option: ${a}`);
|
|
73
|
+
} else {
|
|
82
74
|
commandIndex = j;
|
|
83
75
|
break;
|
|
84
76
|
}
|
|
@@ -97,10 +89,66 @@ function parseArgs(args) {
|
|
|
97
89
|
const positionals = [];
|
|
98
90
|
while (i < args.length) {
|
|
99
91
|
const arg = args[i];
|
|
100
|
-
if (arg === "--
|
|
101
|
-
result
|
|
102
|
-
|
|
103
|
-
|
|
92
|
+
if (arg === "--help" || arg === "-h")
|
|
93
|
+
return { ...result, command: "help" };
|
|
94
|
+
if (arg === "--version" || arg === "-v")
|
|
95
|
+
return { ...result, command: "version" };
|
|
96
|
+
if (["--api-url", "--app-url", "--status", "--limit", "--prompt", "-p", "--objective", "--title"].includes(arg) && (!args[i + 1] || args[i + 1].startsWith("--")))
|
|
97
|
+
throw new Error(`Missing value for ${arg}`);
|
|
98
|
+
if (["--query", "--state", "--action", "--message", "--intent-id", "--question-id", "--expected-turn-count", "--receipt", "--name", "--intro", "--location", "--statuses", "--answer", "--social"].includes(arg)) {
|
|
99
|
+
const value = args[i + 1];
|
|
100
|
+
if (value === undefined || value.startsWith("--"))
|
|
101
|
+
throw new Error(`Missing value for ${arg}`);
|
|
102
|
+
switch (arg) {
|
|
103
|
+
case "--query":
|
|
104
|
+
result.query = value;
|
|
105
|
+
break;
|
|
106
|
+
case "--state":
|
|
107
|
+
result.state = value;
|
|
108
|
+
break;
|
|
109
|
+
case "--action":
|
|
110
|
+
result.action = value;
|
|
111
|
+
break;
|
|
112
|
+
case "--message":
|
|
113
|
+
result.message = value;
|
|
114
|
+
break;
|
|
115
|
+
case "--intent-id":
|
|
116
|
+
result.intentId = value;
|
|
117
|
+
break;
|
|
118
|
+
case "--question-id":
|
|
119
|
+
result.questionId = value;
|
|
120
|
+
break;
|
|
121
|
+
case "--expected-turn-count":
|
|
122
|
+
result.expectedTurnCount = Number(value);
|
|
123
|
+
break;
|
|
124
|
+
case "--receipt":
|
|
125
|
+
result.receipt = value;
|
|
126
|
+
break;
|
|
127
|
+
case "--name":
|
|
128
|
+
result.name = value;
|
|
129
|
+
break;
|
|
130
|
+
case "--intro":
|
|
131
|
+
result.intro = value;
|
|
132
|
+
break;
|
|
133
|
+
case "--location":
|
|
134
|
+
result.location = value;
|
|
135
|
+
break;
|
|
136
|
+
case "--statuses":
|
|
137
|
+
result.statuses = value;
|
|
138
|
+
break;
|
|
139
|
+
case "--answer":
|
|
140
|
+
case "--social": {
|
|
141
|
+
const at = value.indexOf("=");
|
|
142
|
+
if (at < 1 || !value.slice(at + 1).trim())
|
|
143
|
+
throw new Error(`${arg} needs key=value`);
|
|
144
|
+
const pair = { key: value.slice(0, at), value: value.slice(at + 1) };
|
|
145
|
+
if (arg === "--answer")
|
|
146
|
+
(result.answers ??= []).push(pair);
|
|
147
|
+
else
|
|
148
|
+
(result.socials ??= []).push({ label: pair.key, value: pair.value });
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
104
152
|
i += 2;
|
|
105
153
|
} else if (arg === "--api-url") {
|
|
106
154
|
result.apiUrl = args[i + 1];
|
|
@@ -115,7 +163,9 @@ function parseArgs(args) {
|
|
|
115
163
|
result.status = args[i + 1];
|
|
116
164
|
i += 2;
|
|
117
165
|
} else if (arg === "--limit") {
|
|
118
|
-
result.limit =
|
|
166
|
+
result.limit = Number(args[i + 1]);
|
|
167
|
+
if (!Number.isSafeInteger(result.limit) || result.limit < 1)
|
|
168
|
+
throw new Error("--limit must be a positive integer");
|
|
119
169
|
i += 2;
|
|
120
170
|
} else if (arg === "--prompt" || arg === "-p") {
|
|
121
171
|
result.prompt = args[i + 1];
|
|
@@ -126,34 +176,45 @@ function parseArgs(args) {
|
|
|
126
176
|
} else if (arg === "--objective") {
|
|
127
177
|
result.objective = args[i + 1];
|
|
128
178
|
i += 2;
|
|
129
|
-
} else if (arg === "--linkedin") {
|
|
130
|
-
result.linkedin = args[i + 1];
|
|
131
|
-
i += 2;
|
|
132
|
-
} else if (arg === "--github") {
|
|
133
|
-
result.github = args[i + 1];
|
|
134
|
-
i += 2;
|
|
135
|
-
} else if (arg === "--twitter") {
|
|
136
|
-
result.twitter = args[i + 1];
|
|
137
|
-
i += 2;
|
|
138
179
|
} else if (arg === "--title") {
|
|
139
180
|
result.title = args[i + 1];
|
|
140
181
|
i += 2;
|
|
141
|
-
} else if (arg
|
|
142
|
-
|
|
143
|
-
i += 2;
|
|
144
|
-
} else if (arg === "--since") {
|
|
145
|
-
result.since = args[i + 1];
|
|
146
|
-
i += 2;
|
|
147
|
-
} else if (arg === "--acknowledge-uptake") {
|
|
148
|
-
result.acknowledgeUptake = (args[i + 1] ?? "").split(",").map((id) => id.trim()).filter(Boolean);
|
|
149
|
-
i += 2;
|
|
150
|
-
} else if (arg.startsWith("--")) {
|
|
151
|
-
i++;
|
|
182
|
+
} else if (arg.startsWith("-")) {
|
|
183
|
+
throw new Error(`Unknown option: ${arg}`);
|
|
152
184
|
} else {
|
|
153
185
|
positionals.push(arg);
|
|
154
186
|
i++;
|
|
155
187
|
}
|
|
156
188
|
}
|
|
189
|
+
const subcommands = {
|
|
190
|
+
agent: new Set(["me"]),
|
|
191
|
+
opportunity: OPPORTUNITY_SUBCOMMANDS,
|
|
192
|
+
negotiation: NEGOTIATION_SUBCOMMANDS,
|
|
193
|
+
network: NETWORK_SUBCOMMANDS,
|
|
194
|
+
conversation: CONVERSATION_SUBCOMMANDS,
|
|
195
|
+
intent: INTENT_SUBCOMMANDS,
|
|
196
|
+
profile: new Set(["show", "sync", "update"]),
|
|
197
|
+
onboarding: new Set(["confirm-profile", "complete"])
|
|
198
|
+
};
|
|
199
|
+
const allowed = subcommands[result.command];
|
|
200
|
+
if (allowed && result.command !== "profile" && !positionals[0]) {
|
|
201
|
+
throw new Error(`Missing subcommand for index ${result.command}. Run index --help.`);
|
|
202
|
+
}
|
|
203
|
+
if (allowed && positionals[0] && !allowed.has(positionals[0])) {
|
|
204
|
+
throw new Error(`Unknown command: ${result.command} ${positionals[0]}`);
|
|
205
|
+
}
|
|
206
|
+
if (result.command === "agent") {
|
|
207
|
+
result.subcommand = positionals[0];
|
|
208
|
+
result.positionals = positionals.slice(1);
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
211
|
+
if (result.command === "login") {
|
|
212
|
+
if (positionals.length > 1 || positionals[0] && !["local", "dev", "prod"].includes(positionals[0])) {
|
|
213
|
+
throw new Error("Usage: index login [local|dev|prod] [--api-url <origin>] [--app-url <origin>]");
|
|
214
|
+
}
|
|
215
|
+
result.loginTarget = positionals[0];
|
|
216
|
+
return result;
|
|
217
|
+
}
|
|
157
218
|
if (result.command === "opportunity") {
|
|
158
219
|
const sub = positionals[0];
|
|
159
220
|
if (sub && OPPORTUNITY_SUBCOMMANDS.has(sub)) {
|
|
@@ -168,6 +229,9 @@ function parseArgs(args) {
|
|
|
168
229
|
return result;
|
|
169
230
|
}
|
|
170
231
|
if (result.command === "negotiation") {
|
|
232
|
+
if (result.limit !== undefined || result.status !== undefined) {
|
|
233
|
+
throw new Error("Negotiation filters are --intent-id and --state only");
|
|
234
|
+
}
|
|
171
235
|
const sub = positionals[0];
|
|
172
236
|
if (sub && NEGOTIATION_SUBCOMMANDS.has(sub)) {
|
|
173
237
|
result.subcommand = sub;
|
|
@@ -198,20 +262,11 @@ function parseArgs(args) {
|
|
|
198
262
|
}
|
|
199
263
|
if (result.command === "onboarding" && positionals.length > 0) {
|
|
200
264
|
const sub = positionals[0];
|
|
201
|
-
if (sub === "complete") {
|
|
202
|
-
result.subcommand =
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
if (result.command === "contact") {
|
|
206
|
-
if (positionals.length > 0) {
|
|
207
|
-
const sub = positionals[0];
|
|
208
|
-
if (["list", "add", "remove", "import"].includes(sub)) {
|
|
209
|
-
result.subcommand = sub;
|
|
210
|
-
result.positionals = positionals.slice(1);
|
|
211
|
-
}
|
|
265
|
+
if (sub === "complete" || sub === "confirm-profile") {
|
|
266
|
+
result.subcommand = sub;
|
|
212
267
|
}
|
|
213
268
|
}
|
|
214
|
-
if (result.command === "scrape") {
|
|
269
|
+
if (result.command === "scrape" || result.command === "docs") {
|
|
215
270
|
result.positionals = positionals;
|
|
216
271
|
}
|
|
217
272
|
if (result.command === "intent") {
|
|
@@ -233,7 +288,7 @@ function parseArgs(args) {
|
|
|
233
288
|
}
|
|
234
289
|
return result;
|
|
235
290
|
}
|
|
236
|
-
var INTENT_SUBCOMMANDS = new Set(["list", "show", "create", "archive", "update", "
|
|
291
|
+
var INTENT_SUBCOMMANDS = new Set(["list", "show", "create", "prepare", "archive", "pause", "resume", "update", "networks", "add-to-network", "remove-from-network"]);
|
|
237
292
|
function parseIntentArgs(positionals, result) {
|
|
238
293
|
if (positionals.length === 0)
|
|
239
294
|
return;
|
|
@@ -245,9 +300,13 @@ function parseIntentArgs(positionals, result) {
|
|
|
245
300
|
switch (result.subcommand) {
|
|
246
301
|
case "show":
|
|
247
302
|
case "archive":
|
|
303
|
+
case "pause":
|
|
304
|
+
case "resume":
|
|
305
|
+
case "networks":
|
|
248
306
|
result.intentId = rest[0];
|
|
249
307
|
break;
|
|
250
308
|
case "create":
|
|
309
|
+
case "prepare":
|
|
251
310
|
if (rest.length > 0) {
|
|
252
311
|
result.intentContent = rest.join(" ");
|
|
253
312
|
}
|
|
@@ -258,8 +317,8 @@ function parseIntentArgs(positionals, result) {
|
|
|
258
317
|
result.intentContent = rest.slice(1).join(" ");
|
|
259
318
|
}
|
|
260
319
|
break;
|
|
261
|
-
case "
|
|
262
|
-
case "
|
|
320
|
+
case "add-to-network":
|
|
321
|
+
case "remove-from-network":
|
|
263
322
|
result.intentId = rest[0];
|
|
264
323
|
result.targetId = rest[1];
|
|
265
324
|
break;
|
|
@@ -283,7 +342,7 @@ class CredentialStore {
|
|
|
283
342
|
try {
|
|
284
343
|
const raw = await readFile(this.filePath, "utf-8");
|
|
285
344
|
const parsed = JSON.parse(raw);
|
|
286
|
-
if (parsed.token && parsed.apiUrl && parsed.authKind === "
|
|
345
|
+
if (parsed.token && parsed.apiUrl && parsed.authKind === "session") {
|
|
287
346
|
return parsed;
|
|
288
347
|
}
|
|
289
348
|
return null;
|
|
@@ -327,21 +386,16 @@ function isEarlyAccessNetworkCreationError(error) {
|
|
|
327
386
|
}
|
|
328
387
|
|
|
329
388
|
class ApiClient {
|
|
389
|
+
credentialKind;
|
|
330
390
|
baseUrl;
|
|
331
391
|
token;
|
|
332
|
-
constructor(baseUrl, token) {
|
|
392
|
+
constructor(baseUrl, token, credentialKind = "session") {
|
|
393
|
+
this.credentialKind = credentialKind;
|
|
333
394
|
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
334
395
|
this.token = token;
|
|
335
396
|
}
|
|
336
397
|
authHeaders() {
|
|
337
|
-
return { "x-api-key": this.token };
|
|
338
|
-
}
|
|
339
|
-
async revokeApiKey(keyId, targetKey = this.token) {
|
|
340
|
-
const res = await this.post("/api/auth/cli-credential/revoke", { keyId, targetKey });
|
|
341
|
-
const body = await res.json();
|
|
342
|
-
if (body.success !== true) {
|
|
343
|
-
throw new Error("API-key revocation was not confirmed");
|
|
344
|
-
}
|
|
398
|
+
return this.credentialKind === "apiKey" ? { "x-api-key": this.token } : { Authorization: `Bearer ${this.token}` };
|
|
345
399
|
}
|
|
346
400
|
async getMe() {
|
|
347
401
|
const res = await this.get("/api/auth/me");
|
|
@@ -357,10 +411,13 @@ class ApiClient {
|
|
|
357
411
|
const params = new URLSearchParams;
|
|
358
412
|
if (opts?.status)
|
|
359
413
|
params.set("status", opts.status);
|
|
414
|
+
if (opts?.statuses)
|
|
415
|
+
params.set("statuses", opts.statuses);
|
|
360
416
|
if (opts?.limit)
|
|
361
417
|
params.set("limit", String(opts.limit));
|
|
362
418
|
const qs = params.toString();
|
|
363
|
-
const
|
|
419
|
+
const base = opts?.intentId ? `/api/intents/${encodeURIComponent(opts.intentId)}/opportunities` : "/api/opportunities";
|
|
420
|
+
const path = qs ? `${base}?${qs}` : base;
|
|
364
421
|
const res = await this.get(path);
|
|
365
422
|
const body = await res.json();
|
|
366
423
|
return body.opportunities;
|
|
@@ -369,11 +426,12 @@ class ApiClient {
|
|
|
369
426
|
const res = await this.get(`/api/opportunities/${id}`);
|
|
370
427
|
return await res.json();
|
|
371
428
|
}
|
|
372
|
-
async updateOpportunityStatus(id, status
|
|
373
|
-
const res = await this.patch(`/api/opportunities/${id}/status`, {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
429
|
+
async updateOpportunityStatus(id, status) {
|
|
430
|
+
const res = await this.patch(`/api/opportunities/${encodeURIComponent(id)}/status`, { status });
|
|
431
|
+
return await res.json();
|
|
432
|
+
}
|
|
433
|
+
async startOpportunityChat(id) {
|
|
434
|
+
const res = await this.post(`/api/opportunities/${encodeURIComponent(id)}/start-chat`, {});
|
|
377
435
|
return await res.json();
|
|
378
436
|
}
|
|
379
437
|
async listIntents(options = {}) {
|
|
@@ -386,6 +444,8 @@ class ApiClient {
|
|
|
386
444
|
body.sourceType = options.sourceType;
|
|
387
445
|
if (options.page !== undefined)
|
|
388
446
|
body.page = options.page;
|
|
447
|
+
if (options.query !== undefined)
|
|
448
|
+
body.q = options.query;
|
|
389
449
|
const res = await this.post("/api/intents/list", body);
|
|
390
450
|
return await res.json();
|
|
391
451
|
}
|
|
@@ -394,17 +454,38 @@ class ApiClient {
|
|
|
394
454
|
const body = await res.json();
|
|
395
455
|
return body.intent;
|
|
396
456
|
}
|
|
397
|
-
async
|
|
398
|
-
const res = await this.post("/api/intents
|
|
399
|
-
proposalId,
|
|
457
|
+
async createIntent(description, networkIds, preparationReceipt) {
|
|
458
|
+
const res = await this.post("/api/intents", {
|
|
400
459
|
description,
|
|
401
|
-
...
|
|
460
|
+
...networkIds?.length ? { networkIds } : {},
|
|
461
|
+
...preparationReceipt ? { preparationReceipt } : {}
|
|
402
462
|
});
|
|
403
|
-
|
|
404
|
-
|
|
463
|
+
return await res.json();
|
|
464
|
+
}
|
|
465
|
+
async prepareIntent(payload, answers = []) {
|
|
466
|
+
const res = await this.post("/api/intents/prepare", { payload, answers });
|
|
467
|
+
return await res.json();
|
|
468
|
+
}
|
|
469
|
+
async updateIntentStatus(id, status) {
|
|
470
|
+
await this.patch(`/api/intents/${encodeURIComponent(id)}/status`, { status });
|
|
405
471
|
}
|
|
406
472
|
async updateIntent(intentId, description) {
|
|
407
|
-
|
|
473
|
+
const res = await this.patch(`/api/intents/${encodeURIComponent(intentId)}`, { description });
|
|
474
|
+
return await res.json();
|
|
475
|
+
}
|
|
476
|
+
async archiveIntent(intentId) {
|
|
477
|
+
await this.patch(`/api/intents/${encodeURIComponent(intentId)}/archive`);
|
|
478
|
+
}
|
|
479
|
+
async listIntentNetworks(intentId) {
|
|
480
|
+
const res = await this.get(`/api/intents/${encodeURIComponent(intentId)}/networks`);
|
|
481
|
+
const body = await res.json();
|
|
482
|
+
return body.networkIds;
|
|
483
|
+
}
|
|
484
|
+
async addIntentToNetwork(intentId, networkId) {
|
|
485
|
+
await this.post(`/api/intents/${encodeURIComponent(intentId)}/networks`, { networkId });
|
|
486
|
+
}
|
|
487
|
+
async removeIntentFromNetwork(intentId, networkId) {
|
|
488
|
+
await this.del(`/api/intents/${encodeURIComponent(intentId)}/networks/${encodeURIComponent(networkId)}`);
|
|
408
489
|
}
|
|
409
490
|
async listNetworks() {
|
|
410
491
|
const res = await this.get("/api/networks");
|
|
@@ -414,14 +495,26 @@ class ApiClient {
|
|
|
414
495
|
joinPolicy: n.joinPolicy ?? n.permissions?.joinPolicy
|
|
415
496
|
}));
|
|
416
497
|
}
|
|
498
|
+
async discoverNetworks() {
|
|
499
|
+
return await (await this.get("/api/networks/discovery/public?page=1&limit=50")).json();
|
|
500
|
+
}
|
|
501
|
+
async listNetworkRequests() {
|
|
502
|
+
return await (await this.get("/api/network-requests")).json();
|
|
503
|
+
}
|
|
504
|
+
async updateNetworkRequest(id, name, purpose) {
|
|
505
|
+
return await (await this.patch(`/api/network-requests/${encodeURIComponent(id)}`, { name, ...purpose ? { purpose } : {} })).json();
|
|
506
|
+
}
|
|
507
|
+
async dismissNetworkRequest(id) {
|
|
508
|
+
await this.del(`/api/network-requests/${encodeURIComponent(id)}`);
|
|
509
|
+
}
|
|
417
510
|
async createNetworkOrRequest(title, prompt) {
|
|
418
511
|
try {
|
|
419
|
-
const
|
|
512
|
+
const res = await this.post("/api/networks", {
|
|
420
513
|
title,
|
|
421
514
|
...prompt ? { prompt } : {}
|
|
422
515
|
});
|
|
423
|
-
const
|
|
424
|
-
return { kind: "created", network:
|
|
516
|
+
const body = await res.json();
|
|
517
|
+
return { kind: "created", network: body.network };
|
|
425
518
|
} catch (error) {
|
|
426
519
|
if (!isEarlyAccessNetworkCreationError(error))
|
|
427
520
|
throw error;
|
|
@@ -452,6 +545,14 @@ class ApiClient {
|
|
|
452
545
|
async leaveNetwork(id) {
|
|
453
546
|
await this.post(`/api/networks/${id}/leave`, {});
|
|
454
547
|
}
|
|
548
|
+
async updateNetwork(id, settings) {
|
|
549
|
+
const res = await this.put(`/api/networks/${id}`, settings);
|
|
550
|
+
const body = await res.json();
|
|
551
|
+
return body.network;
|
|
552
|
+
}
|
|
553
|
+
async deleteNetwork(id) {
|
|
554
|
+
await this.del(`/api/networks/${id}`);
|
|
555
|
+
}
|
|
455
556
|
async inviteNetworkMember(networkId, email, name) {
|
|
456
557
|
const res = await this.post(`/api/networks/${networkId}/members/invite`, {
|
|
457
558
|
email,
|
|
@@ -481,18 +582,23 @@ class ApiClient {
|
|
|
481
582
|
const body = await res.json();
|
|
482
583
|
return body.messages;
|
|
483
584
|
}
|
|
484
|
-
async sendMessage(conversationId, text) {
|
|
585
|
+
async sendMessage(conversationId, text, intentId, questionId) {
|
|
485
586
|
const res = await this.post(`/api/conversations/${conversationId}/messages`, {
|
|
486
|
-
parts: [{
|
|
587
|
+
parts: [{ kind: "text", text }],
|
|
588
|
+
...intentId ? { metadata: { intentId } } : {},
|
|
589
|
+
...questionId ? { questionId } : {}
|
|
487
590
|
});
|
|
488
591
|
const body = await res.json();
|
|
489
592
|
return body.message;
|
|
490
593
|
}
|
|
594
|
+
async answerAgentQuestions(intentId, answers) {
|
|
595
|
+
return await (await this.post("/api/conversations/agent/answers", { intentId, answers })).json();
|
|
596
|
+
}
|
|
491
597
|
async hideConversation(conversationId) {
|
|
492
598
|
await this.del(`/api/conversations/${conversationId}`);
|
|
493
599
|
}
|
|
494
|
-
async
|
|
495
|
-
const res = await fetch(`${this.baseUrl}/api/
|
|
600
|
+
async streamEvents() {
|
|
601
|
+
const res = await fetch(`${this.baseUrl}/api/events`, {
|
|
496
602
|
headers: {
|
|
497
603
|
...this.authHeaders(),
|
|
498
604
|
Accept: "text/event-stream"
|
|
@@ -504,16 +610,13 @@ class ApiClient {
|
|
|
504
610
|
return res;
|
|
505
611
|
}
|
|
506
612
|
async listNegotiations(opts) {
|
|
507
|
-
const me = await this.getMe();
|
|
508
613
|
const params = new URLSearchParams;
|
|
509
|
-
if (opts?.
|
|
510
|
-
params.set("
|
|
511
|
-
if (opts?.
|
|
512
|
-
params.set("
|
|
513
|
-
if (opts?.since)
|
|
514
|
-
params.set("since", opts.since);
|
|
614
|
+
if (opts?.intentId)
|
|
615
|
+
params.set("intentId", opts.intentId);
|
|
616
|
+
if (opts?.state)
|
|
617
|
+
params.set("state", opts.state);
|
|
515
618
|
const qs = params.toString();
|
|
516
|
-
const path =
|
|
619
|
+
const path = `/api/negotiations${qs ? `?${qs}` : ""}`;
|
|
517
620
|
const res = await this.get(path);
|
|
518
621
|
const body = await res.json();
|
|
519
622
|
return body.negotiations;
|
|
@@ -522,18 +625,37 @@ class ApiClient {
|
|
|
522
625
|
const res = await this.post("/api/enrichment/enrich", {});
|
|
523
626
|
return await res.json();
|
|
524
627
|
}
|
|
525
|
-
async
|
|
526
|
-
|
|
628
|
+
async updateProfile(fields) {
|
|
629
|
+
const body = await (await this.patch("/api/auth/profile/update", fields)).json();
|
|
630
|
+
return body.user;
|
|
527
631
|
}
|
|
528
|
-
async
|
|
529
|
-
|
|
632
|
+
async scrapeUrl(url, objective) {
|
|
633
|
+
const res = await this.post("/api/scrape", { url, ...objective ? { objective } : {} });
|
|
634
|
+
return await res.json();
|
|
530
635
|
}
|
|
531
|
-
async
|
|
532
|
-
|
|
636
|
+
async readDocs(topic) {
|
|
637
|
+
const path = topic ? `/api/docs?${new URLSearchParams({ topic })}` : "/api/docs";
|
|
638
|
+
return (await this.get(path)).json();
|
|
533
639
|
}
|
|
534
|
-
async
|
|
535
|
-
|
|
536
|
-
|
|
640
|
+
async getAgent() {
|
|
641
|
+
return (await this.get("/api/agents/me")).json();
|
|
642
|
+
}
|
|
643
|
+
async getNegotiation(opportunityId) {
|
|
644
|
+
const body = await (await this.get(`/api/opportunities/${encodeURIComponent(opportunityId)}/negotiation`)).json();
|
|
645
|
+
return body.negotiation;
|
|
646
|
+
}
|
|
647
|
+
async submitNegotiationTurn(opportunityId, turn) {
|
|
648
|
+
const body = await (await this.post(`/api/opportunities/${encodeURIComponent(opportunityId)}/negotiation/turns`, turn)).json();
|
|
649
|
+
return body.negotiation;
|
|
650
|
+
}
|
|
651
|
+
async getAgentConversation(intentId) {
|
|
652
|
+
return (await this.get(`/api/conversations/agent/messages?${new URLSearchParams({ intentId })}`)).json();
|
|
653
|
+
}
|
|
654
|
+
async confirmProfile() {
|
|
655
|
+
return (await this.post("/api/auth/onboarding/confirm-profile", {})).json();
|
|
656
|
+
}
|
|
657
|
+
async completeOnboarding(intentId) {
|
|
658
|
+
return (await this.post("/api/auth/onboarding/complete", { intentId })).json();
|
|
537
659
|
}
|
|
538
660
|
async get(path) {
|
|
539
661
|
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
@@ -558,6 +680,19 @@ class ApiClient {
|
|
|
558
680
|
}
|
|
559
681
|
return res;
|
|
560
682
|
}
|
|
683
|
+
async put(path, body) {
|
|
684
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
685
|
+
method: "PUT",
|
|
686
|
+
headers: {
|
|
687
|
+
"Content-Type": "application/json",
|
|
688
|
+
...this.authHeaders()
|
|
689
|
+
},
|
|
690
|
+
...body !== undefined ? { body: JSON.stringify(body) } : {}
|
|
691
|
+
});
|
|
692
|
+
if (!res.ok)
|
|
693
|
+
await this.handleError(res);
|
|
694
|
+
return res;
|
|
695
|
+
}
|
|
561
696
|
async patch(path, body) {
|
|
562
697
|
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
563
698
|
method: "PATCH",
|
|
@@ -582,9 +717,6 @@ class ApiClient {
|
|
|
582
717
|
return res;
|
|
583
718
|
}
|
|
584
719
|
async handleError(res) {
|
|
585
|
-
if (res.status === 401) {
|
|
586
|
-
throw new ApiError("Session expired or invalid. Run `index login` to re-authenticate.", res.status);
|
|
587
|
-
}
|
|
588
720
|
let message = `HTTP ${res.status}`;
|
|
589
721
|
let response;
|
|
590
722
|
try {
|
|
@@ -603,23 +735,33 @@ class ApiClient {
|
|
|
603
735
|
import { randomBytes } from "node:crypto";
|
|
604
736
|
import { createServer } from "node:http";
|
|
605
737
|
|
|
606
|
-
// src/auth.
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
738
|
+
// src/auth.session.ts
|
|
739
|
+
var DEVICE_CLIENT_ID = "index-device";
|
|
740
|
+
async function redeemDeviceCode(baseUrl, deviceCode) {
|
|
741
|
+
const response = await fetch(`${baseUrl}/api/auth/device/token`, {
|
|
742
|
+
method: "POST",
|
|
743
|
+
headers: { "Content-Type": "application/json", "User-Agent": "index-cli" },
|
|
744
|
+
body: JSON.stringify({
|
|
745
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
746
|
+
device_code: deviceCode,
|
|
747
|
+
client_id: DEVICE_CLIENT_ID
|
|
748
|
+
})
|
|
749
|
+
});
|
|
750
|
+
const body = await response.json().catch(() => null);
|
|
751
|
+
if (!response.ok || !body?.access_token) {
|
|
752
|
+
throw new Error(body?.error_description ?? "Could not complete device sign-in.");
|
|
753
|
+
}
|
|
754
|
+
return body.access_token;
|
|
755
|
+
}
|
|
756
|
+
async function revokeSession(baseUrl, token) {
|
|
615
757
|
try {
|
|
616
|
-
await
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
return
|
|
621
|
-
|
|
622
|
-
|
|
758
|
+
const response = await fetch(`${baseUrl}/api/auth/sign-out`, {
|
|
759
|
+
method: "POST",
|
|
760
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
761
|
+
});
|
|
762
|
+
return response.ok;
|
|
763
|
+
} catch {
|
|
764
|
+
return false;
|
|
623
765
|
}
|
|
624
766
|
}
|
|
625
767
|
|
|
@@ -676,33 +818,28 @@ async function handleLogin(apiUrl, appUrl, store, options = {}) {
|
|
|
676
818
|
return;
|
|
677
819
|
}
|
|
678
820
|
stateConsumed = true;
|
|
679
|
-
const
|
|
680
|
-
|
|
681
|
-
if (apiKey && keyId) {
|
|
821
|
+
const deviceCode = url.searchParams.get("device_code");
|
|
822
|
+
if (deviceCode) {
|
|
682
823
|
try {
|
|
683
|
-
const
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
resolveCallback({ success: false, error: "Failed to save CLI credentials." });
|
|
824
|
+
const token = await redeemDeviceCode(baseUrl, deviceCode);
|
|
825
|
+
await store.save({ token, apiUrl: baseUrl, authKind: "session" });
|
|
826
|
+
if (previousCredentials)
|
|
827
|
+
await revokeSession(previousCredentials.apiUrl, previousCredentials.token);
|
|
828
|
+
resolveCallback({ success: true });
|
|
829
|
+
} catch (error) {
|
|
830
|
+
const message = error instanceof Error ? error.message : "Failed to save CLI credentials.";
|
|
831
|
+
resolveCallback({ success: false, error: message });
|
|
692
832
|
res.writeHead(500, { "Content-Type": "text/html" });
|
|
693
|
-
res.end(callbackHtml("Authorization failed", "CLI
|
|
833
|
+
res.end(callbackHtml("Authorization failed", "CLI sign-in could not be completed. Return to the terminal and try again."));
|
|
694
834
|
return;
|
|
695
835
|
}
|
|
696
836
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
697
|
-
res.end(callbackHtml("
|
|
837
|
+
res.end(callbackHtml("Authentication complete", "You can close this window and return to the terminal.", true));
|
|
698
838
|
return;
|
|
699
839
|
}
|
|
700
|
-
resolveCallback({
|
|
701
|
-
success: false,
|
|
702
|
-
error: apiKey ? "CLI API-key callback did not include its key ID." : "No CLI credential received in callback."
|
|
703
|
-
});
|
|
840
|
+
resolveCallback({ success: false, error: "No device code received in callback." });
|
|
704
841
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
705
|
-
res.end(callbackHtml("Authorization failed", "Incomplete
|
|
842
|
+
res.end(callbackHtml("Authorization failed", "Incomplete sign-in received. Please try again."));
|
|
706
843
|
});
|
|
707
844
|
let listenSettled = false;
|
|
708
845
|
let rejectListen = null;
|
|
@@ -813,168 +950,64 @@ p{font-size:14px;font-weight:500;margin:0;color:rgba(244,251,246,0.78)}
|
|
|
813
950
|
}
|
|
814
951
|
|
|
815
952
|
// src/logout.command.ts
|
|
816
|
-
async function handleLogout(store
|
|
953
|
+
async function handleLogout(store) {
|
|
817
954
|
const credentials = await store.load();
|
|
818
955
|
if (!credentials) {
|
|
819
956
|
return { success: true, message: "Already logged out." };
|
|
820
957
|
}
|
|
821
|
-
const
|
|
822
|
-
try {
|
|
823
|
-
await createClient(credentials.apiUrl, credentials.token).revokeApiKey(credentials.keyId, credentials.token);
|
|
824
|
-
} catch (error) {
|
|
825
|
-
const detail = error instanceof Error ? ` ${error.message}` : "";
|
|
826
|
-
return {
|
|
827
|
-
success: false,
|
|
828
|
-
warning: `Logout could not revoke the stored CLI API key, so credentials were retained.${detail}`
|
|
829
|
-
};
|
|
830
|
-
}
|
|
958
|
+
const revoked = await revokeSession(credentials.apiUrl, credentials.token);
|
|
831
959
|
try {
|
|
832
960
|
await store.clear();
|
|
833
961
|
} catch {
|
|
834
962
|
return {
|
|
835
963
|
success: false,
|
|
836
|
-
warning: "
|
|
964
|
+
warning: "Local credential cleanup failed. Remove the local credentials file manually before signing in again."
|
|
837
965
|
};
|
|
838
966
|
}
|
|
839
|
-
return {
|
|
967
|
+
return {
|
|
968
|
+
success: true,
|
|
969
|
+
message: revoked ? "Logged out." : "Logged out locally. The session could not be reached — revoke it in Index web settings if this machine is not yours."
|
|
970
|
+
};
|
|
840
971
|
}
|
|
841
972
|
|
|
842
|
-
// src/output/index.ts
|
|
843
|
-
var exports_output = {};
|
|
844
|
-
__export(exports_output, {
|
|
845
|
-
wordWrap: () => wordWrap,
|
|
846
|
-
warn: () => warn,
|
|
847
|
-
toolActivity: () => toolActivity,
|
|
848
|
-
success: () => success,
|
|
849
|
-
stripAnsi: () => stripAnsi,
|
|
850
|
-
status: () => status,
|
|
851
|
-
raw: () => raw,
|
|
852
|
-
profileCard: () => profileCard,
|
|
853
|
-
padTo: () => padTo,
|
|
854
|
-
opportunityTable: () => opportunityTable,
|
|
855
|
-
opportunityCard: () => opportunityCard,
|
|
856
|
-
networkTable: () => networkTable,
|
|
857
|
-
networkCard: () => networkCard,
|
|
858
|
-
messageList: () => messageList,
|
|
859
|
-
memberTable: () => memberTable,
|
|
860
|
-
intentTable: () => intentTable,
|
|
861
|
-
intentCard: () => intentCard,
|
|
862
|
-
info: () => info,
|
|
863
|
-
humanizeToolName: () => humanizeToolName,
|
|
864
|
-
heading: () => heading,
|
|
865
|
-
error: () => error,
|
|
866
|
-
dim: () => dim,
|
|
867
|
-
conversationTable: () => conversationTable,
|
|
868
|
-
conversationCard: () => conversationCard,
|
|
869
|
-
contactTable: () => contactTable,
|
|
870
|
-
confidenceBar: () => confidenceBar,
|
|
871
|
-
clearStatus: () => clearStatus,
|
|
872
|
-
chatHeader: () => chatHeader,
|
|
873
|
-
YELLOW: () => YELLOW,
|
|
874
|
-
WHITE: () => WHITE,
|
|
875
|
-
USER_PROMPT: () => USER_PROMPT,
|
|
876
|
-
RESET: () => RESET,
|
|
877
|
-
RED: () => RED,
|
|
878
|
-
PROMPT_STR: () => PROMPT_STR,
|
|
879
|
-
ORANGE: () => ORANGE,
|
|
880
|
-
MarkdownRenderer: () => MarkdownRenderer,
|
|
881
|
-
MAGENTA: () => MAGENTA,
|
|
882
|
-
ITALIC: () => ITALIC,
|
|
883
|
-
GREEN: () => GREEN,
|
|
884
|
-
GRAY: () => GRAY,
|
|
885
|
-
DIM: () => DIM,
|
|
886
|
-
CYAN: () => CYAN,
|
|
887
|
-
BOLD: () => BOLD,
|
|
888
|
-
BLUE: () => BLUE,
|
|
889
|
-
AGENT_TEXT: () => AGENT_TEXT
|
|
890
|
-
});
|
|
891
|
-
|
|
892
973
|
// src/output/base.ts
|
|
893
974
|
var RESET = "\x1B[0m";
|
|
894
975
|
var BOLD = "\x1B[1m";
|
|
895
976
|
var DIM = "\x1B[2m";
|
|
896
|
-
var ITALIC = "\x1B[3m";
|
|
897
977
|
var RED = "\x1B[31m";
|
|
898
978
|
var GREEN = "\x1B[32m";
|
|
899
979
|
var YELLOW = "\x1B[33m";
|
|
900
980
|
var BLUE = "\x1B[34m";
|
|
901
|
-
var MAGENTA = "\x1B[35m";
|
|
902
981
|
var CYAN = "\x1B[36m";
|
|
903
982
|
var WHITE = "\x1B[37m";
|
|
904
983
|
var GRAY = "\x1B[90m";
|
|
905
|
-
var ORANGE = "\x1B[38;5;208m";
|
|
906
984
|
var AGENT_TEXT = "\x1B[38;5;252m";
|
|
907
985
|
var USER_PROMPT = CYAN;
|
|
908
986
|
function error(message, exitCode) {
|
|
987
|
+
if (process.argv.includes("--json"))
|
|
988
|
+
throw new Error(message);
|
|
909
989
|
console.error(`${RED}${BOLD}error${RESET}${RED}: ${message}${RESET}`);
|
|
910
|
-
|
|
990
|
+
process.exitCode = exitCode ?? 1;
|
|
991
|
+
if (exitCode !== undefined)
|
|
911
992
|
process.exit(exitCode);
|
|
912
|
-
}
|
|
913
993
|
}
|
|
914
994
|
function success(message) {
|
|
915
995
|
console.log(`${GREEN}${BOLD}+${RESET} ${message}`);
|
|
916
996
|
}
|
|
917
997
|
function info(message) {
|
|
918
|
-
console.
|
|
998
|
+
console.error(`${CYAN}${message}${RESET}`);
|
|
919
999
|
}
|
|
920
1000
|
function warn(message) {
|
|
921
1001
|
console.warn(`${YELLOW}${message}${RESET}`);
|
|
922
1002
|
}
|
|
923
1003
|
function dim(message) {
|
|
924
|
-
console.
|
|
1004
|
+
console.error(`${GRAY}${message}${RESET}`);
|
|
925
1005
|
}
|
|
926
1006
|
function heading(message) {
|
|
927
1007
|
console.log(`
|
|
928
1008
|
${BOLD}${message}${RESET}`);
|
|
929
1009
|
}
|
|
930
|
-
function chatHeader() {
|
|
931
|
-
console.log();
|
|
932
|
-
console.log(` ${BOLD}${CYAN}I N D E X${RESET} ${GRAY}chat${RESET}`);
|
|
933
|
-
console.log(` ${GRAY}─────────────────────────────────────${RESET}`);
|
|
934
|
-
console.log(` ${GRAY}Type your message. "exit" or Ctrl+C to quit.${RESET}`);
|
|
935
|
-
console.log();
|
|
936
|
-
}
|
|
937
1010
|
var PROMPT_STR = `${USER_PROMPT}${BOLD}> ${RESET}`;
|
|
938
|
-
function raw(text) {
|
|
939
|
-
process.stdout.write(text);
|
|
940
|
-
}
|
|
941
|
-
function status(message) {
|
|
942
|
-
process.stderr.write(`\r ${GRAY}${message}${RESET}\x1B[K`);
|
|
943
|
-
}
|
|
944
|
-
function clearStatus() {
|
|
945
|
-
process.stderr.write("\r\x1B[K");
|
|
946
|
-
}
|
|
947
|
-
function toolActivity(description) {
|
|
948
|
-
process.stderr.write(`\r\x1B[K${ORANGE}> ${description}${RESET}
|
|
949
|
-
`);
|
|
950
|
-
}
|
|
951
|
-
var TOOL_DESCRIPTIONS = {
|
|
952
|
-
read_user_contexts: "Reading your profile...",
|
|
953
|
-
create_user_context: "Creating your profile...",
|
|
954
|
-
update_user_context: "Updating your profile...",
|
|
955
|
-
read_intents: "Fetching your active signals...",
|
|
956
|
-
create_intent: "Creating a new signal...",
|
|
957
|
-
update_intent: "Updating signal...",
|
|
958
|
-
delete_intent: "Removing signal...",
|
|
959
|
-
create_intent_index: "Saving signal to index...",
|
|
960
|
-
read_intent_indexes: "Fetching signals in index...",
|
|
961
|
-
delete_intent_index: "Removing signal from index...",
|
|
962
|
-
read_networks: "Checking your communities...",
|
|
963
|
-
create_network: "Creating a new community...",
|
|
964
|
-
update_network: "Updating community...",
|
|
965
|
-
delete_network: "Deleting community...",
|
|
966
|
-
create_network_membership: "Adding member to community...",
|
|
967
|
-
read_network_memberships: "Fetching community memberships...",
|
|
968
|
-
list_opportunities: "Listing your opportunities...",
|
|
969
|
-
update_opportunity: "Updating opportunity status...",
|
|
970
|
-
scrape_url: "Reading content from URL...",
|
|
971
|
-
read_docs: "Looking up documentation...",
|
|
972
|
-
list_contacts: "Listing your contacts...",
|
|
973
|
-
remove_contact: "Removing contact..."
|
|
974
|
-
};
|
|
975
|
-
function humanizeToolName(name) {
|
|
976
|
-
return TOOL_DESCRIPTIONS[name] ?? name.replace(/_/g, " ") + "...";
|
|
977
|
-
}
|
|
978
1011
|
function wordWrap(text, maxWidth) {
|
|
979
1012
|
const lines = [];
|
|
980
1013
|
const words = text.split(/\s+/);
|
|
@@ -1005,220 +1038,6 @@ function padTo(cellWidth, plainText) {
|
|
|
1005
1038
|
function stripAnsi(str) {
|
|
1006
1039
|
return str.replace(/\x1b\[[0-9;]*m/g, "");
|
|
1007
1040
|
}
|
|
1008
|
-
// src/output/markdown.ts
|
|
1009
|
-
class MarkdownRenderer {
|
|
1010
|
-
buffer = "";
|
|
1011
|
-
inCodeBlock = false;
|
|
1012
|
-
codeBlockLang = "";
|
|
1013
|
-
codeBlockContent = "";
|
|
1014
|
-
pristine = true;
|
|
1015
|
-
write(text) {
|
|
1016
|
-
this.buffer += text;
|
|
1017
|
-
this.flush();
|
|
1018
|
-
}
|
|
1019
|
-
flush() {
|
|
1020
|
-
while (this.buffer.length > 0) {
|
|
1021
|
-
if (this.inCodeBlock) {
|
|
1022
|
-
const endIdx = this.buffer.indexOf("```");
|
|
1023
|
-
if (endIdx !== -1) {
|
|
1024
|
-
this.codeBlockContent += this.buffer.slice(0, endIdx);
|
|
1025
|
-
this.buffer = this.buffer.slice(endIdx + 3);
|
|
1026
|
-
if (this.buffer.startsWith(`
|
|
1027
|
-
`)) {
|
|
1028
|
-
this.buffer = this.buffer.slice(1);
|
|
1029
|
-
}
|
|
1030
|
-
this.renderCodeBlock();
|
|
1031
|
-
this.inCodeBlock = false;
|
|
1032
|
-
this.codeBlockLang = "";
|
|
1033
|
-
this.codeBlockContent = "";
|
|
1034
|
-
continue;
|
|
1035
|
-
}
|
|
1036
|
-
this.codeBlockContent += this.buffer;
|
|
1037
|
-
this.buffer = "";
|
|
1038
|
-
return;
|
|
1039
|
-
}
|
|
1040
|
-
const codeBlockMatch = this.buffer.match(/^```([^\n]*)\n/);
|
|
1041
|
-
if (codeBlockMatch) {
|
|
1042
|
-
this.codeBlockLang = codeBlockMatch[1].trim();
|
|
1043
|
-
this.buffer = this.buffer.slice(codeBlockMatch[0].length);
|
|
1044
|
-
this.inCodeBlock = true;
|
|
1045
|
-
this.codeBlockContent = "";
|
|
1046
|
-
continue;
|
|
1047
|
-
}
|
|
1048
|
-
if (this.buffer.startsWith("```")) {
|
|
1049
|
-
return;
|
|
1050
|
-
}
|
|
1051
|
-
const nlIdx = this.buffer.indexOf(`
|
|
1052
|
-
`);
|
|
1053
|
-
if (nlIdx === -1) {
|
|
1054
|
-
return;
|
|
1055
|
-
}
|
|
1056
|
-
const line = this.buffer.slice(0, nlIdx);
|
|
1057
|
-
this.buffer = this.buffer.slice(nlIdx + 1);
|
|
1058
|
-
this.emitLine(line);
|
|
1059
|
-
}
|
|
1060
|
-
}
|
|
1061
|
-
emitLine(line) {
|
|
1062
|
-
if (this.pristine) {
|
|
1063
|
-
process.stdout.write(`
|
|
1064
|
-
`);
|
|
1065
|
-
this.pristine = false;
|
|
1066
|
-
}
|
|
1067
|
-
const rendered = this.renderLine(line);
|
|
1068
|
-
process.stdout.write(rendered + `
|
|
1069
|
-
`);
|
|
1070
|
-
}
|
|
1071
|
-
renderLine(line) {
|
|
1072
|
-
const bulletMatch = line.match(/^(\s*)([-*])\s+(.*)$/);
|
|
1073
|
-
if (bulletMatch) {
|
|
1074
|
-
const [, indent, , content] = bulletMatch;
|
|
1075
|
-
return `${indent} ${CYAN}*${RESET} ${this.renderInline(content)}`;
|
|
1076
|
-
}
|
|
1077
|
-
const numMatch = line.match(/^(\s*)(\d+)\.\s+(.*)$/);
|
|
1078
|
-
if (numMatch) {
|
|
1079
|
-
const [, indent, num, content] = numMatch;
|
|
1080
|
-
return `${indent} ${CYAN}${num}.${RESET} ${this.renderInline(content)}`;
|
|
1081
|
-
}
|
|
1082
|
-
if (line.startsWith("### ")) {
|
|
1083
|
-
return `${BOLD}${WHITE}${line.slice(4)}${RESET}`;
|
|
1084
|
-
}
|
|
1085
|
-
if (line.startsWith("## ")) {
|
|
1086
|
-
return `${BOLD}${WHITE}${line.slice(3)}${RESET}`;
|
|
1087
|
-
}
|
|
1088
|
-
if (line.startsWith("# ")) {
|
|
1089
|
-
return `${BOLD}${WHITE}${line.slice(2)}${RESET}`;
|
|
1090
|
-
}
|
|
1091
|
-
return this.renderInline(line);
|
|
1092
|
-
}
|
|
1093
|
-
renderInline(text) {
|
|
1094
|
-
text = text.replace(/\*\*\*(.+?)\*\*\*/g, `${BOLD}${ITALIC}${WHITE}$1${RESET}${AGENT_TEXT}`);
|
|
1095
|
-
text = text.replace(/\*\*(.+?)\*\*/g, `${BOLD}${WHITE}$1${RESET}${AGENT_TEXT}`);
|
|
1096
|
-
text = text.replace(/(?<!\*)\*([^*]+?)\*(?!\*)/g, `${ITALIC}$1${RESET}${AGENT_TEXT}`);
|
|
1097
|
-
text = text.replace(/`([^`]+)`/g, `${CYAN}$1${RESET}${AGENT_TEXT}`);
|
|
1098
|
-
return `${AGENT_TEXT}${text}${RESET}`;
|
|
1099
|
-
}
|
|
1100
|
-
renderCodeBlock() {
|
|
1101
|
-
const lang = this.codeBlockLang;
|
|
1102
|
-
const content = this.codeBlockContent.trimEnd();
|
|
1103
|
-
if (!this.pristine) {
|
|
1104
|
-
process.stdout.write(`
|
|
1105
|
-
`);
|
|
1106
|
-
}
|
|
1107
|
-
this.pristine = false;
|
|
1108
|
-
if (lang === "intent_proposal") {
|
|
1109
|
-
this.renderIntentProposal(content);
|
|
1110
|
-
return;
|
|
1111
|
-
}
|
|
1112
|
-
if (lang === "opportunity") {
|
|
1113
|
-
this.renderOpportunity(content);
|
|
1114
|
-
return;
|
|
1115
|
-
}
|
|
1116
|
-
const border = `${GRAY}|${RESET}`;
|
|
1117
|
-
if (lang) {
|
|
1118
|
-
process.stdout.write(` ${GRAY}--- ${lang} ${"─".repeat(Math.max(0, 40 - lang.length))}${RESET}
|
|
1119
|
-
`);
|
|
1120
|
-
} else {
|
|
1121
|
-
process.stdout.write(` ${GRAY}${"─".repeat(46)}${RESET}
|
|
1122
|
-
`);
|
|
1123
|
-
}
|
|
1124
|
-
for (const line of content.split(`
|
|
1125
|
-
`)) {
|
|
1126
|
-
process.stdout.write(` ${border} ${CYAN}${line}${RESET}
|
|
1127
|
-
`);
|
|
1128
|
-
}
|
|
1129
|
-
process.stdout.write(` ${GRAY}${"─".repeat(46)}${RESET}
|
|
1130
|
-
|
|
1131
|
-
`);
|
|
1132
|
-
}
|
|
1133
|
-
renderIntentProposal(content) {
|
|
1134
|
-
try {
|
|
1135
|
-
const data = JSON.parse(content);
|
|
1136
|
-
const desc = data.description ?? content;
|
|
1137
|
-
const confidence = data.confidence;
|
|
1138
|
-
process.stdout.write(` ${MAGENTA}+${"─".repeat(56)}+${RESET}
|
|
1139
|
-
`);
|
|
1140
|
-
process.stdout.write(` ${MAGENTA}|${RESET} ${BOLD}${MAGENTA}Signal Proposal${RESET}${" ".repeat(40)}${MAGENTA}|${RESET}
|
|
1141
|
-
`);
|
|
1142
|
-
process.stdout.write(` ${MAGENTA}|${RESET}${" ".repeat(56)}${MAGENTA}|${RESET}
|
|
1143
|
-
`);
|
|
1144
|
-
const wrapped = wordWrap(desc, 52);
|
|
1145
|
-
for (const line of wrapped) {
|
|
1146
|
-
const pad = Math.max(0, 54 - line.length);
|
|
1147
|
-
process.stdout.write(` ${MAGENTA}|${RESET} ${AGENT_TEXT}${line}${RESET}${" ".repeat(pad)}${MAGENTA}|${RESET}
|
|
1148
|
-
`);
|
|
1149
|
-
}
|
|
1150
|
-
if (confidence !== undefined) {
|
|
1151
|
-
process.stdout.write(` ${MAGENTA}|${RESET}${" ".repeat(56)}${MAGENTA}|${RESET}
|
|
1152
|
-
`);
|
|
1153
|
-
const bar = confidenceBar(confidence);
|
|
1154
|
-
process.stdout.write(` ${MAGENTA}|${RESET} ${GRAY}Confidence: ${bar}${RESET}${" ".repeat(24)}${MAGENTA}|${RESET}
|
|
1155
|
-
`);
|
|
1156
|
-
}
|
|
1157
|
-
process.stdout.write(` ${MAGENTA}+${"─".repeat(56)}+${RESET}
|
|
1158
|
-
|
|
1159
|
-
`);
|
|
1160
|
-
} catch {
|
|
1161
|
-
process.stdout.write(` ${GRAY}${content}${RESET}
|
|
1162
|
-
|
|
1163
|
-
`);
|
|
1164
|
-
}
|
|
1165
|
-
}
|
|
1166
|
-
renderOpportunity(content) {
|
|
1167
|
-
try {
|
|
1168
|
-
const data = JSON.parse(content);
|
|
1169
|
-
process.stdout.write(` ${BLUE}+${"─".repeat(56)}+${RESET}
|
|
1170
|
-
`);
|
|
1171
|
-
process.stdout.write(` ${BLUE}|${RESET} ${BOLD}${BLUE}Opportunity${RESET}${" ".repeat(44)}${BLUE}|${RESET}
|
|
1172
|
-
`);
|
|
1173
|
-
if (data.title) {
|
|
1174
|
-
const pad = Math.max(0, 54 - data.title.length);
|
|
1175
|
-
process.stdout.write(` ${BLUE}|${RESET} ${BOLD}${data.title}${RESET}${" ".repeat(pad)}${BLUE}|${RESET}
|
|
1176
|
-
`);
|
|
1177
|
-
}
|
|
1178
|
-
if (data.description) {
|
|
1179
|
-
process.stdout.write(` ${BLUE}|${RESET}${" ".repeat(56)}${BLUE}|${RESET}
|
|
1180
|
-
`);
|
|
1181
|
-
const wrapped = wordWrap(data.description, 52);
|
|
1182
|
-
for (const line of wrapped) {
|
|
1183
|
-
const pad = Math.max(0, 54 - line.length);
|
|
1184
|
-
process.stdout.write(` ${BLUE}|${RESET} ${AGENT_TEXT}${line}${RESET}${" ".repeat(pad)}${BLUE}|${RESET}
|
|
1185
|
-
`);
|
|
1186
|
-
}
|
|
1187
|
-
}
|
|
1188
|
-
process.stdout.write(` ${BLUE}+${"─".repeat(56)}+${RESET}
|
|
1189
|
-
|
|
1190
|
-
`);
|
|
1191
|
-
} catch {
|
|
1192
|
-
process.stdout.write(` ${GRAY}${content}${RESET}
|
|
1193
|
-
|
|
1194
|
-
`);
|
|
1195
|
-
}
|
|
1196
|
-
}
|
|
1197
|
-
reset(reason) {
|
|
1198
|
-
if (this.buffer.length > 0 || this.inCodeBlock) {
|
|
1199
|
-
this.buffer = "";
|
|
1200
|
-
this.inCodeBlock = false;
|
|
1201
|
-
this.codeBlockContent = "";
|
|
1202
|
-
this.codeBlockLang = "";
|
|
1203
|
-
}
|
|
1204
|
-
if (!this.pristine) {
|
|
1205
|
-
process.stdout.write(`
|
|
1206
|
-
${GRAY}--- retrying${reason ? `: ${reason}` : ""} ---${RESET}
|
|
1207
|
-
`);
|
|
1208
|
-
}
|
|
1209
|
-
this.pristine = true;
|
|
1210
|
-
}
|
|
1211
|
-
finalize() {
|
|
1212
|
-
if (this.inCodeBlock) {
|
|
1213
|
-
this.renderCodeBlock();
|
|
1214
|
-
this.inCodeBlock = false;
|
|
1215
|
-
}
|
|
1216
|
-
if (this.buffer.length > 0) {
|
|
1217
|
-
this.emitLine(this.buffer);
|
|
1218
|
-
this.buffer = "";
|
|
1219
|
-
}
|
|
1220
|
-
}
|
|
1221
|
-
}
|
|
1222
1041
|
// src/output/formatters.ts
|
|
1223
1042
|
function profileCard(data) {
|
|
1224
1043
|
const lines = [];
|
|
@@ -1228,9 +1047,8 @@ function profileCard(data) {
|
|
|
1228
1047
|
lines.push("");
|
|
1229
1048
|
lines.push(hline);
|
|
1230
1049
|
const displayName = data.name ?? "(unnamed)";
|
|
1231
|
-
const
|
|
1232
|
-
|
|
1233
|
-
lines.push(` ${border("|")} ${nameContent}${padTo(W - 2, stripAnsi(displayName + (data.isGhost ? " [ghost]" : "")))}${border("|")}`);
|
|
1050
|
+
const nameContent = `${BOLD}${WHITE}${displayName}${RESET}`;
|
|
1051
|
+
lines.push(` ${border("|")} ${nameContent}${padTo(W - 2, stripAnsi(displayName))}${border("|")}`);
|
|
1234
1052
|
if (data.intro) {
|
|
1235
1053
|
lines.push(` ${border("|")}${" ".repeat(W)}${border("|")}`);
|
|
1236
1054
|
const wrapped = wordWrap(data.intro, W - 4);
|
|
@@ -1265,19 +1083,6 @@ function profileCard(data) {
|
|
|
1265
1083
|
console.log(output);
|
|
1266
1084
|
return output;
|
|
1267
1085
|
}
|
|
1268
|
-
function contactTable(contacts) {
|
|
1269
|
-
if (contacts.length === 0) {
|
|
1270
|
-
console.log(" No contacts yet.");
|
|
1271
|
-
return;
|
|
1272
|
-
}
|
|
1273
|
-
const nameWidth = Math.max(6, ...contacts.map((c) => c.name.length));
|
|
1274
|
-
const header = ` ${"Name".padEnd(nameWidth)} Email`;
|
|
1275
|
-
console.log(`${BOLD}${header}${RESET}`);
|
|
1276
|
-
for (const c of contacts) {
|
|
1277
|
-
const ghost = c.isGhost ? ` ${DIM}(ghost)${RESET}` : "";
|
|
1278
|
-
console.log(` ${c.name.padEnd(nameWidth)} ${c.email}${ghost}`);
|
|
1279
|
-
}
|
|
1280
|
-
}
|
|
1281
1086
|
function intentTable(intents) {
|
|
1282
1087
|
if (intents.length === 0) {
|
|
1283
1088
|
dim(" No signals found.");
|
|
@@ -1293,7 +1098,7 @@ function intentTable(intents) {
|
|
|
1293
1098
|
for (const intent of intents) {
|
|
1294
1099
|
const shortId = intent.id.slice(0, 8);
|
|
1295
1100
|
const desc = (intent.summary ?? intent.payload).slice(0, descWidth);
|
|
1296
|
-
const
|
|
1101
|
+
const status = (intent.status ?? "").padEnd(statusWidth);
|
|
1297
1102
|
const source = (intent.sourceType ?? "-").padEnd(sourceWidth);
|
|
1298
1103
|
const date = new Date(intent.createdAt).toLocaleDateString("en-US", {
|
|
1299
1104
|
year: "numeric",
|
|
@@ -1301,7 +1106,7 @@ function intentTable(intents) {
|
|
|
1301
1106
|
day: "numeric"
|
|
1302
1107
|
});
|
|
1303
1108
|
const sColor = intent.status === "ACTIVE" ? GREEN : GRAY;
|
|
1304
|
-
console.log(` ${CYAN}${shortId}${RESET} ${desc.padEnd(descWidth)} ${sColor}${
|
|
1109
|
+
console.log(` ${CYAN}${shortId}${RESET} ${desc.padEnd(descWidth)} ${sColor}${status}${RESET} ${GRAY}${source}${RESET} ${GRAY}${date}${RESET}`);
|
|
1305
1110
|
}
|
|
1306
1111
|
}
|
|
1307
1112
|
function intentCard(intent) {
|
|
@@ -1341,10 +1146,10 @@ function intentCard(intent) {
|
|
|
1341
1146
|
if (intent.archivedAt) {
|
|
1342
1147
|
console.log(` ${BOLD}Archived${RESET} ${GRAY}${new Date(intent.archivedAt).toLocaleString()}${RESET}`);
|
|
1343
1148
|
}
|
|
1344
|
-
if (intent.
|
|
1149
|
+
if (intent.networks && intent.networks.length > 0) {
|
|
1345
1150
|
console.log();
|
|
1346
|
-
console.log(` ${BOLD}
|
|
1347
|
-
for (const idx of intent.
|
|
1151
|
+
console.log(` ${BOLD}Networks${RESET}`);
|
|
1152
|
+
for (const idx of intent.networks) {
|
|
1348
1153
|
const score = idx.relevancyScore !== undefined ? ` (${idx.relevancyScore.toFixed(2)})` : "";
|
|
1349
1154
|
console.log(` ${CYAN}*${RESET} ${idx.title}${GRAY}${score}${RESET}`);
|
|
1350
1155
|
}
|
|
@@ -1370,35 +1175,25 @@ function opportunityTable(opportunities) {
|
|
|
1370
1175
|
}
|
|
1371
1176
|
const idW = 8;
|
|
1372
1177
|
const nameW = 20;
|
|
1373
|
-
const
|
|
1374
|
-
const
|
|
1375
|
-
|
|
1376
|
-
const dateW = 20;
|
|
1377
|
-
process.stdout.write(` ${BOLD}${"ID".padEnd(idW)} ${"Counterparty".padEnd(nameW)} ${"Category".padEnd(catW)} ${"Status".padEnd(statusW)} ${"Conf".padEnd(confW)} ${"Created".padEnd(dateW)}${RESET}
|
|
1178
|
+
const statusW = 12;
|
|
1179
|
+
const headlineW = 48;
|
|
1180
|
+
process.stdout.write(` ${BOLD}${"ID".padEnd(idW)} ${"Counterparty".padEnd(nameW)} ${"Status".padEnd(statusW)} Headline${RESET}
|
|
1378
1181
|
`);
|
|
1379
|
-
process.stdout.write(` ${GRAY}${"-".repeat(idW)} ${"-".repeat(nameW)} ${"-".repeat(
|
|
1182
|
+
process.stdout.write(` ${GRAY}${"-".repeat(idW)} ${"-".repeat(nameW)} ${"-".repeat(statusW)} ${"-".repeat(headlineW)}${RESET}
|
|
1380
1183
|
`);
|
|
1381
1184
|
for (const opp of opportunities) {
|
|
1382
|
-
const shortId = opp.
|
|
1383
|
-
const
|
|
1384
|
-
const name = (opp.counterpartName ?? fallbackName ?? "Unknown").slice(0, nameW);
|
|
1385
|
-
const category = (opp.interpretation?.category ?? "-").slice(0, catW);
|
|
1185
|
+
const shortId = opp.opportunityId.slice(0, idW);
|
|
1186
|
+
const name = opp.peer.name.slice(0, nameW);
|
|
1386
1187
|
const st = opp.status.slice(0, statusW);
|
|
1387
|
-
const
|
|
1388
|
-
|
|
1389
|
-
const date = opp.createdAt ? new Date(opp.createdAt).toLocaleDateString("en-US", {
|
|
1390
|
-
year: "numeric",
|
|
1391
|
-
month: "short",
|
|
1392
|
-
day: "numeric"
|
|
1393
|
-
}) : "-";
|
|
1394
|
-
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}
|
|
1188
|
+
const headline = (opp.headline ?? opp.mainText).slice(0, headlineW);
|
|
1189
|
+
process.stdout.write(` ${CYAN}${shortId}${RESET} ${name.padEnd(nameW)} ${statusColor(st)}${st.padEnd(statusW)}${RESET} ${headline}
|
|
1395
1190
|
`);
|
|
1396
1191
|
}
|
|
1397
1192
|
}
|
|
1398
1193
|
function opportunityCard(opp) {
|
|
1399
1194
|
const width = 58;
|
|
1400
1195
|
const innerWidth = width - 2;
|
|
1401
|
-
const title = opp.
|
|
1196
|
+
const title = opp.headline ?? "Opportunity";
|
|
1402
1197
|
process.stdout.write(`
|
|
1403
1198
|
${BLUE}+${"─".repeat(width)}+${RESET}
|
|
1404
1199
|
`);
|
|
@@ -1409,13 +1204,15 @@ function opportunityCard(opp) {
|
|
|
1409
1204
|
cardLine(`${BOLD}Status:${RESET} ${statusColor(st)}${st}${RESET}`);
|
|
1410
1205
|
if (opp.category)
|
|
1411
1206
|
cardLine(`${BOLD}Category:${RESET} ${opp.category}`);
|
|
1412
|
-
if (opp.
|
|
1413
|
-
cardLine(`${BOLD}Network:${RESET} ${opp.
|
|
1207
|
+
if (opp.network?.title)
|
|
1208
|
+
cardLine(`${BOLD}Network:${RESET} ${opp.network.title}`);
|
|
1414
1209
|
if (opp.confidence != null)
|
|
1415
1210
|
cardLine(`${BOLD}Confidence:${RESET} ${confidenceBar(opp.confidence)}`);
|
|
1416
1211
|
if (opp.myRole)
|
|
1417
1212
|
cardLine(`${BOLD}Your role:${RESET} ${roleLabel(opp.myRole)}`);
|
|
1418
|
-
if (opp.
|
|
1213
|
+
if (opp.peer?.name)
|
|
1214
|
+
cardLine(`${BOLD}With:${RESET} ${opp.peer.name}`);
|
|
1215
|
+
else if (opp.otherParties && opp.otherParties.length > 0) {
|
|
1419
1216
|
process.stdout.write(` ${BLUE}|${RESET}
|
|
1420
1217
|
`);
|
|
1421
1218
|
cardLine(`${BOLD}With:${RESET}`);
|
|
@@ -1423,11 +1220,11 @@ function opportunityCard(opp) {
|
|
|
1423
1220
|
cardLine(` ${p.name ?? p.id} ${roleLabel(p.role)}`);
|
|
1424
1221
|
}
|
|
1425
1222
|
}
|
|
1426
|
-
if (opp.
|
|
1223
|
+
if (opp.mainText) {
|
|
1427
1224
|
process.stdout.write(` ${BLUE}|${RESET}
|
|
1428
1225
|
`);
|
|
1429
1226
|
cardLine(`${BOLD}Details:${RESET}`);
|
|
1430
|
-
for (const line of wordWrap(opp.
|
|
1227
|
+
for (const line of wordWrap(opp.mainText, innerWidth - 4)) {
|
|
1431
1228
|
cardLine(` ${AGENT_TEXT}${line}${RESET}`);
|
|
1432
1229
|
}
|
|
1433
1230
|
}
|
|
@@ -1590,7 +1387,7 @@ function messageList(messages) {
|
|
|
1590
1387
|
month: "short",
|
|
1591
1388
|
day: "numeric"
|
|
1592
1389
|
});
|
|
1593
|
-
const textParts = msg.parts.filter((p) => p.
|
|
1390
|
+
const textParts = msg.parts.filter((p) => p.kind === "text" && p.text).map((p) => p.text).join("");
|
|
1594
1391
|
console.log(` ${CYAN}${sender}${RESET} ${GRAY}${date} ${time}${RESET}`);
|
|
1595
1392
|
console.log(` ${textParts}`);
|
|
1596
1393
|
console.log();
|
|
@@ -1598,17 +1395,20 @@ function messageList(messages) {
|
|
|
1598
1395
|
}
|
|
1599
1396
|
// src/profile.command.ts
|
|
1600
1397
|
async function handleProfile(client, subcommand, positionals, options = {}) {
|
|
1601
|
-
if (subcommand === "create") {
|
|
1602
|
-
await profileCreate(client, options, options?.json);
|
|
1603
|
-
return;
|
|
1604
|
-
}
|
|
1605
1398
|
if (subcommand === "update") {
|
|
1606
|
-
const
|
|
1607
|
-
if (
|
|
1608
|
-
|
|
1609
|
-
return;
|
|
1399
|
+
const { name, intro, location, socials } = options;
|
|
1400
|
+
if (name === undefined && intro === undefined && location === undefined && socials === undefined) {
|
|
1401
|
+
throw new Error("Usage: index profile update [--name <text>] [--intro <text>] [--location <text>] [--social label=value]");
|
|
1610
1402
|
}
|
|
1611
|
-
await
|
|
1403
|
+
const user = await client.updateProfile({ name, intro, location, socials });
|
|
1404
|
+
if (options.json)
|
|
1405
|
+
console.log(JSON.stringify(user));
|
|
1406
|
+
else
|
|
1407
|
+
success("Profile updated.");
|
|
1408
|
+
return;
|
|
1409
|
+
}
|
|
1410
|
+
if (subcommand === "create" || subcommand === "search") {
|
|
1411
|
+
error(`profile ${subcommand} is not available; use "index profile sync" for public research prefill`, 1);
|
|
1612
1412
|
return;
|
|
1613
1413
|
}
|
|
1614
1414
|
if (subcommand === "sync") {
|
|
@@ -1624,35 +1424,6 @@ async function handleProfile(client, subcommand, positionals, options = {}) {
|
|
|
1624
1424
|
await profileShow(client, userId, options?.json);
|
|
1625
1425
|
return;
|
|
1626
1426
|
}
|
|
1627
|
-
if (subcommand === "search") {
|
|
1628
|
-
const query = positionals.join(" ");
|
|
1629
|
-
if (!query) {
|
|
1630
|
-
error("Usage: index profile search <query>", 1);
|
|
1631
|
-
return;
|
|
1632
|
-
}
|
|
1633
|
-
const result = await client.readUserContexts({ query });
|
|
1634
|
-
if (options.json) {
|
|
1635
|
-
console.log(JSON.stringify(result));
|
|
1636
|
-
return;
|
|
1637
|
-
}
|
|
1638
|
-
if (!result.success) {
|
|
1639
|
-
error(result.error ?? "Search failed", 1);
|
|
1640
|
-
return;
|
|
1641
|
-
}
|
|
1642
|
-
const data = result.data;
|
|
1643
|
-
heading("Search Results");
|
|
1644
|
-
if (!data.profiles?.length) {
|
|
1645
|
-
dim(" No profiles found.");
|
|
1646
|
-
} else {
|
|
1647
|
-
for (const p of data.profiles) {
|
|
1648
|
-
console.log(` ${p.name} (${p.userId.slice(0, 8)})`);
|
|
1649
|
-
if (p.bio)
|
|
1650
|
-
dim(` ${p.bio.slice(0, 100)}`);
|
|
1651
|
-
}
|
|
1652
|
-
}
|
|
1653
|
-
console.log();
|
|
1654
|
-
return;
|
|
1655
|
-
}
|
|
1656
1427
|
await profileMe(client, options?.json);
|
|
1657
1428
|
}
|
|
1658
1429
|
async function profileMe(client, json) {
|
|
@@ -1687,61 +1458,26 @@ async function profileSync(client, json) {
|
|
|
1687
1458
|
return;
|
|
1688
1459
|
}
|
|
1689
1460
|
success("Profile enriched.");
|
|
1690
|
-
if (result.profile
|
|
1461
|
+
if (result.profile?.name)
|
|
1691
1462
|
dim(` Name: ${result.profile.name}`);
|
|
1692
|
-
if (result.profile
|
|
1463
|
+
if (result.profile?.location)
|
|
1693
1464
|
dim(` Location: ${result.profile.location}`);
|
|
1694
|
-
dim(` Social links: ${result.profile
|
|
1695
|
-
}
|
|
1696
|
-
async function profileCreate(client, options, json) {
|
|
1697
|
-
if (!json)
|
|
1698
|
-
info("Creating profile...");
|
|
1699
|
-
const query = { confirm: true };
|
|
1700
|
-
if (options.linkedin)
|
|
1701
|
-
query.linkedinUrl = options.linkedin;
|
|
1702
|
-
if (options.github)
|
|
1703
|
-
query.githubUrl = options.github;
|
|
1704
|
-
if (options.twitter)
|
|
1705
|
-
query.twitterUrl = options.twitter;
|
|
1706
|
-
const result = await client.createUserContext(query);
|
|
1707
|
-
if (json) {
|
|
1708
|
-
console.log(JSON.stringify(result));
|
|
1709
|
-
return;
|
|
1710
|
-
}
|
|
1711
|
-
if (!result.success) {
|
|
1712
|
-
error(result.error ?? "Profile creation failed", 1);
|
|
1713
|
-
return;
|
|
1714
|
-
}
|
|
1715
|
-
success("Profile created.");
|
|
1716
|
-
}
|
|
1717
|
-
async function profileUpdate(client, action, details, json) {
|
|
1718
|
-
if (!json)
|
|
1719
|
-
info("Updating profile...");
|
|
1720
|
-
const query = { action };
|
|
1721
|
-
if (details)
|
|
1722
|
-
query.details = details;
|
|
1723
|
-
const result = await client.updateUserContext(query);
|
|
1724
|
-
if (json) {
|
|
1725
|
-
console.log(JSON.stringify(result));
|
|
1726
|
-
return;
|
|
1727
|
-
}
|
|
1728
|
-
if (!result.success) {
|
|
1729
|
-
error(result.error ?? "Profile update failed", 1);
|
|
1730
|
-
return;
|
|
1731
|
-
}
|
|
1732
|
-
success("Profile updated.");
|
|
1465
|
+
dim(` Social links: ${result.profile?.socials?.length ?? 0}`);
|
|
1733
1466
|
}
|
|
1734
1467
|
|
|
1735
1468
|
// src/intent.command.ts
|
|
1736
1469
|
var INTENT_HELP = `
|
|
1737
1470
|
Usage:
|
|
1738
|
-
index intent list [--archived] [--limit <n>] List your signals
|
|
1471
|
+
index intent list [--archived] [--limit <n>] [--query <text>] List your signals
|
|
1739
1472
|
index intent show <id> Show signal details (accepts short ID)
|
|
1740
|
-
index intent
|
|
1473
|
+
index intent prepare <content> [--answer 'prompt=reply'] Review and repair a draft
|
|
1474
|
+
index intent create <content> [--receipt <token>] Create an admitted signal
|
|
1475
|
+
index intent pause <id> | resume <id> Hold or restart its agent
|
|
1741
1476
|
index intent update <id> <content> Update a signal's description
|
|
1742
1477
|
index intent archive <id> Archive a signal (accepts short ID)
|
|
1743
|
-
index intent
|
|
1744
|
-
index intent
|
|
1478
|
+
index intent networks <id> List the networks a signal is shared in
|
|
1479
|
+
index intent add-to-network <id> <network-id> Add a signal to a network
|
|
1480
|
+
index intent remove-from-network <id> <network-id> Remove a signal from a network
|
|
1745
1481
|
`;
|
|
1746
1482
|
async function handleIntent(client, subcommand, options) {
|
|
1747
1483
|
if (!subcommand) {
|
|
@@ -1756,7 +1492,8 @@ async function handleIntent(client, subcommand, options) {
|
|
|
1756
1492
|
case "list": {
|
|
1757
1493
|
const result = await client.listIntents({
|
|
1758
1494
|
archived: options.archived,
|
|
1759
|
-
limit: options.limit
|
|
1495
|
+
limit: options.limit,
|
|
1496
|
+
query: options.query
|
|
1760
1497
|
});
|
|
1761
1498
|
if (options.json) {
|
|
1762
1499
|
console.log(JSON.stringify(result));
|
|
@@ -1784,6 +1521,13 @@ async function handleIntent(client, subcommand, options) {
|
|
|
1784
1521
|
intentCard(intent);
|
|
1785
1522
|
return;
|
|
1786
1523
|
}
|
|
1524
|
+
case "prepare": {
|
|
1525
|
+
if (!options.intentContent)
|
|
1526
|
+
throw new Error("Usage: index intent prepare <content> [--answer 'prompt=reply']");
|
|
1527
|
+
const prepared = await client.prepareIntent(options.intentContent, (options.answers ?? []).map(({ key, value }) => ({ prompt: key, answer: value })));
|
|
1528
|
+
console.log(JSON.stringify(prepared, null, options.json ? undefined : 2));
|
|
1529
|
+
return;
|
|
1530
|
+
}
|
|
1787
1531
|
case "create": {
|
|
1788
1532
|
if (!options.intentContent) {
|
|
1789
1533
|
error("Missing content. Usage: index intent create <content>", 1);
|
|
@@ -1791,27 +1535,13 @@ async function handleIntent(client, subcommand, options) {
|
|
|
1791
1535
|
}
|
|
1792
1536
|
if (!options.json)
|
|
1793
1537
|
info("Processing signal...");
|
|
1794
|
-
const result = await client.
|
|
1795
|
-
description: options.intentContent
|
|
1796
|
-
});
|
|
1538
|
+
const result = await client.createIntent(options.intentContent, options.targetId ? [options.targetId] : undefined, options.receipt);
|
|
1797
1539
|
if (options.json) {
|
|
1798
1540
|
console.log(JSON.stringify(result));
|
|
1799
1541
|
return;
|
|
1800
1542
|
}
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
return;
|
|
1804
|
-
}
|
|
1805
|
-
const proposals = parseIntentProposals(result.data?.message);
|
|
1806
|
-
if (proposals.length === 0) {
|
|
1807
|
-
error("Signal proposal could not be parsed from the response.", 1);
|
|
1808
|
-
return;
|
|
1809
|
-
}
|
|
1810
|
-
for (const proposal of proposals) {
|
|
1811
|
-
await client.confirmIntent(proposal.proposalId, proposal.description);
|
|
1812
|
-
success("Signal created.");
|
|
1813
|
-
dim(` ${proposal.description}`);
|
|
1814
|
-
}
|
|
1543
|
+
success("Signal created.");
|
|
1544
|
+
dim(` shared in ${result.networkIds.length} network${result.networkIds.length === 1 ? "" : "s"}`);
|
|
1815
1545
|
return;
|
|
1816
1546
|
}
|
|
1817
1547
|
case "update": {
|
|
@@ -1830,102 +1560,90 @@ async function handleIntent(client, subcommand, options) {
|
|
|
1830
1560
|
console.log(JSON.stringify(result));
|
|
1831
1561
|
return;
|
|
1832
1562
|
}
|
|
1833
|
-
if (!result.success) {
|
|
1834
|
-
error(result.error ?? "Failed to update signal", 1);
|
|
1835
|
-
return;
|
|
1836
|
-
}
|
|
1837
1563
|
success("Signal updated.");
|
|
1838
1564
|
return;
|
|
1839
1565
|
}
|
|
1566
|
+
case "pause":
|
|
1567
|
+
case "resume": {
|
|
1568
|
+
if (!options.intentId)
|
|
1569
|
+
throw new Error(`Usage: index intent ${subcommand} <id>`);
|
|
1570
|
+
const status = subcommand === "pause" ? "PAUSED" : "ACTIVE";
|
|
1571
|
+
await client.updateIntentStatus(options.intentId, status);
|
|
1572
|
+
if (options.json)
|
|
1573
|
+
console.log(JSON.stringify({ intentId: options.intentId, status }));
|
|
1574
|
+
else
|
|
1575
|
+
success(`Signal ${status.toLowerCase()}.`);
|
|
1576
|
+
return;
|
|
1577
|
+
}
|
|
1840
1578
|
case "archive": {
|
|
1841
1579
|
if (!options.intentId) {
|
|
1842
1580
|
error("Missing signal ID. Usage: index intent archive <id>", 1);
|
|
1843
1581
|
return;
|
|
1844
1582
|
}
|
|
1845
|
-
|
|
1846
|
-
const result = await client.callTool("delete_intent", { intentId: intent.id });
|
|
1583
|
+
await client.archiveIntent(options.intentId);
|
|
1847
1584
|
if (options.json) {
|
|
1848
|
-
console.log(JSON.stringify(
|
|
1849
|
-
return;
|
|
1850
|
-
}
|
|
1851
|
-
if (!result.success) {
|
|
1852
|
-
error(result.error ?? "Failed to archive signal", 1);
|
|
1585
|
+
console.log(JSON.stringify({ success: true }));
|
|
1853
1586
|
return;
|
|
1854
1587
|
}
|
|
1855
1588
|
success(`Signal ${options.intentId} archived.`);
|
|
1856
1589
|
return;
|
|
1857
1590
|
}
|
|
1858
|
-
case "
|
|
1859
|
-
if (!options.intentId
|
|
1860
|
-
error("Usage: index intent
|
|
1591
|
+
case "networks": {
|
|
1592
|
+
if (!options.intentId) {
|
|
1593
|
+
error("Usage: index intent networks <intent-id>", 1);
|
|
1861
1594
|
return;
|
|
1862
1595
|
}
|
|
1863
|
-
const
|
|
1864
|
-
const result = await client.callTool("create_intent_index", {
|
|
1865
|
-
intentId: intent.id,
|
|
1866
|
-
networkId: options.targetId
|
|
1867
|
-
});
|
|
1596
|
+
const networkIds = await client.listIntentNetworks(options.intentId);
|
|
1868
1597
|
if (options.json) {
|
|
1869
|
-
console.log(JSON.stringify(
|
|
1870
|
-
return;
|
|
1871
|
-
}
|
|
1872
|
-
if (!result.success) {
|
|
1873
|
-
error(result.error ?? "Failed to link signal", 1);
|
|
1598
|
+
console.log(JSON.stringify({ networkIds }));
|
|
1874
1599
|
return;
|
|
1875
1600
|
}
|
|
1876
|
-
|
|
1601
|
+
heading("Networks");
|
|
1602
|
+
for (const networkId of networkIds)
|
|
1603
|
+
dim(` ${networkId}`);
|
|
1604
|
+
console.log();
|
|
1877
1605
|
return;
|
|
1878
1606
|
}
|
|
1879
|
-
case "
|
|
1607
|
+
case "add-to-network": {
|
|
1880
1608
|
if (!options.intentId || !options.targetId) {
|
|
1881
|
-
error("Usage: index intent
|
|
1609
|
+
error("Usage: index intent add-to-network <intent-id> <network-id>", 1);
|
|
1882
1610
|
return;
|
|
1883
1611
|
}
|
|
1884
|
-
|
|
1885
|
-
const result = await client.callTool("delete_intent_index", {
|
|
1886
|
-
intentId: intent.id,
|
|
1887
|
-
networkId: options.targetId
|
|
1888
|
-
});
|
|
1612
|
+
await client.addIntentToNetwork(options.intentId, options.targetId);
|
|
1889
1613
|
if (options.json) {
|
|
1890
|
-
console.log(JSON.stringify(
|
|
1614
|
+
console.log(JSON.stringify({ success: true }));
|
|
1615
|
+
return;
|
|
1616
|
+
}
|
|
1617
|
+
success("Signal added to network.");
|
|
1618
|
+
return;
|
|
1619
|
+
}
|
|
1620
|
+
case "remove-from-network": {
|
|
1621
|
+
if (!options.intentId || !options.targetId) {
|
|
1622
|
+
error("Usage: index intent remove-from-network <intent-id> <network-id>", 1);
|
|
1891
1623
|
return;
|
|
1892
1624
|
}
|
|
1893
|
-
|
|
1894
|
-
|
|
1625
|
+
await client.removeIntentFromNetwork(options.intentId, options.targetId);
|
|
1626
|
+
if (options.json) {
|
|
1627
|
+
console.log(JSON.stringify({ success: true }));
|
|
1895
1628
|
return;
|
|
1896
1629
|
}
|
|
1897
|
-
success("Signal
|
|
1630
|
+
success("Signal removed from network.");
|
|
1898
1631
|
return;
|
|
1899
1632
|
}
|
|
1900
1633
|
}
|
|
1901
1634
|
}
|
|
1902
|
-
function parseIntentProposals(message) {
|
|
1903
|
-
if (!message)
|
|
1904
|
-
return [];
|
|
1905
|
-
const proposals = [];
|
|
1906
|
-
const blockRegex = /```intent_proposal\s*\n([\s\S]*?)\n```/g;
|
|
1907
|
-
let match;
|
|
1908
|
-
while ((match = blockRegex.exec(message)) !== null) {
|
|
1909
|
-
try {
|
|
1910
|
-
const parsed = JSON.parse(match[1]);
|
|
1911
|
-
if (parsed.proposalId && parsed.description) {
|
|
1912
|
-
proposals.push({ proposalId: parsed.proposalId, description: parsed.description });
|
|
1913
|
-
}
|
|
1914
|
-
} catch {}
|
|
1915
|
-
}
|
|
1916
|
-
return proposals;
|
|
1917
|
-
}
|
|
1918
1635
|
|
|
1919
1636
|
// src/opportunity.command.ts
|
|
1920
1637
|
var OPPORTUNITY_HELP = `
|
|
1921
1638
|
Usage:
|
|
1922
1639
|
index opportunity list List your opportunities
|
|
1923
|
-
index opportunity list --
|
|
1640
|
+
index opportunity list --intent-id <id> --statuses negotiating,pending,accepted,expired
|
|
1641
|
+
index opportunity list --status <s> Filter by one settled or actionable status
|
|
1924
1642
|
index opportunity list --limit <n> Limit results
|
|
1925
1643
|
index opportunity show <id> Show full opportunity details (accepts short ID)
|
|
1926
1644
|
index opportunity accept <id> Accept an opportunity (accepts short ID)
|
|
1927
|
-
index opportunity accept <id> --acknowledge-uptake <id,id> Continue after an uptake advisory
|
|
1928
1645
|
index opportunity reject <id> Reject an opportunity (accepts short ID)
|
|
1646
|
+
index opportunity start-chat <id> Open the chat through this opportunity
|
|
1929
1647
|
`;
|
|
1930
1648
|
async function handleOpportunity(client, subcommand, options) {
|
|
1931
1649
|
if (!subcommand) {
|
|
@@ -1938,7 +1656,7 @@ async function handleOpportunity(client, subcommand, options) {
|
|
|
1938
1656
|
}
|
|
1939
1657
|
switch (subcommand) {
|
|
1940
1658
|
case "list":
|
|
1941
|
-
await opportunityList(client, options.status, options.limit, options.json);
|
|
1659
|
+
await opportunityList(client, options.status, options.statuses, options.intentId, options.limit, options.json);
|
|
1942
1660
|
return;
|
|
1943
1661
|
case "show":
|
|
1944
1662
|
if (!options.targetId) {
|
|
@@ -1952,7 +1670,7 @@ async function handleOpportunity(client, subcommand, options) {
|
|
|
1952
1670
|
error("Missing opportunity ID. Usage: index opportunity accept <id>", 1);
|
|
1953
1671
|
return;
|
|
1954
1672
|
}
|
|
1955
|
-
await opportunityStatusUpdate(client, options.targetId, "accepted", options.json
|
|
1673
|
+
await opportunityStatusUpdate(client, options.targetId, "accepted", options.json);
|
|
1956
1674
|
return;
|
|
1957
1675
|
case "reject":
|
|
1958
1676
|
if (!options.targetId) {
|
|
@@ -1961,13 +1679,23 @@ async function handleOpportunity(client, subcommand, options) {
|
|
|
1961
1679
|
}
|
|
1962
1680
|
await opportunityStatusUpdate(client, options.targetId, "rejected", options.json);
|
|
1963
1681
|
return;
|
|
1682
|
+
case "start-chat": {
|
|
1683
|
+
if (!options.targetId)
|
|
1684
|
+
throw new Error("Usage: index opportunity start-chat <id>");
|
|
1685
|
+
const result = await client.startOpportunityChat(options.targetId);
|
|
1686
|
+
if (options.json)
|
|
1687
|
+
console.log(JSON.stringify(result));
|
|
1688
|
+
else
|
|
1689
|
+
success(`Chat opened: ${result.conversationId}`);
|
|
1690
|
+
return;
|
|
1691
|
+
}
|
|
1964
1692
|
default:
|
|
1965
1693
|
error(`Unknown subcommand: ${subcommand}`, 1);
|
|
1966
1694
|
return;
|
|
1967
1695
|
}
|
|
1968
1696
|
}
|
|
1969
|
-
async function opportunityList(client,
|
|
1970
|
-
const opportunities = await client.listOpportunities({ status
|
|
1697
|
+
async function opportunityList(client, status, statuses, intentId, limit, json) {
|
|
1698
|
+
const opportunities = await client.listOpportunities({ status, statuses, intentId, limit });
|
|
1971
1699
|
if (json) {
|
|
1972
1700
|
console.log(JSON.stringify(opportunities));
|
|
1973
1701
|
return;
|
|
@@ -1984,225 +1712,55 @@ async function opportunityShow(client, id, json) {
|
|
|
1984
1712
|
}
|
|
1985
1713
|
opportunityCard(opportunity);
|
|
1986
1714
|
}
|
|
1987
|
-
async function opportunityStatusUpdate(client, id,
|
|
1715
|
+
async function opportunityStatusUpdate(client, id, status, json) {
|
|
1988
1716
|
const opportunity = await client.getOpportunity(id);
|
|
1989
|
-
|
|
1990
|
-
try {
|
|
1991
|
-
const result2 = await client.updateOpportunityStatus(opportunity.id, "accepted", acknowledgedUptakeQuestionIds);
|
|
1992
|
-
if (json) {
|
|
1993
|
-
console.log(JSON.stringify(result2));
|
|
1994
|
-
return;
|
|
1995
|
-
}
|
|
1996
|
-
success("Opportunity accepted.");
|
|
1997
|
-
} catch (error2) {
|
|
1998
|
-
const advisory = uptakeAdvisoryFromError(error2);
|
|
1999
|
-
if (json && error2 instanceof ApiError) {
|
|
2000
|
-
console.log(JSON.stringify(error2.response ?? { error: error2.message }));
|
|
2001
|
-
return;
|
|
2002
|
-
}
|
|
2003
|
-
if (!advisory)
|
|
2004
|
-
throw error2;
|
|
2005
|
-
heading("Questions before accepting");
|
|
2006
|
-
for (const question of advisory.advisory.questions) {
|
|
2007
|
-
console.log(`
|
|
2008
|
-
${question.title}`);
|
|
2009
|
-
console.log(question.prompt);
|
|
2010
|
-
for (const option of question.options) {
|
|
2011
|
-
console.log(` - ${option.label}${option.description ? ` — ${option.description}` : ""}`);
|
|
2012
|
-
}
|
|
2013
|
-
dim(` Question ID: ${question.id}`);
|
|
2014
|
-
}
|
|
2015
|
-
const ids = advisory.advisory.questions.map((question) => question.id).join(",");
|
|
2016
|
-
info(`Answer or dismiss these questions, then retry. To continue anyway, run:
|
|
2017
|
-
index opportunity accept ${opportunity.id} --acknowledge-uptake ${ids}`);
|
|
2018
|
-
}
|
|
2019
|
-
return;
|
|
2020
|
-
}
|
|
2021
|
-
const result = await client.updateOpportunityStatus(opportunity.id, "rejected");
|
|
1717
|
+
const result = await client.updateOpportunityStatus(opportunity.id, status);
|
|
2022
1718
|
if (json) {
|
|
2023
1719
|
console.log(JSON.stringify(result));
|
|
2024
1720
|
return;
|
|
2025
1721
|
}
|
|
2026
|
-
success(
|
|
2027
|
-
}
|
|
2028
|
-
function uptakeAdvisoryFromError(error2) {
|
|
2029
|
-
if (!(error2 instanceof ApiError) || error2.status !== 409)
|
|
2030
|
-
return null;
|
|
2031
|
-
const body = error2.response;
|
|
2032
|
-
return body?.advisory?.code === "unresolved_uptake_questions" ? body : null;
|
|
1722
|
+
success(`Opportunity ${status}.`);
|
|
2033
1723
|
}
|
|
2034
1724
|
|
|
2035
1725
|
// src/negotiation.command.ts
|
|
2036
|
-
var NEGOTIATION_HELP = `
|
|
2037
|
-
Usage:
|
|
2038
|
-
index negotiation list List your agent's negotiations
|
|
2039
|
-
index negotiation list --limit <n> Limit results
|
|
2040
|
-
index negotiation list --since <date|duration> Filter by time (ISO date or duration like 1h, 2d, 1w)
|
|
2041
|
-
index negotiation show <id> Show negotiation turn-by-turn details
|
|
2042
|
-
`;
|
|
2043
1726
|
async function handleNegotiation(client, subcommand, options) {
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
1727
|
+
let result;
|
|
1728
|
+
if (subcommand === "list") {
|
|
1729
|
+
if (options.state !== undefined && options.state !== "open" && options.state !== "settled")
|
|
1730
|
+
throw new Error("--state must be open or settled");
|
|
1731
|
+
result = await client.listNegotiations({ intentId: options.intentId, state: options.state });
|
|
1732
|
+
} else if (subcommand === "show" || subcommand === "turn") {
|
|
1733
|
+
if (!options.targetId)
|
|
1734
|
+
throw new Error("An opportunity ID is required");
|
|
1735
|
+
if (subcommand === "show") {
|
|
1736
|
+
result = await client.getNegotiation(options.targetId);
|
|
2047
1737
|
} else {
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
await
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
error("Missing negotiation ID. Usage: index negotiation show <id>", 1);
|
|
2059
|
-
return;
|
|
2060
|
-
}
|
|
2061
|
-
await negotiationShow(client, options.targetId, options.json);
|
|
2062
|
-
return;
|
|
2063
|
-
default:
|
|
2064
|
-
error(`Unknown subcommand: ${subcommand}`, 1);
|
|
2065
|
-
return;
|
|
2066
|
-
}
|
|
2067
|
-
}
|
|
2068
|
-
function resolveSince(input) {
|
|
2069
|
-
const match = input.match(/^(\d+)([smhdw])$/);
|
|
2070
|
-
if (match) {
|
|
2071
|
-
const n = parseInt(match[1], 10);
|
|
2072
|
-
const unit = match[2];
|
|
2073
|
-
const ms = { s: 1000, m: 60000, h: 3600000, d: 86400000, w: 604800000 }[unit];
|
|
2074
|
-
return new Date(Date.now() - n * ms).toISOString();
|
|
2075
|
-
}
|
|
2076
|
-
const d = new Date(input);
|
|
2077
|
-
if (isNaN(d.getTime()))
|
|
2078
|
-
throw new Error(`Invalid --since value: "${input}". Use ISO date or duration like 1h, 2d, 1w.`);
|
|
2079
|
-
return d.toISOString();
|
|
2080
|
-
}
|
|
2081
|
-
async function negotiationList(client, limit, since, json) {
|
|
2082
|
-
const sinceIso = since ? resolveSince(since) : undefined;
|
|
2083
|
-
const negotiations = await client.listNegotiations({ limit, since: sinceIso });
|
|
2084
|
-
if (json) {
|
|
2085
|
-
console.log(JSON.stringify(negotiations));
|
|
2086
|
-
return;
|
|
2087
|
-
}
|
|
2088
|
-
heading("Negotiations");
|
|
2089
|
-
negotiationTable(negotiations);
|
|
2090
|
-
console.log();
|
|
2091
|
-
}
|
|
2092
|
-
async function negotiationShow(client, id, json) {
|
|
2093
|
-
const negotiations = await client.listNegotiations({ limit: 50 });
|
|
2094
|
-
const match = negotiations.find((n) => n.id === id || n.id.startsWith(id));
|
|
2095
|
-
if (!match) {
|
|
2096
|
-
error(`Negotiation not found: ${id}`, 1);
|
|
2097
|
-
return;
|
|
2098
|
-
}
|
|
2099
|
-
if (json) {
|
|
2100
|
-
console.log(JSON.stringify(match));
|
|
2101
|
-
return;
|
|
2102
|
-
}
|
|
2103
|
-
negotiationCard(match);
|
|
2104
|
-
}
|
|
2105
|
-
var { BOLD: BOLD2, RESET: RESET2, CYAN: CYAN2, GRAY: GRAY2, GREEN: GREEN2, YELLOW: YELLOW2, BLUE: BLUE2, DIM: DIM2 } = exports_output;
|
|
2106
|
-
function outcomeLabel(outcome) {
|
|
2107
|
-
if (!outcome)
|
|
2108
|
-
return `${GRAY2}unknown${RESET2}`;
|
|
2109
|
-
return outcome.hasOpportunity ? `${GREEN2}opportunity${RESET2}` : `${GRAY2}no match${RESET2}`;
|
|
2110
|
-
}
|
|
2111
|
-
function roleLabel2(role) {
|
|
2112
|
-
switch (role) {
|
|
2113
|
-
case "agent":
|
|
2114
|
-
return `${GREEN2}helper${RESET2}`;
|
|
2115
|
-
case "patient":
|
|
2116
|
-
return `${YELLOW2}seeker${RESET2}`;
|
|
2117
|
-
case "peer":
|
|
2118
|
-
return `${CYAN2}peer${RESET2}`;
|
|
2119
|
-
default:
|
|
2120
|
-
return `${GRAY2}-${RESET2}`;
|
|
2121
|
-
}
|
|
2122
|
-
}
|
|
2123
|
-
function actionColorFor(action) {
|
|
2124
|
-
switch (action) {
|
|
2125
|
-
case "accept":
|
|
2126
|
-
return GREEN2;
|
|
2127
|
-
case "reject":
|
|
2128
|
-
return RED;
|
|
2129
|
-
default:
|
|
2130
|
-
return BLUE2;
|
|
2131
|
-
}
|
|
2132
|
-
}
|
|
2133
|
-
function negotiationTable(negotiations) {
|
|
2134
|
-
if (negotiations.length === 0) {
|
|
2135
|
-
dim(" No negotiations found.");
|
|
2136
|
-
return;
|
|
2137
|
-
}
|
|
2138
|
-
const idW = 8;
|
|
2139
|
-
const nameW = 22;
|
|
2140
|
-
const outcomeW = 14;
|
|
2141
|
-
const roleW = 8;
|
|
2142
|
-
const turnsW = 6;
|
|
2143
|
-
const dateW = 20;
|
|
2144
|
-
process.stdout.write(` ${BOLD2}${"ID".padEnd(idW)} ${"Counterparty".padEnd(nameW)} ${"Outcome".padEnd(outcomeW)} ${"Role".padEnd(roleW)} ${"Turns".padEnd(turnsW)} ${"Created".padEnd(dateW)}${RESET2}
|
|
2145
|
-
`);
|
|
2146
|
-
process.stdout.write(` ${GRAY2}${"-".repeat(idW)} ${"-".repeat(nameW)} ${"-".repeat(outcomeW)} ${"-".repeat(roleW)} ${"-".repeat(turnsW)} ${"-".repeat(dateW)}${RESET2}
|
|
2147
|
-
`);
|
|
2148
|
-
for (const n of negotiations) {
|
|
2149
|
-
const shortId = n.id.slice(0, 8);
|
|
2150
|
-
const name = (n.counterparty?.name ?? "Unknown").slice(0, nameW);
|
|
2151
|
-
const turns = String(n.outcome?.turnCount ?? n.turns?.length ?? "-");
|
|
2152
|
-
const date = n.createdAt ? new Date(n.createdAt).toLocaleDateString("en-US", {
|
|
2153
|
-
year: "numeric",
|
|
2154
|
-
month: "short",
|
|
2155
|
-
day: "numeric"
|
|
2156
|
-
}) : "-";
|
|
2157
|
-
const outcomeStr = outcomeLabel(n.outcome);
|
|
2158
|
-
const roleStr = roleLabel2(n.outcome?.role);
|
|
2159
|
-
process.stdout.write(` ${CYAN2}${shortId}${RESET2} ${name.padEnd(nameW)} ${outcomeStr}${padTo(outcomeW, stripAnsi(outcomeStr))} ${roleStr}${padTo(roleW, stripAnsi(roleStr))} ${turns.padEnd(turnsW)} ${GRAY2}${date}${RESET2}
|
|
2160
|
-
`);
|
|
2161
|
-
}
|
|
2162
|
-
}
|
|
2163
|
-
function negotiationCard(n) {
|
|
2164
|
-
console.log();
|
|
2165
|
-
console.log(` ${BOLD2}${CYAN2}Negotiation Details${RESET2}`);
|
|
2166
|
-
console.log(` ${GRAY2}${"─".repeat(60)}${RESET2}`);
|
|
2167
|
-
console.log(` ${BOLD2}ID${RESET2} ${GRAY2}${n.id}${RESET2}`);
|
|
2168
|
-
console.log(` ${BOLD2}Counterparty${RESET2} ${n.counterparty?.name ?? "Unknown"}`);
|
|
2169
|
-
console.log(` ${BOLD2}Outcome${RESET2} ${outcomeLabel(n.outcome)}`);
|
|
2170
|
-
console.log(` ${BOLD2}Your Role${RESET2} ${roleLabel2(n.outcome?.role)}`);
|
|
2171
|
-
console.log(` ${BOLD2}Turns${RESET2} ${n.outcome?.turnCount ?? n.turns?.length ?? "-"}`);
|
|
2172
|
-
console.log(` ${BOLD2}Created${RESET2} ${GRAY2}${new Date(n.createdAt).toLocaleString()}${RESET2}`);
|
|
2173
|
-
if (n.turns && n.turns.length > 0) {
|
|
2174
|
-
console.log();
|
|
2175
|
-
console.log(` ${BOLD2}Turn-by-Turn${RESET2}`);
|
|
2176
|
-
console.log(` ${GRAY2}${"─".repeat(60)}${RESET2}`);
|
|
2177
|
-
for (let i = 0;i < n.turns.length; i++) {
|
|
2178
|
-
const t = n.turns[i];
|
|
2179
|
-
const time = new Date(t.createdAt).toLocaleTimeString("en-US", {
|
|
2180
|
-
hour: "2-digit",
|
|
2181
|
-
minute: "2-digit",
|
|
2182
|
-
second: "2-digit"
|
|
1738
|
+
if (!options.action || !["propose", "counter", "accept", "decline"].includes(options.action))
|
|
1739
|
+
throw new Error("--action must be propose, counter, accept, or decline");
|
|
1740
|
+
if (!options.message?.trim())
|
|
1741
|
+
throw new Error("--message is required");
|
|
1742
|
+
if (options.expectedTurnCount === undefined || !Number.isSafeInteger(options.expectedTurnCount) || options.expectedTurnCount < 0)
|
|
1743
|
+
throw new Error("--expected-turn-count must be the observed nonnegative integer turn count");
|
|
1744
|
+
result = await client.submitNegotiationTurn(options.targetId, {
|
|
1745
|
+
action: options.action,
|
|
1746
|
+
message: options.message,
|
|
1747
|
+
expectedTurnCount: options.expectedTurnCount
|
|
2183
1748
|
});
|
|
2184
|
-
const actionColor = actionColorFor(t.action);
|
|
2185
|
-
console.log(` ${DIM2}Turn ${i + 1}${RESET2} ${CYAN2}${t.speaker?.name ?? "?"}${RESET2} ${actionColor}${t.action}${RESET2} ${GRAY2}${time}${RESET2}`);
|
|
2186
|
-
if (t.suggestedRoles) {
|
|
2187
|
-
console.log(` ${DIM2} roles: own=${t.suggestedRoles.ownUser ?? "?"} other=${t.suggestedRoles.otherUser ?? "?"}${RESET2}`);
|
|
2188
|
-
}
|
|
2189
|
-
if (t.reasoning) {
|
|
2190
|
-
const lines = wordWrap(t.reasoning, 72);
|
|
2191
|
-
for (const line of lines) {
|
|
2192
|
-
console.log(` ${DIM2} ${line}${RESET2}`);
|
|
2193
|
-
}
|
|
2194
|
-
}
|
|
2195
|
-
console.log();
|
|
2196
1749
|
}
|
|
1750
|
+
} else {
|
|
1751
|
+
throw new Error("Usage: index negotiation list [--intent-id <id>] [--state open|settled], show <opportunity-id>, or turn <opportunity-id> --action <action> --message <text> --expected-turn-count <n>");
|
|
2197
1752
|
}
|
|
2198
|
-
console.log(
|
|
2199
|
-
console.log();
|
|
1753
|
+
console.log(JSON.stringify(result, null, options.json ? undefined : 2));
|
|
2200
1754
|
}
|
|
2201
1755
|
|
|
2202
1756
|
// src/network.command.ts
|
|
2203
1757
|
var NETWORK_HELP = `
|
|
2204
1758
|
Network Commands:
|
|
2205
1759
|
index network list List your networks
|
|
1760
|
+
index network discover Find public networks to join
|
|
1761
|
+
index network requests See your network creation requests
|
|
1762
|
+
index network request-update <id> --title <name> [--prompt <purpose>]
|
|
1763
|
+
index network request-dismiss <id> Dismiss your request
|
|
2206
1764
|
index network create <name> Create directly or submit an early-access request
|
|
2207
1765
|
index network create <name> --prompt Create directly or request early access with a description
|
|
2208
1766
|
index network show <id|key> Show network details and members
|
|
@@ -2222,6 +1780,47 @@ async function handleNetwork(client, subcommand, positionals, options) {
|
|
|
2222
1780
|
case "list":
|
|
2223
1781
|
await networkList(client, options.json);
|
|
2224
1782
|
return;
|
|
1783
|
+
case "discover": {
|
|
1784
|
+
const result = await client.discoverNetworks();
|
|
1785
|
+
if (options.json)
|
|
1786
|
+
console.log(JSON.stringify(result));
|
|
1787
|
+
else {
|
|
1788
|
+
heading("Public networks");
|
|
1789
|
+
networkTable(result.networks);
|
|
1790
|
+
}
|
|
1791
|
+
return;
|
|
1792
|
+
}
|
|
1793
|
+
case "requests": {
|
|
1794
|
+
const result = await client.listNetworkRequests();
|
|
1795
|
+
if (options.json)
|
|
1796
|
+
console.log(JSON.stringify(result));
|
|
1797
|
+
else {
|
|
1798
|
+
heading("Your network requests");
|
|
1799
|
+
for (const request of result.requests)
|
|
1800
|
+
dim(` ${request.id} · ${request.title} · ${request.status}`);
|
|
1801
|
+
}
|
|
1802
|
+
return;
|
|
1803
|
+
}
|
|
1804
|
+
case "request-update": {
|
|
1805
|
+
if (!positionals[0] || !options.title)
|
|
1806
|
+
throw new Error("Usage: index network request-update <id> --title <name> [--prompt <purpose>]");
|
|
1807
|
+
const result = await client.updateNetworkRequest(positionals[0], options.title, options.prompt);
|
|
1808
|
+
if (options.json)
|
|
1809
|
+
console.log(JSON.stringify(result));
|
|
1810
|
+
else
|
|
1811
|
+
success("Network request resubmitted.");
|
|
1812
|
+
return;
|
|
1813
|
+
}
|
|
1814
|
+
case "request-dismiss": {
|
|
1815
|
+
if (!positionals[0])
|
|
1816
|
+
throw new Error("Usage: index network request-dismiss <id>");
|
|
1817
|
+
await client.dismissNetworkRequest(positionals[0]);
|
|
1818
|
+
if (options.json)
|
|
1819
|
+
console.log(JSON.stringify({ success: true }));
|
|
1820
|
+
else
|
|
1821
|
+
success("Network request dismissed.");
|
|
1822
|
+
return;
|
|
1823
|
+
}
|
|
2225
1824
|
case "create":
|
|
2226
1825
|
await networkCreate(client, positionals[0], options.prompt, options.json);
|
|
2227
1826
|
return;
|
|
@@ -2249,13 +1848,12 @@ async function handleNetwork(client, subcommand, positionals, options) {
|
|
|
2249
1848
|
}
|
|
2250
1849
|
async function networkList(client, json) {
|
|
2251
1850
|
const networks = await client.listNetworks();
|
|
2252
|
-
const filtered = networks.filter((n) => !n.isPersonal);
|
|
2253
1851
|
if (json) {
|
|
2254
|
-
console.log(JSON.stringify(
|
|
1852
|
+
console.log(JSON.stringify(networks));
|
|
2255
1853
|
return;
|
|
2256
1854
|
}
|
|
2257
1855
|
heading("Networks");
|
|
2258
|
-
networkTable(
|
|
1856
|
+
networkTable(networks);
|
|
2259
1857
|
console.log();
|
|
2260
1858
|
}
|
|
2261
1859
|
async function networkCreate(client, name, prompt, json) {
|
|
@@ -2336,13 +1934,9 @@ async function networkUpdate(client, id, options, json) {
|
|
|
2336
1934
|
error("Provide at least --title or --prompt. Usage: index network update <id> [--title <t>] [--prompt <p>]", 1);
|
|
2337
1935
|
return;
|
|
2338
1936
|
}
|
|
2339
|
-
const
|
|
1937
|
+
const network = await client.updateNetwork(id, settings);
|
|
2340
1938
|
if (json) {
|
|
2341
|
-
console.log(JSON.stringify(
|
|
2342
|
-
return;
|
|
2343
|
-
}
|
|
2344
|
-
if (!result.success) {
|
|
2345
|
-
error(result.error ?? "Network update failed", 1);
|
|
1939
|
+
console.log(JSON.stringify({ network }));
|
|
2346
1940
|
return;
|
|
2347
1941
|
}
|
|
2348
1942
|
success("Network updated.");
|
|
@@ -2352,13 +1946,9 @@ async function networkDelete(client, id, json) {
|
|
|
2352
1946
|
error("Usage: index network delete <id>", 1);
|
|
2353
1947
|
return;
|
|
2354
1948
|
}
|
|
2355
|
-
|
|
1949
|
+
await client.deleteNetwork(id);
|
|
2356
1950
|
if (json) {
|
|
2357
|
-
console.log(JSON.stringify(
|
|
2358
|
-
return;
|
|
2359
|
-
}
|
|
2360
|
-
if (!result.success) {
|
|
2361
|
-
error(result.error ?? "Network deletion failed", 1);
|
|
1951
|
+
console.log(JSON.stringify({ success: true }));
|
|
2362
1952
|
return;
|
|
2363
1953
|
}
|
|
2364
1954
|
success("Network deleted.");
|
|
@@ -2382,6 +1972,47 @@ async function networkInvite(client, id, email, json) {
|
|
|
2382
1972
|
dim(" Created a pending account for this invitee.");
|
|
2383
1973
|
}
|
|
2384
1974
|
|
|
1975
|
+
// src/sse.parser.ts
|
|
1976
|
+
function parseSSEEvents(chunk) {
|
|
1977
|
+
if (!chunk)
|
|
1978
|
+
return [];
|
|
1979
|
+
const events = [];
|
|
1980
|
+
const rawEvents = chunk.split(`
|
|
1981
|
+
|
|
1982
|
+
`);
|
|
1983
|
+
for (let i = 0;i < rawEvents.length; i++) {
|
|
1984
|
+
const raw = rawEvents[i].trim();
|
|
1985
|
+
if (!raw)
|
|
1986
|
+
continue;
|
|
1987
|
+
if (i === rawEvents.length - 1 && !chunk.endsWith(`
|
|
1988
|
+
|
|
1989
|
+
`)) {
|
|
1990
|
+
continue;
|
|
1991
|
+
}
|
|
1992
|
+
let eventType;
|
|
1993
|
+
const dataLines = [];
|
|
1994
|
+
for (const line of raw.split(`
|
|
1995
|
+
`)) {
|
|
1996
|
+
if (line.startsWith(":")) {
|
|
1997
|
+
continue;
|
|
1998
|
+
}
|
|
1999
|
+
if (line.startsWith("event:")) {
|
|
2000
|
+
eventType = line.slice("event:".length).trim();
|
|
2001
|
+
} else if (line.startsWith("data:")) {
|
|
2002
|
+
dataLines.push(line.slice("data:".length).trim());
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
if (dataLines.length > 0) {
|
|
2006
|
+
events.push({
|
|
2007
|
+
event: eventType,
|
|
2008
|
+
data: dataLines.join(`
|
|
2009
|
+
`)
|
|
2010
|
+
});
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
return events;
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2385
2016
|
// src/conversation.command.ts
|
|
2386
2017
|
var CONVERSATION_HELP = `
|
|
2387
2018
|
Conversation Commands:
|
|
@@ -2390,13 +2021,37 @@ Conversation Commands:
|
|
|
2390
2021
|
index conversation show <id> Show messages (accepts short ID)
|
|
2391
2022
|
index conversation show <id> --limit <n> Limit number of messages
|
|
2392
2023
|
index conversation send <id> <message> Send a message (accepts short ID)
|
|
2024
|
+
index conversation show agent --intent-id <id> Read scoped agent state
|
|
2025
|
+
index conversation send agent <text> --intent-id <id> [--question-id <id>]
|
|
2026
|
+
index conversation answer agent --intent-id <id> --answer 'question-id=text' [--answer ...]
|
|
2393
2027
|
index conversation stream Listen for real-time events (SSE)
|
|
2394
2028
|
`;
|
|
2395
2029
|
async function handleConversation(client, subcommand, positionals, options) {
|
|
2396
|
-
if (
|
|
2397
|
-
|
|
2030
|
+
if (positionals[0] === "agent" && (subcommand === "show" || subcommand === "send")) {
|
|
2031
|
+
if (!options?.intentId)
|
|
2032
|
+
throw new Error("Personal-agent conversations require --intent-id <id>");
|
|
2033
|
+
let result;
|
|
2034
|
+
if (subcommand === "show")
|
|
2035
|
+
result = await client.getAgentConversation(options.intentId);
|
|
2036
|
+
else {
|
|
2037
|
+
const text = positionals.slice(1).join(" ");
|
|
2038
|
+
if (!text.trim())
|
|
2039
|
+
throw new Error("A message is required");
|
|
2040
|
+
result = options.questionId ? await client.answerAgentQuestions(options.intentId, [{ questionId: options.questionId, text }]) : await client.sendMessage("agent", text, options.intentId);
|
|
2041
|
+
}
|
|
2042
|
+
console.log(JSON.stringify(result, null, options.json ? undefined : 2));
|
|
2043
|
+
return;
|
|
2044
|
+
}
|
|
2045
|
+
if (subcommand === "answer") {
|
|
2046
|
+
if (positionals[0] !== "agent" || !options?.intentId || !options.answers?.length) {
|
|
2047
|
+
throw new Error("Usage: index conversation answer agent --intent-id <id> --answer 'question-id=text' [--answer ...]");
|
|
2048
|
+
}
|
|
2049
|
+
const result = await client.answerAgentQuestions(options.intentId, options.answers.map(({ key, value }) => ({ questionId: key, text: value })));
|
|
2050
|
+
console.log(JSON.stringify(result, null, options.json ? undefined : 2));
|
|
2398
2051
|
return;
|
|
2399
2052
|
}
|
|
2053
|
+
if (!subcommand)
|
|
2054
|
+
throw new Error(CONVERSATION_HELP.trim());
|
|
2400
2055
|
switch (subcommand) {
|
|
2401
2056
|
case "list":
|
|
2402
2057
|
await conversationList(client, options?.json);
|
|
@@ -2411,10 +2066,10 @@ async function handleConversation(client, subcommand, positionals, options) {
|
|
|
2411
2066
|
await conversationSend(client, positionals[0], positionals.slice(1), options?.json);
|
|
2412
2067
|
return;
|
|
2413
2068
|
case "stream":
|
|
2414
|
-
await conversationStream(client);
|
|
2069
|
+
await conversationStream(client, options?.json);
|
|
2415
2070
|
return;
|
|
2416
2071
|
case "help":
|
|
2417
|
-
console.log(CONVERSATION_HELP);
|
|
2072
|
+
console.log(options?.json ? JSON.stringify({ help: CONVERSATION_HELP.trim() }) : CONVERSATION_HELP);
|
|
2418
2073
|
return;
|
|
2419
2074
|
default:
|
|
2420
2075
|
error(`Unknown conversation subcommand: ${subcommand}`, 1);
|
|
@@ -2472,11 +2127,11 @@ async function conversationSend(client, id, messageParts, json) {
|
|
|
2472
2127
|
}
|
|
2473
2128
|
success(`Message sent (${msg.id})`);
|
|
2474
2129
|
}
|
|
2475
|
-
async function conversationStream(client) {
|
|
2130
|
+
async function conversationStream(client, json) {
|
|
2476
2131
|
info("Connecting to conversation stream...");
|
|
2477
2132
|
dim(`Press Ctrl+C to stop.
|
|
2478
2133
|
`);
|
|
2479
|
-
const response = await client.
|
|
2134
|
+
const response = await client.streamEvents();
|
|
2480
2135
|
if (!response.body) {
|
|
2481
2136
|
error("No response body from stream endpoint.", 1);
|
|
2482
2137
|
return;
|
|
@@ -2490,33 +2145,21 @@ async function conversationStream(client) {
|
|
|
2490
2145
|
if (done)
|
|
2491
2146
|
break;
|
|
2492
2147
|
buffer += decoder.decode(value, { stream: true });
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
`
|
|
2496
|
-
const idx = buffer.indexOf(`
|
|
2148
|
+
buffer = buffer.replace(/\r\n/g, `
|
|
2149
|
+
`);
|
|
2150
|
+
const boundary = buffer.lastIndexOf(`
|
|
2497
2151
|
|
|
2498
2152
|
`);
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
continue;
|
|
2510
|
-
try {
|
|
2511
|
-
const event = JSON.parse(jsonStr);
|
|
2512
|
-
const type = event.type;
|
|
2513
|
-
if (type === "connected") {
|
|
2514
|
-
success("Connected to conversation stream.");
|
|
2515
|
-
} else {
|
|
2516
|
-
dim(`[${type}] ${JSON.stringify(event)}`);
|
|
2517
|
-
}
|
|
2518
|
-
} catch {}
|
|
2519
|
-
}
|
|
2153
|
+
if (boundary < 0)
|
|
2154
|
+
continue;
|
|
2155
|
+
const complete = buffer.slice(0, boundary + 2);
|
|
2156
|
+
buffer = buffer.slice(boundary + 2);
|
|
2157
|
+
for (const event of parseSSEEvents(complete)) {
|
|
2158
|
+
const data = JSON.parse(event.data);
|
|
2159
|
+
if (json)
|
|
2160
|
+
console.log(JSON.stringify({ event: event.event, data }));
|
|
2161
|
+
else
|
|
2162
|
+
dim(JSON.stringify(data));
|
|
2520
2163
|
}
|
|
2521
2164
|
}
|
|
2522
2165
|
} finally {
|
|
@@ -2524,81 +2167,6 @@ async function conversationStream(client) {
|
|
|
2524
2167
|
}
|
|
2525
2168
|
}
|
|
2526
2169
|
|
|
2527
|
-
// src/contact.command.ts
|
|
2528
|
-
var CONTACT_HELP = `
|
|
2529
|
-
Usage:
|
|
2530
|
-
index contact list List your contacts
|
|
2531
|
-
index contact remove <email> Remove a contact
|
|
2532
|
-
`;
|
|
2533
|
-
async function handleContact(client, subcommand, positionals, options) {
|
|
2534
|
-
if (!subcommand) {
|
|
2535
|
-
if (options.json) {
|
|
2536
|
-
console.log(JSON.stringify({ error: "No subcommand provided" }));
|
|
2537
|
-
} else {
|
|
2538
|
-
console.log(CONTACT_HELP);
|
|
2539
|
-
}
|
|
2540
|
-
return;
|
|
2541
|
-
}
|
|
2542
|
-
switch (subcommand) {
|
|
2543
|
-
case "list": {
|
|
2544
|
-
const result = await client.callTool("list_contacts", {});
|
|
2545
|
-
if (options.json) {
|
|
2546
|
-
console.log(JSON.stringify(result));
|
|
2547
|
-
return;
|
|
2548
|
-
}
|
|
2549
|
-
if (!result.success) {
|
|
2550
|
-
error(result.error ?? "Failed to list contacts", 1);
|
|
2551
|
-
return;
|
|
2552
|
-
}
|
|
2553
|
-
const data = result.data;
|
|
2554
|
-
heading("Contacts");
|
|
2555
|
-
contactTable(data.contacts);
|
|
2556
|
-
dim(`
|
|
2557
|
-
${data.count} contact${data.count !== 1 ? "s" : ""}`);
|
|
2558
|
-
console.log();
|
|
2559
|
-
return;
|
|
2560
|
-
}
|
|
2561
|
-
case "remove": {
|
|
2562
|
-
const email = positionals[0];
|
|
2563
|
-
if (!email) {
|
|
2564
|
-
error("Missing email. Usage: index contact remove <email>", 1);
|
|
2565
|
-
return;
|
|
2566
|
-
}
|
|
2567
|
-
const listResult = await client.callTool("list_contacts", {});
|
|
2568
|
-
if (!listResult.success) {
|
|
2569
|
-
error("Failed to resolve contact", 1);
|
|
2570
|
-
return;
|
|
2571
|
-
}
|
|
2572
|
-
const contacts = listResult.data.contacts;
|
|
2573
|
-
const match = contacts.find((c) => c.email.toLowerCase() === email.toLowerCase());
|
|
2574
|
-
if (!match) {
|
|
2575
|
-
error(`No contact found with email: ${email}`, 1);
|
|
2576
|
-
return;
|
|
2577
|
-
}
|
|
2578
|
-
const result = await client.callTool("remove_contact", { contactUserId: match.userId });
|
|
2579
|
-
if (options.json) {
|
|
2580
|
-
console.log(JSON.stringify(result));
|
|
2581
|
-
return;
|
|
2582
|
-
}
|
|
2583
|
-
if (!result.success) {
|
|
2584
|
-
error(result.error ?? "Failed to remove contact", 1);
|
|
2585
|
-
return;
|
|
2586
|
-
}
|
|
2587
|
-
success(`Removed ${email} from contacts.`);
|
|
2588
|
-
return;
|
|
2589
|
-
}
|
|
2590
|
-
default: {
|
|
2591
|
-
if (options.json) {
|
|
2592
|
-
console.log(JSON.stringify({ error: `Unknown subcommand: ${subcommand}` }));
|
|
2593
|
-
} else {
|
|
2594
|
-
error(`Unknown subcommand: ${subcommand}`);
|
|
2595
|
-
console.log(CONTACT_HELP);
|
|
2596
|
-
}
|
|
2597
|
-
return;
|
|
2598
|
-
}
|
|
2599
|
-
}
|
|
2600
|
-
}
|
|
2601
|
-
|
|
2602
2170
|
// src/scrape.command.ts
|
|
2603
2171
|
async function handleScrape(client, positionals, options) {
|
|
2604
2172
|
const url = positionals[0];
|
|
@@ -2608,20 +2176,15 @@ async function handleScrape(client, positionals, options) {
|
|
|
2608
2176
|
}
|
|
2609
2177
|
if (!options.json)
|
|
2610
2178
|
info(`Scraping ${url}...`);
|
|
2611
|
-
const result = await client.
|
|
2179
|
+
const result = await client.scrapeUrl(url, options.objective);
|
|
2612
2180
|
if (options.json) {
|
|
2613
2181
|
console.log(JSON.stringify(result));
|
|
2614
2182
|
return;
|
|
2615
2183
|
}
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
return;
|
|
2619
|
-
}
|
|
2620
|
-
const data = result.data;
|
|
2621
|
-
heading(`Content from ${data.url}`);
|
|
2622
|
-
console.log(data.content);
|
|
2184
|
+
heading(`Content from ${result.url}`);
|
|
2185
|
+
console.log(result.content);
|
|
2623
2186
|
dim(`
|
|
2624
|
-
${
|
|
2187
|
+
${result.contentLength} characters extracted`);
|
|
2625
2188
|
console.log();
|
|
2626
2189
|
}
|
|
2627
2190
|
|
|
@@ -2632,18 +2195,17 @@ import { join as join2 } from "node:path";
|
|
|
2632
2195
|
async function handleSync(client, options) {
|
|
2633
2196
|
if (!options.json)
|
|
2634
2197
|
info("Syncing context...");
|
|
2635
|
-
const
|
|
2636
|
-
|
|
2637
|
-
client.
|
|
2638
|
-
client.
|
|
2639
|
-
client.
|
|
2198
|
+
const me = await client.getMe();
|
|
2199
|
+
const [profile, networks, intents] = await Promise.all([
|
|
2200
|
+
client.getUser(me.id),
|
|
2201
|
+
client.listNetworks(),
|
|
2202
|
+
client.listIntents({ limit: 100 })
|
|
2640
2203
|
]);
|
|
2641
2204
|
const context = {
|
|
2642
2205
|
syncedAt: new Date().toISOString(),
|
|
2643
|
-
profile
|
|
2644
|
-
networks
|
|
2645
|
-
intents: intents.
|
|
2646
|
-
contacts: contacts.success ? contacts.data : null
|
|
2206
|
+
profile,
|
|
2207
|
+
networks,
|
|
2208
|
+
intents: intents.intents
|
|
2647
2209
|
};
|
|
2648
2210
|
if (options.json) {
|
|
2649
2211
|
console.log(JSON.stringify(context));
|
|
@@ -2655,190 +2217,100 @@ async function handleSync(client, options) {
|
|
|
2655
2217
|
success("Context synced to ~/.index/context.json");
|
|
2656
2218
|
}
|
|
2657
2219
|
|
|
2658
|
-
// src/
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
index onboarding complete Mark onboarding as complete
|
|
2662
|
-
`;
|
|
2663
|
-
async function handleOnboarding(client, subcommand, options) {
|
|
2664
|
-
if (subcommand === "complete") {
|
|
2665
|
-
await onboardingComplete(client, options?.json);
|
|
2666
|
-
return;
|
|
2667
|
-
}
|
|
2668
|
-
console.log(ONBOARDING_HELP);
|
|
2669
|
-
}
|
|
2670
|
-
async function onboardingComplete(client, json) {
|
|
2671
|
-
if (!json) {
|
|
2672
|
-
info("Completing onboarding...");
|
|
2673
|
-
}
|
|
2674
|
-
const result = await client.callTool("complete_onboarding", {});
|
|
2220
|
+
// src/docs.command.ts
|
|
2221
|
+
async function handleDocs(client, topic, json) {
|
|
2222
|
+
const result = await client.readDocs(topic);
|
|
2675
2223
|
if (json) {
|
|
2676
2224
|
console.log(JSON.stringify(result));
|
|
2677
2225
|
return;
|
|
2678
2226
|
}
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2227
|
+
console.log(result.content);
|
|
2228
|
+
if (result.topics)
|
|
2229
|
+
dim(`
|
|
2230
|
+
Topics: ${result.topics.join(", ")}`);
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
// src/onboarding.command.ts
|
|
2234
|
+
async function handleOnboarding(client, subcommand, options) {
|
|
2235
|
+
let result;
|
|
2236
|
+
if (subcommand === "confirm-profile")
|
|
2237
|
+
result = await client.confirmProfile();
|
|
2238
|
+
else if (subcommand === "complete")
|
|
2239
|
+
result = await client.completeOnboarding(options?.intentId);
|
|
2240
|
+
else
|
|
2241
|
+
throw new Error("Usage: index onboarding confirm-profile | complete [--intent-id <id>]");
|
|
2242
|
+
console.log(JSON.stringify(result, null, options?.json ? undefined : 2));
|
|
2684
2243
|
}
|
|
2685
2244
|
|
|
2686
2245
|
// src/main.ts
|
|
2687
2246
|
var DEFAULT_API_URL = "https://protocol.index.network";
|
|
2688
|
-
var
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
}
|
|
2697
|
-
|
|
2698
|
-
const
|
|
2699
|
-
|
|
2700
|
-
const innerTop = `${BOX.h} ${title} ${BOX.h.repeat(dashRun)}`;
|
|
2701
|
-
console.log(`${GRAY}${BOX.tl}${innerTop}${BOX.tr}${RESET}`);
|
|
2702
|
-
for (const row of rows) {
|
|
2703
|
-
console.log(`${GRAY}${BOX.v}${RESET}${padVisual(row, innerW)}${GRAY}${BOX.v}${RESET}`);
|
|
2704
|
-
}
|
|
2705
|
-
console.log(`${GRAY}${BOX.bl}${BOX.h.repeat(innerW)}${BOX.br}${RESET}
|
|
2706
|
-
`);
|
|
2247
|
+
var LOGIN_API_URLS = {
|
|
2248
|
+
local: "http://localhost:3001",
|
|
2249
|
+
dev: "https://protocol.dev.index.network",
|
|
2250
|
+
prod: DEFAULT_API_URL
|
|
2251
|
+
};
|
|
2252
|
+
function webOriginForApi(apiUrl) {
|
|
2253
|
+
const url = new URL(apiUrl);
|
|
2254
|
+
if (url.hostname === "localhost" || url.hostname === "127.0.0.1") {
|
|
2255
|
+
return `${url.protocol}//${url.hostname}:3000`;
|
|
2256
|
+
}
|
|
2257
|
+
const hostname = url.hostname.startsWith("protocol.") ? url.hostname.slice("protocol.".length) : url.hostname;
|
|
2258
|
+
return `https://${hostname}`;
|
|
2707
2259
|
}
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
]
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
"profile",
|
|
2745
|
-
"conversation",
|
|
2746
|
-
"network",
|
|
2747
|
-
"contact",
|
|
2748
|
-
"scrape",
|
|
2749
|
-
"sync",
|
|
2750
|
-
"onboarding"
|
|
2751
|
-
];
|
|
2752
|
-
const cmdLW = Math.max(...cmdLefts.map((s) => s.length));
|
|
2753
|
-
const optLefts = [
|
|
2754
|
-
"--api-url <url>",
|
|
2755
|
-
"--app-url <url>",
|
|
2756
|
-
"--archived",
|
|
2757
|
-
"--status <status>",
|
|
2758
|
-
"--limit <n>",
|
|
2759
|
-
"--since <date>",
|
|
2760
|
-
"--json",
|
|
2761
|
-
"--objective <text>",
|
|
2762
|
-
"--linkedin <url>",
|
|
2763
|
-
"--github <url>",
|
|
2764
|
-
"--twitter <url>",
|
|
2765
|
-
"--title <text>",
|
|
2766
|
-
"--details <text>",
|
|
2767
|
-
"--help",
|
|
2768
|
-
"--version"
|
|
2769
|
-
];
|
|
2770
|
-
const optLW = Math.max(...optLefts.map((s) => s.length));
|
|
2771
|
-
console.log();
|
|
2772
|
-
console.log(` ${BOLD}${CYAN}I N D E X${RESET} ${GRAY}cli${RESET}`);
|
|
2773
|
-
console.log(` ${GRAY}v${VERSION}${RESET}
|
|
2774
|
-
`);
|
|
2775
|
-
panel("getting started", [
|
|
2776
|
-
helpRowCmd(gsLW, "index login", "authenticate via browser"),
|
|
2777
|
-
helpRowCmd(gsLW, "index logout", "clear stored session"),
|
|
2778
|
-
helpRowCmd(gsLW, 'index intent create "..."', "describe what you're looking for"),
|
|
2779
|
-
helpRowCmd(gsLW, "index negotiation list", "see agent debates in progress"),
|
|
2780
|
-
helpRowCmd(gsLW, "index opportunity list", "see what was found for you")
|
|
2781
|
-
]);
|
|
2782
|
-
panel("common forms", [
|
|
2783
|
-
helpRowCmd(formsLW, "index conversation list", "list your conversations"),
|
|
2784
|
-
helpRowCmd(formsLW, "index sync --json", "print synced context as JSON"),
|
|
2785
|
-
"",
|
|
2786
|
-
helpRowCmd(formsLW, "index profile create", "use social URL flags"),
|
|
2787
|
-
helpRowCmd(formsLW, "index profile update", "use action text or --details"),
|
|
2788
|
-
helpRowCmd(formsLW, "index intent list", "supports --archived and --limit"),
|
|
2789
|
-
helpRowCmd(formsLW, "index negotiation list", "supports --since and --limit"),
|
|
2790
|
-
helpRowCmd(formsLW, "index opportunity list", "supports --status and --limit")
|
|
2791
|
-
]);
|
|
2792
|
-
panel("commands", [
|
|
2793
|
-
helpRowDim(cmdLW, "pattern", "index <command> [args] [options]"),
|
|
2794
|
-
helpRowDim(cmdLW, "example", 'index intent create "looking for a CTO"'),
|
|
2795
|
-
"",
|
|
2796
|
-
helpRowCmd(cmdLW, "intent", "list · show · create · update · archive"),
|
|
2797
|
-
helpRowCont(cmdLW, "link · unlink · links"),
|
|
2798
|
-
helpRowCmd(cmdLW, "negotiation", "list · show"),
|
|
2799
|
-
"",
|
|
2800
|
-
helpRowCmd(cmdLW, "profile", "show · sync · search · create · update"),
|
|
2801
|
-
helpRowCmd(cmdLW, "conversation", "list · with · show · send · stream"),
|
|
2802
|
-
helpRowCmd(cmdLW, "network", "list · create · show · update · delete"),
|
|
2803
|
-
helpRowCont(cmdLW, "join · leave · invite"),
|
|
2804
|
-
helpRowCmd(cmdLW, "contact", "list · remove"),
|
|
2805
|
-
"",
|
|
2806
|
-
helpRowCmd(cmdLW, "scrape", "extract content from a URL"),
|
|
2807
|
-
helpRowCmd(cmdLW, "sync", "download your context locally"),
|
|
2808
|
-
helpRowCmd(cmdLW, "onboarding", "finish account setup")
|
|
2809
|
-
]);
|
|
2810
|
-
panel("options", [
|
|
2811
|
-
helpRowDim(optLW, "--api-url <url>", "override API server URL"),
|
|
2812
|
-
helpRowDim(optLW, "--app-url <url>", "override app URL for login"),
|
|
2813
|
-
helpRowDim(optLW, "--archived", "include archived signals"),
|
|
2814
|
-
helpRowDim(optLW, "--status <status>", "filter opportunities by status"),
|
|
2815
|
-
helpRowDim(optLW, "--limit <n>", "limit number of results"),
|
|
2816
|
-
helpRowDim(optLW, "--since <date>", "filter by ISO date or duration"),
|
|
2817
|
-
helpRowDim(optLW, "--json", "output raw JSON"),
|
|
2818
|
-
helpRowDim(optLW, "--objective <text>", "objective for scrape command"),
|
|
2819
|
-
helpRowDim(optLW, "--linkedin <url>", "LinkedIn URL for profile create"),
|
|
2820
|
-
helpRowDim(optLW, "--github <url>", "GitHub URL for profile create"),
|
|
2821
|
-
helpRowDim(optLW, "--twitter <url>", "Twitter URL for profile create"),
|
|
2822
|
-
helpRowDim(optLW, "--title <text>", "title for network update"),
|
|
2823
|
-
helpRowDim(optLW, "--details <text>", "details for profile update"),
|
|
2824
|
-
helpRowDim(optLW, "--help", "show help for any command"),
|
|
2825
|
-
helpRowDim(optLW, "--version", "show version")
|
|
2826
|
-
]);
|
|
2260
|
+
var VERSION = package_default.version;
|
|
2261
|
+
function renderHelp(json) {
|
|
2262
|
+
const help = `Usage: index <command> [args] [options]
|
|
2263
|
+
|
|
2264
|
+
login [local|dev|prod] [--app-url <url>] Authenticate through the matching web app
|
|
2265
|
+
logout Revoke and clear the stored session
|
|
2266
|
+
docs [topic] Read the protocol's canonical guidance
|
|
2267
|
+
agent me Read your selected personal agent
|
|
2268
|
+
profile [show <user-id>|sync|update] Read, research, or edit your profile
|
|
2269
|
+
intent list|show|prepare|create|update|pause|resume|archive|networks|add-to-network|remove-from-network
|
|
2270
|
+
network list|discover|requests|request-update|request-dismiss|show|create|update|delete|join|leave|invite
|
|
2271
|
+
opportunity list|show|accept|reject|start-chat
|
|
2272
|
+
negotiation list [--intent-id <id>] [--state open|settled]
|
|
2273
|
+
negotiation show <opportunity-id>
|
|
2274
|
+
negotiation turn <opportunity-id> --action propose|counter|accept|decline
|
|
2275
|
+
--message <text> --expected-turn-count <n>
|
|
2276
|
+
conversation list|with|show|send|answer|stream
|
|
2277
|
+
conversation show agent --intent-id <id>
|
|
2278
|
+
conversation send agent <text> --intent-id <id> [--question-id <id>]
|
|
2279
|
+
onboarding confirm-profile
|
|
2280
|
+
onboarding complete [--intent-id <id>]
|
|
2281
|
+
scrape <url> [--objective <text>]
|
|
2282
|
+
sync Download profile, networks, and intents
|
|
2283
|
+
|
|
2284
|
+
Global options: --api-url <origin>, --json, --help, --version
|
|
2285
|
+
List options: --archived (intents), --status (opportunities), --limit <n>
|
|
2286
|
+
Intent list options: --query <text> (matches description and summary)
|
|
2287
|
+
Network options: --prompt <text> (create), --title <text> (update)
|
|
2288
|
+
|
|
2289
|
+
Auth: INDEX_SESSION_TOKEN or INDEX_API_KEY, otherwise stored browser login.
|
|
2290
|
+
API origin: --api-url, INDEX_API_URL, stored login URL, production default.
|
|
2291
|
+
Login target: local (localhost:3001), dev (protocol.dev.index.network), prod (default).
|
|
2292
|
+
--json emits one result/error; conversation stream emits NDJSON events.`;
|
|
2293
|
+
console.log(json ? JSON.stringify({ version: VERSION, help }) : `Index CLI ${VERSION}
|
|
2294
|
+
|
|
2295
|
+
${help}`);
|
|
2827
2296
|
}
|
|
2828
2297
|
async function requireAuth(apiUrlOverride) {
|
|
2829
2298
|
const store = new CredentialStore;
|
|
2830
2299
|
const creds = await store.load();
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
const
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2300
|
+
const session = process.env.INDEX_SESSION_TOKEN || undefined;
|
|
2301
|
+
const apiKey = process.env.INDEX_API_KEY || undefined;
|
|
2302
|
+
if (session && apiKey)
|
|
2303
|
+
throw new Error("Set only one of INDEX_SESSION_TOKEN and INDEX_API_KEY");
|
|
2304
|
+
const token = session ?? apiKey ?? creds?.token;
|
|
2305
|
+
if (!token)
|
|
2306
|
+
throw new Error("Not logged in. Run `index login` or set INDEX_SESSION_TOKEN or INDEX_API_KEY.");
|
|
2307
|
+
const apiUrl = apiUrlOverride ?? process.env.INDEX_API_URL ?? creds?.apiUrl ?? DEFAULT_API_URL;
|
|
2308
|
+
return new ApiClient(apiUrl, token, apiKey ? "apiKey" : "session");
|
|
2309
|
+
}
|
|
2310
|
+
async function runLogin(target, apiUrlOverride, appUrlOverride, json) {
|
|
2839
2311
|
const store = new CredentialStore;
|
|
2840
|
-
const apiUrl = apiUrlOverride ?? DEFAULT_API_URL;
|
|
2841
|
-
const appUrl = appUrlOverride ??
|
|
2312
|
+
const apiUrl = apiUrlOverride ?? (target ? LOGIN_API_URLS[target] : undefined) ?? process.env.INDEX_API_URL ?? (await store.load())?.apiUrl ?? DEFAULT_API_URL;
|
|
2313
|
+
const appUrl = appUrlOverride ?? webOriginForApi(apiUrl);
|
|
2842
2314
|
info(`Authenticating with ${apiUrl}...`);
|
|
2843
2315
|
const { authUrl, callbackPromise } = await handleLogin(apiUrl, appUrl, store);
|
|
2844
2316
|
info("Opening browser for authentication...");
|
|
@@ -2865,6 +2337,12 @@ async function runLogin(apiUrlOverride, appUrlOverride) {
|
|
|
2865
2337
|
} catch {}
|
|
2866
2338
|
dim("Waiting for authentication callback...");
|
|
2867
2339
|
const result = await callbackPromise;
|
|
2340
|
+
if (json) {
|
|
2341
|
+
if (!result.success)
|
|
2342
|
+
throw new Error(result.error ?? "Login failed.");
|
|
2343
|
+
console.log(JSON.stringify(result));
|
|
2344
|
+
return;
|
|
2345
|
+
}
|
|
2868
2346
|
if (result.success) {
|
|
2869
2347
|
try {
|
|
2870
2348
|
const creds = await store.load();
|
|
@@ -2882,8 +2360,14 @@ async function runLogin(apiUrlOverride, appUrlOverride) {
|
|
|
2882
2360
|
error(result.error ?? "Login failed.", 1);
|
|
2883
2361
|
}
|
|
2884
2362
|
}
|
|
2885
|
-
async function runLogout() {
|
|
2363
|
+
async function runLogout(json) {
|
|
2886
2364
|
const result = await handleLogout(new CredentialStore);
|
|
2365
|
+
if (json) {
|
|
2366
|
+
console.log(JSON.stringify(result));
|
|
2367
|
+
if (!result.success)
|
|
2368
|
+
process.exitCode = 1;
|
|
2369
|
+
return;
|
|
2370
|
+
}
|
|
2887
2371
|
if (result.success) {
|
|
2888
2372
|
success(result.message);
|
|
2889
2373
|
return;
|
|
@@ -2895,30 +2379,38 @@ async function main() {
|
|
|
2895
2379
|
const args = parseArgs(process.argv.slice(2));
|
|
2896
2380
|
switch (args.command) {
|
|
2897
2381
|
case "help":
|
|
2898
|
-
renderHelp();
|
|
2382
|
+
renderHelp(args.json);
|
|
2899
2383
|
return;
|
|
2900
2384
|
case "version":
|
|
2901
|
-
console.log(VERSION);
|
|
2385
|
+
console.log(args.json ? JSON.stringify({ version: VERSION }) : VERSION);
|
|
2902
2386
|
return;
|
|
2903
2387
|
case "unknown":
|
|
2904
2388
|
error(`Unknown command: ${args.unknown}`, 1);
|
|
2905
2389
|
return;
|
|
2906
2390
|
case "login":
|
|
2907
|
-
await runLogin(args.apiUrl, args.appUrl);
|
|
2391
|
+
await runLogin(args.loginTarget, args.apiUrl, args.appUrl, args.json);
|
|
2908
2392
|
return;
|
|
2909
2393
|
case "logout":
|
|
2910
|
-
await runLogout();
|
|
2394
|
+
await runLogout(args.json);
|
|
2911
2395
|
return;
|
|
2912
2396
|
}
|
|
2913
2397
|
const client = await requireAuth(args.apiUrl);
|
|
2914
2398
|
switch (args.command) {
|
|
2399
|
+
case "docs":
|
|
2400
|
+
await handleDocs(client, args.positionals?.[0], args.json);
|
|
2401
|
+
return;
|
|
2402
|
+
case "agent":
|
|
2403
|
+
if (args.subcommand !== "me")
|
|
2404
|
+
throw new Error("Usage: index agent me");
|
|
2405
|
+
console.log(JSON.stringify(await client.getAgent(), null, args.json ? undefined : 2));
|
|
2406
|
+
return;
|
|
2915
2407
|
case "profile":
|
|
2916
2408
|
await handleProfile(client, args.subcommand, args.subcommand === "search" || args.subcommand === "update" ? args.positionals ?? [] : args.userId ? [args.userId] : [], {
|
|
2917
2409
|
json: args.json,
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2410
|
+
name: args.name,
|
|
2411
|
+
intro: args.intro,
|
|
2412
|
+
location: args.location,
|
|
2413
|
+
socials: args.socials
|
|
2922
2414
|
});
|
|
2923
2415
|
return;
|
|
2924
2416
|
case "intent":
|
|
@@ -2928,24 +2420,31 @@ async function main() {
|
|
|
2928
2420
|
archived: args.archived,
|
|
2929
2421
|
limit: args.limit,
|
|
2930
2422
|
json: args.json,
|
|
2931
|
-
targetId: args.targetId
|
|
2423
|
+
targetId: args.targetId,
|
|
2424
|
+
query: args.query,
|
|
2425
|
+
receipt: args.receipt,
|
|
2426
|
+
answers: args.answers
|
|
2932
2427
|
});
|
|
2933
2428
|
return;
|
|
2934
2429
|
case "opportunity":
|
|
2935
2430
|
await handleOpportunity(client, args.subcommand, {
|
|
2936
2431
|
targetId: args.targetId,
|
|
2937
2432
|
status: args.status,
|
|
2433
|
+
statuses: args.statuses,
|
|
2434
|
+
intentId: args.intentId,
|
|
2938
2435
|
limit: args.limit,
|
|
2939
2436
|
json: args.json,
|
|
2940
|
-
positionals: args.positionals
|
|
2941
|
-
acknowledgeUptake: args.acknowledgeUptake
|
|
2437
|
+
positionals: args.positionals
|
|
2942
2438
|
});
|
|
2943
2439
|
return;
|
|
2944
2440
|
case "negotiation":
|
|
2945
2441
|
await handleNegotiation(client, args.subcommand, {
|
|
2946
2442
|
targetId: args.targetId,
|
|
2947
|
-
|
|
2948
|
-
|
|
2443
|
+
intentId: args.intentId,
|
|
2444
|
+
state: args.state,
|
|
2445
|
+
action: args.action,
|
|
2446
|
+
message: args.message,
|
|
2447
|
+
expectedTurnCount: args.expectedTurnCount,
|
|
2949
2448
|
json: args.json
|
|
2950
2449
|
});
|
|
2951
2450
|
return;
|
|
@@ -2959,12 +2458,10 @@ async function main() {
|
|
|
2959
2458
|
case "conversation":
|
|
2960
2459
|
await handleConversation(client, args.subcommand, args.positionals ?? [], {
|
|
2961
2460
|
limit: args.limit,
|
|
2962
|
-
json: args.json
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
await handleContact(client, args.subcommand, args.positionals ?? [], {
|
|
2967
|
-
json: args.json
|
|
2461
|
+
json: args.json,
|
|
2462
|
+
intentId: args.intentId,
|
|
2463
|
+
questionId: args.questionId,
|
|
2464
|
+
answers: args.answers
|
|
2968
2465
|
});
|
|
2969
2466
|
return;
|
|
2970
2467
|
case "scrape":
|
|
@@ -2974,7 +2471,7 @@ async function main() {
|
|
|
2974
2471
|
});
|
|
2975
2472
|
return;
|
|
2976
2473
|
case "onboarding":
|
|
2977
|
-
await handleOnboarding(client, args.subcommand, { json: args.json });
|
|
2474
|
+
await handleOnboarding(client, args.subcommand, { json: args.json, intentId: args.intentId });
|
|
2978
2475
|
return;
|
|
2979
2476
|
case "sync":
|
|
2980
2477
|
await handleSync(client, { json: args.json });
|
|
@@ -2982,5 +2479,9 @@ async function main() {
|
|
|
2982
2479
|
}
|
|
2983
2480
|
}
|
|
2984
2481
|
main().catch((err) => {
|
|
2985
|
-
|
|
2482
|
+
if (process.argv.includes("--json")) {
|
|
2483
|
+
console.log(JSON.stringify(err instanceof ApiError ? { error: err.message, status: err.status, response: err.response } : { error: err instanceof Error ? err.message : String(err) }));
|
|
2484
|
+
process.exitCode = 1;
|
|
2485
|
+
} else
|
|
2486
|
+
error(err instanceof Error ? err.message : String(err), 1);
|
|
2986
2487
|
});
|