@heyditto/cli 1.4.0 → 1.6.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 +63 -8
- package/dist/cli.js +479 -404
- package/dist/cli.js.map +1 -1
- package/package.json +6 -3
package/dist/cli.js
CHANGED
|
@@ -2,14 +2,26 @@
|
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
3
|
import { readFile } from "node:fs/promises";
|
|
4
4
|
import { createInterface } from "node:readline/promises";
|
|
5
|
-
import { parseArgs } from "node:util";
|
|
6
5
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
7
6
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
7
|
+
import { Command, Option } from "commander";
|
|
8
8
|
import { agentSignupURL, apiBaseURL, authFilePath, mcpServerURL, newKeyURL, packageName, packageVersion, resolveApiKey, } from "./config.js";
|
|
9
9
|
import { clearStoredKey, readStoredAuth, writeStoredAuth, writeStoredKey } from "./store.js";
|
|
10
10
|
const OUTPUT_FORMATS = ["json", "text", "markdown", "raw"];
|
|
11
|
-
const outputOption = { type: "string" };
|
|
12
11
|
const MEMORY_FORMATS = ["full", "outline", "blocks"];
|
|
12
|
+
function outputOption() {
|
|
13
|
+
return new Option("--output <format>", "output format")
|
|
14
|
+
.choices([...OUTPUT_FORMATS])
|
|
15
|
+
.default("text");
|
|
16
|
+
}
|
|
17
|
+
function hiddenOutputOption() {
|
|
18
|
+
return outputOption().hideHelp();
|
|
19
|
+
}
|
|
20
|
+
function memoryFormatOption() {
|
|
21
|
+
return new Option("--memory-format <format>", "memory body format")
|
|
22
|
+
.choices([...MEMORY_FORMATS])
|
|
23
|
+
.default("full");
|
|
24
|
+
}
|
|
13
25
|
function parseOutputFormat(value) {
|
|
14
26
|
if (!value)
|
|
15
27
|
return "text";
|
|
@@ -32,6 +44,14 @@ function parseIntegerOption(value, name) {
|
|
|
32
44
|
throw new Error(`${name} must be an integer`);
|
|
33
45
|
return n;
|
|
34
46
|
}
|
|
47
|
+
function parseNumberOption(value, name) {
|
|
48
|
+
if (!value)
|
|
49
|
+
return undefined;
|
|
50
|
+
const n = Number.parseFloat(value);
|
|
51
|
+
if (!Number.isFinite(n))
|
|
52
|
+
throw new Error(`${name} must be a number`);
|
|
53
|
+
return n;
|
|
54
|
+
}
|
|
35
55
|
function parseJSONOption(value, name) {
|
|
36
56
|
try {
|
|
37
57
|
return JSON.parse(value);
|
|
@@ -72,60 +92,9 @@ function formatToolResult(result, format) {
|
|
|
72
92
|
return JSON.stringify({ text }, null, 2);
|
|
73
93
|
}
|
|
74
94
|
}
|
|
75
|
-
// text / markdown
|
|
95
|
+
// text / markdown: pass the text block through; fall back to raw envelope.
|
|
76
96
|
return text ?? JSON.stringify(result, null, 2);
|
|
77
97
|
}
|
|
78
|
-
function usage() {
|
|
79
|
-
return `${packageName} ${packageVersion}
|
|
80
|
-
|
|
81
|
-
Usage:
|
|
82
|
-
heyditto save <content> [--source <s>] [--source-context <c>]
|
|
83
|
-
heyditto search <query>... [--include-public] [--filter-username <u>]
|
|
84
|
-
heyditto fetch <id>... [--memory-format full|outline|blocks]
|
|
85
|
-
heyditto list [--username <u>] [--limit <n>] [--offset <n>] [--source <s>]
|
|
86
|
-
heyditto update <id> [--content <text>|--content-file <path>] [--title <t>]
|
|
87
|
-
[--source-context <c>] [--edits-json <json>|--edits-file <path>]
|
|
88
|
-
[--base-revision <n>]
|
|
89
|
-
heyditto publish <id> [--title <t>] [--privacy-mode scan_and_block|scan_and_warn|scan_and_redact]
|
|
90
|
-
heyditto unpublish (--memory-id <id>|--share-id <id>|<id>)
|
|
91
|
-
heyditto subjects <query> [--top-k <n>]
|
|
92
|
-
heyditto memories <subject-id>... [--query <q>]
|
|
93
|
-
heyditto network <pair-id> [--limit <n>]
|
|
94
|
-
heyditto graphs create <name> Create a dedicated graph you own
|
|
95
|
-
heyditto graphs list Public graphs you're subscribed to
|
|
96
|
-
heyditto graphs add <@username> Subscribe to a public graph
|
|
97
|
-
heyditto graphs remove <@username> Unsubscribe from a public graph
|
|
98
|
-
heyditto graphs subscribers Who is subscribed to your graph
|
|
99
|
-
heyditto init --agent [--agent-caller <name>] [--json]
|
|
100
|
-
|
|
101
|
-
All data commands (and 'status') accept --output <format>, where <format>
|
|
102
|
-
is one of: json, text, markdown, raw. Default is 'text' (passthrough of
|
|
103
|
-
the server's text block, which is JSON for data commands). Use --output json
|
|
104
|
-
to guarantee structured JSON output suitable for piping into 'jq'.
|
|
105
|
-
|
|
106
|
-
Auth:
|
|
107
|
-
heyditto init --agent [--json] Create a free, claimable agent account
|
|
108
|
-
heyditto login [<key>] [--paste] [--stdin] Save an API key to ${authFilePath()}
|
|
109
|
-
heyditto logout Delete the saved key
|
|
110
|
-
heyditto status [--output <format>] Show endpoint, key source, live tools
|
|
111
|
-
heyditto config Print MCP client config snippet
|
|
112
|
-
|
|
113
|
-
Other:
|
|
114
|
-
heyditto help Show this message
|
|
115
|
-
|
|
116
|
-
Note: on macOS, Apple ships /usr/bin/ditto (a file-copy utility). If 'ditto'
|
|
117
|
-
runs the wrong tool, install with 'npm i -g @heyditto/cli' and invoke as
|
|
118
|
-
'heyditto' (alias bin), or check 'type -a ditto' to disambiguate.
|
|
119
|
-
|
|
120
|
-
Environment:
|
|
121
|
-
DITTO_API_KEY Optional override (takes precedence over the saved key).
|
|
122
|
-
Run 'heyditto init --agent --json' for no-human setup, or get
|
|
123
|
-
a human-owned key at ${newKeyURL()}.
|
|
124
|
-
DITTO_API_BASE Optional. Defaults to https://api.heyditto.ai.
|
|
125
|
-
DITTO_CONFIG_DIR Optional. Defaults to $XDG_CONFIG_HOME/heyditto/cli or
|
|
126
|
-
~/.config/heyditto/cli.
|
|
127
|
-
`;
|
|
128
|
-
}
|
|
129
98
|
async function getClient() {
|
|
130
99
|
const { key, source } = await resolveApiKey();
|
|
131
100
|
if (!key) {
|
|
@@ -161,11 +130,6 @@ async function callAndPrint(name, args, format) {
|
|
|
161
130
|
await client.close();
|
|
162
131
|
}
|
|
163
132
|
}
|
|
164
|
-
function requirePositionals(positionals, minimum, label) {
|
|
165
|
-
if (positionals.length < minimum) {
|
|
166
|
-
throw new Error(`${label}: expected at least ${minimum} argument(s), got ${positionals.length}`);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
133
|
async function readKeyFromStdin() {
|
|
170
134
|
return new Promise((resolve, reject) => {
|
|
171
135
|
let buf = "";
|
|
@@ -189,28 +153,19 @@ function openInBrowser(url) {
|
|
|
189
153
|
const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
|
|
190
154
|
const child = spawn(cmd, args, { stdio: "ignore", detached: true });
|
|
191
155
|
child.on("error", () => {
|
|
192
|
-
/* swallow
|
|
156
|
+
/* swallow: best-effort */
|
|
193
157
|
});
|
|
194
158
|
child.unref();
|
|
195
159
|
}
|
|
196
|
-
async function cmdLogin(
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
paste: { type: "boolean", default: false },
|
|
201
|
-
stdin: { type: "boolean", default: false },
|
|
202
|
-
output: outputOption,
|
|
203
|
-
},
|
|
204
|
-
allowPositionals: true,
|
|
205
|
-
});
|
|
206
|
-
parseOutputFormat(values.output); // validate but ignored — login is interactive
|
|
207
|
-
let key = positionals[0]?.trim();
|
|
208
|
-
if (!key && values.stdin) {
|
|
160
|
+
async function cmdLogin(keyArg, options) {
|
|
161
|
+
parseOutputFormat(options.output); // validate but ignored: login is interactive
|
|
162
|
+
let key = keyArg?.trim();
|
|
163
|
+
if (!key && options.stdin) {
|
|
209
164
|
key = (await readKeyFromStdin()).trim();
|
|
210
165
|
}
|
|
211
166
|
else if (!key) {
|
|
212
|
-
if (
|
|
213
|
-
process.stderr.write(`Opening ${newKeyURL()} in your browser
|
|
167
|
+
if (options.paste) {
|
|
168
|
+
process.stderr.write(`Opening ${newKeyURL()} in your browser...\n`);
|
|
214
169
|
openInBrowser(newKeyURL());
|
|
215
170
|
}
|
|
216
171
|
if (!process.stdin.isTTY) {
|
|
@@ -221,7 +176,7 @@ async function cmdLogin(rest) {
|
|
|
221
176
|
if (!key)
|
|
222
177
|
throw new Error("no key provided");
|
|
223
178
|
if (!key.startsWith("ditto_mcp_")) {
|
|
224
|
-
process.stderr.write(`warning: key does not start with "ditto_mcp_"
|
|
179
|
+
process.stderr.write(`warning: key does not start with "ditto_mcp_" - proceeding anyway\n`);
|
|
225
180
|
}
|
|
226
181
|
await writeStoredKey(key);
|
|
227
182
|
process.stdout.write(`Saved key to ${authFilePath()}\n`);
|
|
@@ -233,21 +188,19 @@ async function cmdLogin(rest) {
|
|
|
233
188
|
function defaultAgentCaller() {
|
|
234
189
|
return process.env.DITTO_AGENT_CALLER?.trim() || process.env.CURSOR_AGENT?.trim() || "agent";
|
|
235
190
|
}
|
|
236
|
-
async function cmdInit(
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
options: {
|
|
240
|
-
agent: { type: "boolean", default: false },
|
|
241
|
-
"agent-caller": { type: "string" },
|
|
242
|
-
json: { type: "boolean", default: false },
|
|
243
|
-
output: outputOption,
|
|
244
|
-
},
|
|
245
|
-
allowPositionals: true,
|
|
246
|
-
});
|
|
247
|
-
const output = values.json ? "json" : parseOutputFormat(values.output);
|
|
248
|
-
if (!values.agent) {
|
|
191
|
+
async function cmdInit(graphs, options) {
|
|
192
|
+
const output = options.json ? "json" : parseOutputFormat(options.output);
|
|
193
|
+
if (!options.agent) {
|
|
249
194
|
throw new Error("init currently supports only --agent");
|
|
250
195
|
}
|
|
196
|
+
// --subscribe pre-subscribes the new agent to public foundation knowledge
|
|
197
|
+
// graphs (e.g. the @minos mentor KG). Accepts repeats and comma-separated
|
|
198
|
+
// lists, plus bare positional graph names: --subscribe @minos @a,@b.
|
|
199
|
+
// De-duped; '@' optional.
|
|
200
|
+
const subscribeGraphs = Array.from(new Set([...(options.subscribe ?? []), ...graphs]
|
|
201
|
+
.flatMap((v) => v.split(","))
|
|
202
|
+
.map((g) => g.trim().replace(/^@/, ""))
|
|
203
|
+
.filter((g) => g.length > 0)));
|
|
251
204
|
const stored = await readStoredAuth();
|
|
252
205
|
if (stored?.apiKey && stored.agentMode) {
|
|
253
206
|
const existing = {
|
|
@@ -273,7 +226,7 @@ async function cmdInit(rest) {
|
|
|
273
226
|
if (stored?.apiKey) {
|
|
274
227
|
throw new Error(`a Ditto API key is already saved at ${authFilePath()}; run 'heyditto logout' before creating an agent account`);
|
|
275
228
|
}
|
|
276
|
-
const agentCaller =
|
|
229
|
+
const agentCaller = options.agentCaller?.trim() || defaultAgentCaller();
|
|
277
230
|
const response = await fetch(agentSignupURL(), {
|
|
278
231
|
method: "POST",
|
|
279
232
|
headers: {
|
|
@@ -282,6 +235,7 @@ async function cmdInit(rest) {
|
|
|
282
235
|
},
|
|
283
236
|
body: JSON.stringify({
|
|
284
237
|
agentCaller,
|
|
238
|
+
...(subscribeGraphs.length > 0 ? { subscribeGraphs } : {}),
|
|
285
239
|
metadata: {
|
|
286
240
|
package: packageName,
|
|
287
241
|
version: packageVersion,
|
|
@@ -324,6 +278,12 @@ async function cmdInit(rest) {
|
|
|
324
278
|
claimURL: signup.claimURL,
|
|
325
279
|
status: signup.status,
|
|
326
280
|
configPath: authFilePath(),
|
|
281
|
+
...(subscribeGraphs.length > 0
|
|
282
|
+
? {
|
|
283
|
+
subscribedGraphs: signup.subscribedGraphs ?? [],
|
|
284
|
+
failedGraphs: signup.failedGraphs ?? [],
|
|
285
|
+
}
|
|
286
|
+
: {}),
|
|
327
287
|
};
|
|
328
288
|
if (output === "json" || output === "raw") {
|
|
329
289
|
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
@@ -331,15 +291,22 @@ async function cmdInit(rest) {
|
|
|
331
291
|
}
|
|
332
292
|
process.stdout.write(`Created agent account ${signup.userID}\n`);
|
|
333
293
|
process.stdout.write(`Saved key to ${authFilePath()}\n`);
|
|
294
|
+
if (subscribeGraphs.length > 0) {
|
|
295
|
+
const subscribed = signup.subscribedGraphs ?? [];
|
|
296
|
+
const failed = signup.failedGraphs ?? [];
|
|
297
|
+
if (subscribed.length > 0) {
|
|
298
|
+
process.stdout.write(`Subscribed to ${subscribed.map((g) => `@${g}`).join(", ")}\n`);
|
|
299
|
+
}
|
|
300
|
+
if (failed.length > 0) {
|
|
301
|
+
process.stdout.write(`Could not subscribe (not found or not public): ${failed
|
|
302
|
+
.map((g) => `@${g}`)
|
|
303
|
+
.join(", ")}\n`);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
334
306
|
process.stdout.write(`Claim later: ${signup.claimURL}\n`);
|
|
335
307
|
}
|
|
336
|
-
async function cmdLogout(
|
|
337
|
-
|
|
338
|
-
args: rest,
|
|
339
|
-
options: { output: outputOption },
|
|
340
|
-
allowPositionals: true,
|
|
341
|
-
});
|
|
342
|
-
parseOutputFormat(values.output);
|
|
308
|
+
async function cmdLogout(options) {
|
|
309
|
+
parseOutputFormat(options.output);
|
|
343
310
|
const removed = await clearStoredKey();
|
|
344
311
|
if (removed) {
|
|
345
312
|
process.stdout.write(`Removed ${authFilePath()}\n`);
|
|
@@ -351,225 +318,183 @@ async function cmdLogout(rest) {
|
|
|
351
318
|
process.stderr.write(`note: DITTO_API_KEY is still set in your environment and will continue to be used.\n`);
|
|
352
319
|
}
|
|
353
320
|
}
|
|
354
|
-
async function cmdSave(
|
|
355
|
-
const
|
|
356
|
-
args: rest,
|
|
357
|
-
options: {
|
|
358
|
-
source: { type: "string", default: "cli" },
|
|
359
|
-
"source-context": { type: "string" },
|
|
360
|
-
output: outputOption,
|
|
361
|
-
},
|
|
362
|
-
allowPositionals: true,
|
|
363
|
-
});
|
|
364
|
-
const format = parseOutputFormat(values.output);
|
|
365
|
-
requirePositionals(positionals, 1, "save");
|
|
321
|
+
async function cmdSave(content, options) {
|
|
322
|
+
const format = parseOutputFormat(options.output);
|
|
366
323
|
await callAndPrint("save_memory", {
|
|
367
|
-
content:
|
|
368
|
-
source:
|
|
369
|
-
sourceContext:
|
|
324
|
+
content: content.join(" "),
|
|
325
|
+
source: options.source ?? "cli",
|
|
326
|
+
sourceContext: options.sourceContext,
|
|
370
327
|
}, format);
|
|
371
328
|
}
|
|
372
|
-
async function cmdSearch(
|
|
373
|
-
const
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
"include-public": { type: "boolean", default: false },
|
|
377
|
-
"filter-username": { type: "string" },
|
|
378
|
-
output: outputOption,
|
|
379
|
-
},
|
|
380
|
-
allowPositionals: true,
|
|
381
|
-
});
|
|
382
|
-
const format = parseOutputFormat(values.output);
|
|
383
|
-
requirePositionals(positionals, 1, "search");
|
|
384
|
-
const args = { queries: positionals };
|
|
385
|
-
if (values["include-public"])
|
|
329
|
+
async function cmdSearch(queries, options) {
|
|
330
|
+
const format = parseOutputFormat(options.output);
|
|
331
|
+
const args = { queries };
|
|
332
|
+
if (options.includePublic)
|
|
386
333
|
args.includePublic = true;
|
|
387
|
-
if (
|
|
388
|
-
args.filterUsername =
|
|
334
|
+
if (options.filterUsername)
|
|
335
|
+
args.filterUsername = options.filterUsername;
|
|
389
336
|
await callAndPrint("search_memories", args, format);
|
|
390
337
|
}
|
|
391
|
-
async function cmdFetch(
|
|
392
|
-
const
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
const format = parseOutputFormat(
|
|
398
|
-
const memoryFormat = parseMemoryFormat(values["memory-format"]);
|
|
399
|
-
requirePositionals(positionals, 1, "fetch");
|
|
400
|
-
await callAndPrint("fetch_memories", { ids: positionals, format: memoryFormat }, format);
|
|
401
|
-
}
|
|
402
|
-
async function cmdList(rest) {
|
|
403
|
-
const { values } = parseArgs({
|
|
404
|
-
args: rest,
|
|
405
|
-
options: {
|
|
406
|
-
username: { type: "string" },
|
|
407
|
-
limit: { type: "string" },
|
|
408
|
-
offset: { type: "string" },
|
|
409
|
-
source: { type: "string" },
|
|
410
|
-
output: outputOption,
|
|
411
|
-
},
|
|
412
|
-
allowPositionals: true,
|
|
413
|
-
});
|
|
414
|
-
const format = parseOutputFormat(values.output);
|
|
338
|
+
async function cmdFetch(ids, options) {
|
|
339
|
+
const format = parseOutputFormat(options.output);
|
|
340
|
+
const memoryFormat = parseMemoryFormat(options.memoryFormat);
|
|
341
|
+
await callAndPrint("fetch_memories", { ids, format: memoryFormat }, format);
|
|
342
|
+
}
|
|
343
|
+
async function cmdList(options) {
|
|
344
|
+
const format = parseOutputFormat(options.output);
|
|
415
345
|
const args = {};
|
|
416
|
-
if (
|
|
417
|
-
args.username =
|
|
418
|
-
const limit = parseIntegerOption(
|
|
346
|
+
if (options.username)
|
|
347
|
+
args.username = options.username;
|
|
348
|
+
const limit = parseIntegerOption(options.limit, "--limit");
|
|
419
349
|
if (limit !== undefined)
|
|
420
350
|
args.limit = limit;
|
|
421
|
-
const offset = parseIntegerOption(
|
|
351
|
+
const offset = parseIntegerOption(options.offset, "--offset");
|
|
422
352
|
if (offset !== undefined)
|
|
423
353
|
args.offset = offset;
|
|
424
|
-
if (
|
|
425
|
-
args.source =
|
|
354
|
+
if (options.source)
|
|
355
|
+
args.source = options.source;
|
|
426
356
|
await callAndPrint("list_memories", args, format);
|
|
427
357
|
}
|
|
428
|
-
async function cmdUpdate(
|
|
429
|
-
const
|
|
430
|
-
|
|
431
|
-
options: {
|
|
432
|
-
content: { type: "string" },
|
|
433
|
-
"content-file": { type: "string" },
|
|
434
|
-
title: { type: "string" },
|
|
435
|
-
"source-context": { type: "string" },
|
|
436
|
-
"edits-json": { type: "string" },
|
|
437
|
-
"edits-file": { type: "string" },
|
|
438
|
-
"base-revision": { type: "string" },
|
|
439
|
-
output: outputOption,
|
|
440
|
-
},
|
|
441
|
-
allowPositionals: true,
|
|
442
|
-
});
|
|
443
|
-
const format = parseOutputFormat(values.output);
|
|
444
|
-
requirePositionals(positionals, 1, "update");
|
|
445
|
-
if (values.content && values["content-file"]) {
|
|
358
|
+
async function cmdUpdate(id, options) {
|
|
359
|
+
const format = parseOutputFormat(options.output);
|
|
360
|
+
if (options.content && options.contentFile) {
|
|
446
361
|
throw new Error("update: use either --content or --content-file, not both");
|
|
447
362
|
}
|
|
448
|
-
if (
|
|
363
|
+
if (options.editsJson && options.editsFile) {
|
|
449
364
|
throw new Error("update: use either --edits-json or --edits-file, not both");
|
|
450
365
|
}
|
|
451
|
-
if ((
|
|
366
|
+
if ((options.content || options.contentFile) && (options.editsJson || options.editsFile)) {
|
|
452
367
|
throw new Error("update: content replacement and block edits are mutually exclusive");
|
|
453
368
|
}
|
|
454
|
-
const args = { memoryId:
|
|
455
|
-
if (
|
|
456
|
-
args.content =
|
|
457
|
-
if (
|
|
458
|
-
args.content = await readTextFile(
|
|
459
|
-
if (
|
|
460
|
-
args.title =
|
|
461
|
-
if (
|
|
462
|
-
args.sourceContext =
|
|
463
|
-
if (
|
|
464
|
-
const raw =
|
|
465
|
-
args.edits = parseJSONOption(raw,
|
|
466
|
-
const baseRevision = parseIntegerOption(
|
|
369
|
+
const args = { memoryId: id };
|
|
370
|
+
if (options.content)
|
|
371
|
+
args.content = options.content;
|
|
372
|
+
if (options.contentFile)
|
|
373
|
+
args.content = await readTextFile(options.contentFile, "--content-file");
|
|
374
|
+
if (options.title !== undefined)
|
|
375
|
+
args.title = options.title;
|
|
376
|
+
if (options.sourceContext !== undefined)
|
|
377
|
+
args.sourceContext = options.sourceContext;
|
|
378
|
+
if (options.editsJson || options.editsFile) {
|
|
379
|
+
const raw = options.editsJson ?? (await readTextFile(options.editsFile, "--edits-file"));
|
|
380
|
+
args.edits = parseJSONOption(raw, options.editsJson ? "--edits-json" : "--edits-file");
|
|
381
|
+
const baseRevision = parseIntegerOption(options.baseRevision, "--base-revision");
|
|
467
382
|
if (baseRevision === undefined) {
|
|
468
383
|
throw new Error("update: --base-revision is required with block edits");
|
|
469
384
|
}
|
|
470
385
|
args.baseRevision = baseRevision;
|
|
471
386
|
}
|
|
472
387
|
else {
|
|
473
|
-
const baseRevision = parseIntegerOption(
|
|
388
|
+
const baseRevision = parseIntegerOption(options.baseRevision, "--base-revision");
|
|
474
389
|
if (baseRevision !== undefined)
|
|
475
390
|
args.baseRevision = baseRevision;
|
|
476
391
|
}
|
|
477
392
|
await callAndPrint("update_memory", args, format);
|
|
478
393
|
}
|
|
479
|
-
async function cmdPublish(
|
|
480
|
-
const
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
},
|
|
487
|
-
allowPositionals: true,
|
|
488
|
-
});
|
|
489
|
-
const format = parseOutputFormat(values.output);
|
|
490
|
-
requirePositionals(positionals, 1, "publish");
|
|
491
|
-
const args = { memoryId: positionals[0] };
|
|
492
|
-
if (values.title !== undefined)
|
|
493
|
-
args.title = values.title;
|
|
494
|
-
if (values["privacy-mode"] !== undefined)
|
|
495
|
-
args.privacyMode = values["privacy-mode"];
|
|
394
|
+
async function cmdPublish(id, options) {
|
|
395
|
+
const format = parseOutputFormat(options.output);
|
|
396
|
+
const args = { memoryId: id };
|
|
397
|
+
if (options.title !== undefined)
|
|
398
|
+
args.title = options.title;
|
|
399
|
+
if (options.privacyMode !== undefined)
|
|
400
|
+
args.privacyMode = options.privacyMode;
|
|
496
401
|
await callAndPrint("publish_memory", args, format);
|
|
497
402
|
}
|
|
498
|
-
async function cmdUnpublish(
|
|
499
|
-
const
|
|
500
|
-
|
|
501
|
-
options: {
|
|
502
|
-
"memory-id": { type: "string" },
|
|
503
|
-
"share-id": { type: "string" },
|
|
504
|
-
output: outputOption,
|
|
505
|
-
},
|
|
506
|
-
allowPositionals: true,
|
|
507
|
-
});
|
|
508
|
-
const format = parseOutputFormat(values.output);
|
|
509
|
-
const provided = [values["memory-id"], values["share-id"], positionals[0]].filter(Boolean);
|
|
403
|
+
async function cmdUnpublish(id, options) {
|
|
404
|
+
const format = parseOutputFormat(options.output);
|
|
405
|
+
const provided = [options.memoryId, options.shareId, id].filter(Boolean);
|
|
510
406
|
if (provided.length !== 1) {
|
|
511
407
|
throw new Error("unpublish: provide exactly one of --memory-id, --share-id, or positional id");
|
|
512
408
|
}
|
|
513
409
|
const args = {};
|
|
514
|
-
if (
|
|
515
|
-
args.memoryId =
|
|
410
|
+
if (options.memoryId) {
|
|
411
|
+
args.memoryId = options.memoryId;
|
|
516
412
|
}
|
|
517
|
-
else if (
|
|
518
|
-
args.shareId =
|
|
413
|
+
else if (options.shareId) {
|
|
414
|
+
args.shareId = options.shareId;
|
|
519
415
|
}
|
|
520
416
|
else {
|
|
521
|
-
args.memoryId =
|
|
417
|
+
args.memoryId = id;
|
|
522
418
|
}
|
|
523
419
|
await callAndPrint("unpublish_memory", args, format);
|
|
524
420
|
}
|
|
525
|
-
async function cmdSubjects(
|
|
526
|
-
const
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
allowPositionals: true,
|
|
530
|
-
});
|
|
531
|
-
const format = parseOutputFormat(values.output);
|
|
532
|
-
requirePositionals(positionals, 1, "subjects");
|
|
533
|
-
const args = { query: positionals.join(" ") };
|
|
534
|
-
const topK = parseIntegerOption(values["top-k"], "--top-k");
|
|
421
|
+
async function cmdSubjects(query, options) {
|
|
422
|
+
const format = parseOutputFormat(options.output);
|
|
423
|
+
const args = { query: query.join(" ") };
|
|
424
|
+
const topK = parseIntegerOption(options.topK, "--top-k");
|
|
535
425
|
if (topK !== undefined)
|
|
536
426
|
args.topK = topK;
|
|
537
427
|
await callAndPrint("search_subjects", args, format);
|
|
538
428
|
}
|
|
539
|
-
async function cmdMemories(
|
|
540
|
-
const
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
});
|
|
545
|
-
const format = parseOutputFormat(values.output);
|
|
546
|
-
requirePositionals(positionals, 1, "memories");
|
|
547
|
-
const args = { subjectIds: positionals };
|
|
548
|
-
if (values.query)
|
|
549
|
-
args.query = values.query;
|
|
429
|
+
async function cmdMemories(subjectIds, options) {
|
|
430
|
+
const format = parseOutputFormat(options.output);
|
|
431
|
+
const args = { subjectIds };
|
|
432
|
+
if (options.query)
|
|
433
|
+
args.query = options.query;
|
|
550
434
|
await callAndPrint("search_memories_in_subjects", args, format);
|
|
551
435
|
}
|
|
552
|
-
async function cmdNetwork(
|
|
553
|
-
const
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
allowPositionals: true,
|
|
557
|
-
});
|
|
558
|
-
const format = parseOutputFormat(values.output);
|
|
559
|
-
requirePositionals(positionals, 1, "network");
|
|
560
|
-
const args = { pairId: positionals[0] };
|
|
561
|
-
const limit = parseIntegerOption(values.limit, "--limit");
|
|
436
|
+
async function cmdNetwork(pairId, options) {
|
|
437
|
+
const format = parseOutputFormat(options.output);
|
|
438
|
+
const args = { pairId };
|
|
439
|
+
const limit = parseIntegerOption(options.limit, "--limit");
|
|
562
440
|
if (limit !== undefined)
|
|
563
441
|
args.limit = limit;
|
|
564
442
|
await callAndPrint("get_memory_network", args, format);
|
|
565
443
|
}
|
|
566
|
-
async function
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
444
|
+
async function cmdFriends(options) {
|
|
445
|
+
await callAndPrint("list_friends", {}, parseOutputFormat(options.output));
|
|
446
|
+
}
|
|
447
|
+
async function cmdKnowledgeGraphs(options) {
|
|
448
|
+
await callAndPrint("list_knowledge_graphs", {}, parseOutputFormat(options.output));
|
|
449
|
+
}
|
|
450
|
+
async function cmdMyMemories(options) {
|
|
451
|
+
const args = {};
|
|
452
|
+
const limit = parseIntegerOption(options.limit, "--limit");
|
|
453
|
+
if (limit !== undefined)
|
|
454
|
+
args.limit = limit;
|
|
455
|
+
const offset = parseIntegerOption(options.offset, "--offset");
|
|
456
|
+
if (offset !== undefined)
|
|
457
|
+
args.offset = offset;
|
|
458
|
+
if (options.source)
|
|
459
|
+
args.source = options.source;
|
|
460
|
+
await callAndPrint("list_my_memories", args, parseOutputFormat(options.output));
|
|
461
|
+
}
|
|
462
|
+
async function cmdSubjectEdges(subjectId, options) {
|
|
463
|
+
const args = { subjectId };
|
|
464
|
+
if (options.kg)
|
|
465
|
+
args.kg = options.kg;
|
|
466
|
+
const limit = parseIntegerOption(options.limit, "--limit");
|
|
467
|
+
if (limit !== undefined)
|
|
468
|
+
args.limit = limit;
|
|
469
|
+
const minWeight = parseNumberOption(options.minWeight, "--min-weight");
|
|
470
|
+
if (minWeight !== undefined)
|
|
471
|
+
args.minWeight = minWeight;
|
|
472
|
+
await callAndPrint("get_subject_edges", args, parseOutputFormat(options.output));
|
|
473
|
+
}
|
|
474
|
+
async function cmdGraphSharing(options) {
|
|
475
|
+
if (!!options.enable === !!options.disable) {
|
|
476
|
+
throw new Error("sharing: provide exactly one of --enable or --disable");
|
|
477
|
+
}
|
|
478
|
+
const args = {
|
|
479
|
+
publicSubscriptionsEnabled: !!options.enable,
|
|
480
|
+
};
|
|
481
|
+
if (options.title !== undefined)
|
|
482
|
+
args.title = options.title;
|
|
483
|
+
if (options.description !== undefined)
|
|
484
|
+
args.description = options.description;
|
|
485
|
+
await callAndPrint("set_knowledge_graph_sharing", args, parseOutputFormat(options.output));
|
|
486
|
+
}
|
|
487
|
+
async function cmdDelete(memoryId, options) {
|
|
488
|
+
if (!options.confirm) {
|
|
489
|
+
throw new Error("delete: pass --confirm to permanently delete this memory");
|
|
490
|
+
}
|
|
491
|
+
const args = { memoryId, confirm: true };
|
|
492
|
+
if (options.kg)
|
|
493
|
+
args.kg = options.kg;
|
|
494
|
+
await callAndPrint("delete_memory", args, parseOutputFormat(options.output));
|
|
495
|
+
}
|
|
496
|
+
async function cmdStatus(options) {
|
|
497
|
+
const format = parseOutputFormat(options.output);
|
|
573
498
|
const [{ key, source }, stored] = await Promise.all([resolveApiKey(), readStoredAuth()]);
|
|
574
499
|
const report = {
|
|
575
500
|
package: packageName,
|
|
@@ -633,20 +558,15 @@ async function cmdStatus(rest) {
|
|
|
633
558
|
lines.push(`connect: ok`, `tools: unavailable (tools/list failed: ${report.toolsError})`);
|
|
634
559
|
}
|
|
635
560
|
else if (report.connect && !report.connect.ok) {
|
|
636
|
-
lines.push(`connect: FAILED
|
|
561
|
+
lines.push(`connect: FAILED - ${report.connect.error}`);
|
|
637
562
|
}
|
|
638
563
|
if (report.agent?.claimURL) {
|
|
639
564
|
lines.push(`agent: unclaimed (${report.agent.caller || "agent"})`, `claim: ${report.agent.claimURL}`);
|
|
640
565
|
}
|
|
641
566
|
process.stdout.write(`${lines.join("\n")}\n`);
|
|
642
567
|
}
|
|
643
|
-
function cmdConfig(
|
|
644
|
-
|
|
645
|
-
args: rest,
|
|
646
|
-
options: { output: outputOption },
|
|
647
|
-
allowPositionals: true,
|
|
648
|
-
});
|
|
649
|
-
parseOutputFormat(values.output); // accepted; output is always JSON
|
|
568
|
+
function cmdConfig(options) {
|
|
569
|
+
parseOutputFormat(options.output); // accepted; output is always JSON
|
|
650
570
|
const config = {
|
|
651
571
|
mcpServers: {
|
|
652
572
|
ditto: {
|
|
@@ -658,141 +578,296 @@ function cmdConfig(rest) {
|
|
|
658
578
|
};
|
|
659
579
|
process.stdout.write(`${JSON.stringify(config, null, 2)}\n`);
|
|
660
580
|
}
|
|
661
|
-
//
|
|
662
|
-
//
|
|
663
|
-
//
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
581
|
+
// These commands mirror the MCP subscription tools. Subscriptions only ever
|
|
582
|
+
// cover other users' public graphs by @username; this cannot touch the account's
|
|
583
|
+
// own graph or app graph, since those are not subscriptions.
|
|
584
|
+
async function cmdGraphsCreate(nameParts, options) {
|
|
585
|
+
await callAndPrint("create_dedicated_graph", { name: nameParts.join(" ") }, parseOutputFormat(options.output));
|
|
586
|
+
}
|
|
587
|
+
async function cmdGraphsList(options) {
|
|
588
|
+
await callAndPrint("list_knowledge_graph_subscriptions", {}, parseOutputFormat(options.output));
|
|
589
|
+
}
|
|
590
|
+
async function cmdGraphsSubscribers(options) {
|
|
591
|
+
await callAndPrint("list_knowledge_graph_subscribers", {}, parseOutputFormat(options.output));
|
|
592
|
+
}
|
|
593
|
+
async function cmdGraphsAdd(username, options) {
|
|
594
|
+
await callAndPrint("subscribe_knowledge_graph", { username }, parseOutputFormat(options.output));
|
|
595
|
+
}
|
|
596
|
+
async function cmdGraphsRemove(username, options) {
|
|
597
|
+
await callAndPrint("unsubscribe_knowledge_graph", { username }, parseOutputFormat(options.output));
|
|
598
|
+
}
|
|
599
|
+
function addExamples(command, examples) {
|
|
600
|
+
return command.addHelpText("after", `\nExamples:\n${examples}`);
|
|
601
|
+
}
|
|
602
|
+
function buildProgram() {
|
|
603
|
+
const program = new Command();
|
|
604
|
+
program
|
|
605
|
+
.name("heyditto")
|
|
606
|
+
.description("Save, search, fetch, and traverse Ditto memories from the shell.")
|
|
607
|
+
.version(packageVersion, "-v, --version", "print the CLI version")
|
|
608
|
+
.helpCommand("help [command]", "show help for a command")
|
|
609
|
+
.showHelpAfterError()
|
|
610
|
+
.addHelpText("after", `
|
|
611
|
+
Notes:
|
|
612
|
+
On macOS, Apple ships /usr/bin/ditto (a file-copy utility). If 'ditto'
|
|
613
|
+
runs the wrong tool, install with 'npm i -g @heyditto/cli' and invoke as
|
|
614
|
+
'heyditto' (alias bin), or check 'type -a ditto' to disambiguate.
|
|
615
|
+
|
|
616
|
+
Environment:
|
|
617
|
+
DITTO_API_KEY Optional override, taking precedence over the saved key.
|
|
618
|
+
DITTO_API_BASE Optional API base URL. Defaults to https://api.heyditto.ai.
|
|
619
|
+
DITTO_CONFIG_DIR Optional config directory. Defaults to $XDG_CONFIG_HOME/heyditto/cli
|
|
620
|
+
or ~/.config/heyditto/cli.
|
|
621
|
+
`);
|
|
622
|
+
addExamples(program
|
|
623
|
+
.command("save")
|
|
624
|
+
.description("save a memory")
|
|
625
|
+
.summary("save a memory")
|
|
626
|
+
.argument("<content...>", "memory content")
|
|
627
|
+
.option("--source <source>", "memory source", "cli")
|
|
628
|
+
.option("--source-context <context>", "source context, such as a filename")
|
|
629
|
+
.addOption(outputOption())
|
|
630
|
+
.action(cmdSave), ` heyditto save "Project X uses Bun + SolidJS"
|
|
631
|
+
heyditto save "$(cat note.md)" --source document --source-context note.md`);
|
|
632
|
+
addExamples(program
|
|
633
|
+
.command("search")
|
|
634
|
+
.description("search private memories, optionally public graphs")
|
|
635
|
+
.summary("search private memories, optionally public graphs")
|
|
636
|
+
.argument("<query...>", "one or more search queries")
|
|
637
|
+
.option("--include-public", "include public DittoHub memories")
|
|
638
|
+
.option("--filter-username <username>", "scope public results to a username")
|
|
639
|
+
.addOption(outputOption())
|
|
640
|
+
.action(cmdSearch), ` heyditto search "typescript preferences"
|
|
641
|
+
heyditto search "launch notes" --include-public --filter-username peyton`);
|
|
642
|
+
program
|
|
643
|
+
.command("fetch")
|
|
644
|
+
.description("fetch memories by id")
|
|
645
|
+
.summary("fetch memories by id")
|
|
646
|
+
.argument("<id...>", "memory ids or public share ids")
|
|
647
|
+
.addOption(memoryFormatOption())
|
|
648
|
+
.addOption(outputOption())
|
|
649
|
+
.action(cmdFetch);
|
|
650
|
+
program
|
|
651
|
+
.command("list")
|
|
652
|
+
.description("list memories or public publishes")
|
|
653
|
+
.summary("list memories or public publishes")
|
|
654
|
+
.option("--username <username>", "list public DittoHub publishes for a username")
|
|
655
|
+
.option("--limit <number>", "maximum number of results")
|
|
656
|
+
.option("--offset <number>", "result offset")
|
|
657
|
+
.option("--source <source>", "filter by memory source")
|
|
658
|
+
.addOption(outputOption())
|
|
659
|
+
.action(cmdList);
|
|
660
|
+
program
|
|
661
|
+
.command("my-memories")
|
|
662
|
+
.alias("list_my_memories")
|
|
663
|
+
.description("list only your saved memories")
|
|
664
|
+
.summary("list only your saved memories")
|
|
665
|
+
.option("--limit <number>", "maximum number of results")
|
|
666
|
+
.option("--offset <number>", "result offset")
|
|
667
|
+
.option("--source <source>", "filter by memory source")
|
|
668
|
+
.addOption(outputOption())
|
|
669
|
+
.action(cmdMyMemories);
|
|
670
|
+
program
|
|
671
|
+
.command("update")
|
|
672
|
+
.description("update a saved memory")
|
|
673
|
+
.summary("update a saved memory")
|
|
674
|
+
.argument("<id>", "memory id")
|
|
675
|
+
.option("--content <text>", "replacement memory content")
|
|
676
|
+
.option("--content-file <path>", "path to replacement memory content")
|
|
677
|
+
.option("--title <title>", "memory title")
|
|
678
|
+
.option("--source-context <context>", "source context")
|
|
679
|
+
.option("--edits-json <json>", "structured block edits as JSON")
|
|
680
|
+
.option("--edits-file <path>", "path to structured block edits JSON")
|
|
681
|
+
.option("--base-revision <number>", "base memory revision")
|
|
682
|
+
.addOption(outputOption())
|
|
683
|
+
.addHelpText("after", `
|
|
684
|
+
Examples:
|
|
685
|
+
heyditto update <memory-id> --content-file revised.md --output json
|
|
686
|
+
heyditto update <memory-id> --edits-file edits.json --base-revision 3 --output json`)
|
|
687
|
+
.action(cmdUpdate);
|
|
688
|
+
program
|
|
689
|
+
.command("publish")
|
|
690
|
+
.description("publish a memory to DittoHub")
|
|
691
|
+
.summary("publish a memory to DittoHub")
|
|
692
|
+
.argument("<id>", "memory id")
|
|
693
|
+
.option("--title <title>", "public title")
|
|
694
|
+
.option("--privacy-mode <mode>", "privacy mode: scan_and_block, scan_and_warn, or scan_and_redact")
|
|
695
|
+
.addOption(outputOption())
|
|
696
|
+
.action(cmdPublish);
|
|
697
|
+
program
|
|
698
|
+
.command("unpublish")
|
|
699
|
+
.description("remove an existing public share")
|
|
700
|
+
.summary("remove an existing public share")
|
|
701
|
+
.argument("[id]", "memory id")
|
|
702
|
+
.option("--memory-id <id>", "memory id")
|
|
703
|
+
.option("--share-id <id>", "share id")
|
|
704
|
+
.addOption(outputOption())
|
|
705
|
+
.action(cmdUnpublish);
|
|
706
|
+
program
|
|
707
|
+
.command("delete")
|
|
708
|
+
.alias("delete_memory")
|
|
709
|
+
.description("permanently delete a saved memory")
|
|
710
|
+
.summary("permanently delete a saved memory")
|
|
711
|
+
.argument("<memory-id>", "memory id")
|
|
712
|
+
.requiredOption("--confirm", "confirm permanent deletion")
|
|
713
|
+
.option("--kg <alias>", "knowledge graph alias")
|
|
714
|
+
.addOption(outputOption())
|
|
715
|
+
.action(cmdDelete);
|
|
716
|
+
program
|
|
717
|
+
.command("subjects")
|
|
718
|
+
.description("search the subject graph")
|
|
719
|
+
.summary("search the subject graph")
|
|
720
|
+
.argument("<query...>", "subject search query")
|
|
721
|
+
.option("--top-k <number>", "maximum number of subjects")
|
|
722
|
+
.addOption(outputOption())
|
|
723
|
+
.action(cmdSubjects);
|
|
724
|
+
program
|
|
725
|
+
.command("subject-edges")
|
|
726
|
+
.alias("get_subject_edges")
|
|
727
|
+
.description("list related subjects for a subject")
|
|
728
|
+
.summary("list related subjects for a subject")
|
|
729
|
+
.argument("<subject-id>", "subject id")
|
|
730
|
+
.option("--kg <alias>", "knowledge graph alias")
|
|
731
|
+
.option("--limit <number>", "maximum number of related subjects")
|
|
732
|
+
.option("--min-weight <number>", "minimum edge weight from 0 to 1")
|
|
733
|
+
.addOption(outputOption())
|
|
734
|
+
.action(cmdSubjectEdges);
|
|
735
|
+
program
|
|
736
|
+
.command("memories")
|
|
737
|
+
.description("fetch memory previews for subjects")
|
|
738
|
+
.summary("fetch memory previews for subjects")
|
|
739
|
+
.argument("<subject-id...>", "subject ids")
|
|
740
|
+
.option("--query <query>", "optional search query")
|
|
741
|
+
.addOption(outputOption())
|
|
742
|
+
.action(cmdMemories);
|
|
743
|
+
program
|
|
744
|
+
.command("network")
|
|
745
|
+
.description("traverse related memories")
|
|
746
|
+
.summary("traverse related memories")
|
|
747
|
+
.argument("<pair-id>", "memory pair id")
|
|
748
|
+
.option("--limit <number>", "maximum number of related memories")
|
|
749
|
+
.addOption(outputOption())
|
|
750
|
+
.action(cmdNetwork);
|
|
751
|
+
program
|
|
752
|
+
.command("friends")
|
|
753
|
+
.alias("list_friends")
|
|
754
|
+
.description("list Ditto friends")
|
|
755
|
+
.summary("list Ditto friends")
|
|
756
|
+
.addOption(outputOption())
|
|
757
|
+
.action(cmdFriends);
|
|
758
|
+
program
|
|
759
|
+
.command("knowledge-graphs")
|
|
760
|
+
.alias("list_knowledge_graphs")
|
|
761
|
+
.description("list readable knowledge graphs")
|
|
762
|
+
.summary("list readable knowledge graphs")
|
|
763
|
+
.addOption(outputOption())
|
|
764
|
+
.action(cmdKnowledgeGraphs);
|
|
765
|
+
program
|
|
766
|
+
.command("graph-sharing")
|
|
767
|
+
.alias("set_knowledge_graph_sharing")
|
|
768
|
+
.description("configure whether others can subscribe to your graph")
|
|
769
|
+
.summary("configure graph sharing")
|
|
770
|
+
.option("--enable", "allow public subscriptions to your graph")
|
|
771
|
+
.option("--disable", "disable public subscriptions to your graph")
|
|
772
|
+
.option("--title <title>", "subscribable graph title")
|
|
773
|
+
.option("--description <description>", "subscribable graph description")
|
|
774
|
+
.addOption(outputOption())
|
|
775
|
+
.action(cmdGraphSharing);
|
|
776
|
+
const graphs = program
|
|
777
|
+
.command("graphs")
|
|
778
|
+
.description("manage knowledge graph subscriptions")
|
|
779
|
+
.summary("manage knowledge graph subscriptions")
|
|
780
|
+
.showHelpAfterError()
|
|
781
|
+
.addHelpText("after", `
|
|
782
|
+
Subscriptions cover other users' public graphs by @username. They do not modify
|
|
783
|
+
your own graph or an app graph.`);
|
|
784
|
+
graphs
|
|
785
|
+
.command("create")
|
|
786
|
+
.description("create a dedicated graph you own")
|
|
787
|
+
.argument("<name...>", "graph name")
|
|
788
|
+
.addOption(outputOption())
|
|
789
|
+
.action(cmdGraphsCreate);
|
|
790
|
+
graphs
|
|
791
|
+
.command("list")
|
|
792
|
+
.description("list public graphs you're subscribed to")
|
|
793
|
+
.addOption(outputOption())
|
|
794
|
+
.action(cmdGraphsList);
|
|
795
|
+
graphs
|
|
796
|
+
.command("available")
|
|
797
|
+
.alias("list_knowledge_graphs")
|
|
798
|
+
.description("list readable knowledge graphs")
|
|
799
|
+
.addOption(outputOption())
|
|
800
|
+
.action(cmdKnowledgeGraphs);
|
|
801
|
+
graphs
|
|
802
|
+
.command("add")
|
|
803
|
+
.description("subscribe to a public graph")
|
|
804
|
+
.argument("<username>", "public graph username, with or without @")
|
|
805
|
+
.addOption(outputOption())
|
|
806
|
+
.action(cmdGraphsAdd);
|
|
807
|
+
graphs
|
|
808
|
+
.command("remove")
|
|
809
|
+
.description("unsubscribe from a public graph")
|
|
810
|
+
.argument("<username>", "public graph username, with or without @")
|
|
811
|
+
.addOption(outputOption())
|
|
812
|
+
.action(cmdGraphsRemove);
|
|
813
|
+
graphs
|
|
814
|
+
.command("subscribers")
|
|
815
|
+
.description("list who is subscribed to your graph")
|
|
816
|
+
.addOption(outputOption())
|
|
817
|
+
.action(cmdGraphsSubscribers);
|
|
818
|
+
graphs
|
|
819
|
+
.command("sharing")
|
|
820
|
+
.alias("set_knowledge_graph_sharing")
|
|
821
|
+
.description("configure whether others can subscribe to your graph")
|
|
822
|
+
.option("--enable", "allow public subscriptions to your graph")
|
|
823
|
+
.option("--disable", "disable public subscriptions to your graph")
|
|
824
|
+
.option("--title <title>", "subscribable graph title")
|
|
825
|
+
.option("--description <description>", "subscribable graph description")
|
|
826
|
+
.addOption(outputOption())
|
|
827
|
+
.action(cmdGraphSharing);
|
|
828
|
+
program
|
|
829
|
+
.command("init")
|
|
830
|
+
.description("initialize a claimable agent account")
|
|
831
|
+
.argument("[graph...]", "public graphs to subscribe to")
|
|
832
|
+
.option("--agent", "create a free, claimable agent account")
|
|
833
|
+
.option("--agent-caller <name>", "agent name")
|
|
834
|
+
.option("--subscribe <graph>", "public graph to subscribe to", (value, previous) => [...previous, value], [])
|
|
835
|
+
.option("--json", "print machine-readable output")
|
|
836
|
+
.addOption(hiddenOutputOption())
|
|
837
|
+
.action(cmdInit);
|
|
838
|
+
program
|
|
839
|
+
.command("login")
|
|
840
|
+
.description("save an API key")
|
|
841
|
+
.argument("[key]", "Ditto API key")
|
|
842
|
+
.option("--paste", "open the key creation page before prompting")
|
|
843
|
+
.option("--stdin", "read the API key from stdin")
|
|
844
|
+
.addOption(hiddenOutputOption())
|
|
845
|
+
.action(cmdLogin);
|
|
846
|
+
program
|
|
847
|
+
.command("logout")
|
|
848
|
+
.description("delete the saved API key")
|
|
849
|
+
.addOption(hiddenOutputOption())
|
|
850
|
+
.action(cmdLogout);
|
|
851
|
+
program
|
|
852
|
+
.command("status")
|
|
853
|
+
.description("show CLI auth and endpoint status")
|
|
854
|
+
.addOption(outputOption())
|
|
855
|
+
.action(cmdStatus);
|
|
856
|
+
program
|
|
857
|
+
.command("config")
|
|
858
|
+
.description("print MCP client configuration")
|
|
859
|
+
.addOption(hiddenOutputOption())
|
|
860
|
+
.action(cmdConfig);
|
|
861
|
+
return program;
|
|
728
862
|
}
|
|
729
863
|
async function main() {
|
|
730
|
-
const argv = process.argv
|
|
731
|
-
const
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
await cmdInit(rest);
|
|
736
|
-
return;
|
|
737
|
-
case "save":
|
|
738
|
-
await cmdSave(rest);
|
|
739
|
-
return;
|
|
740
|
-
case "search":
|
|
741
|
-
await cmdSearch(rest);
|
|
742
|
-
return;
|
|
743
|
-
case "fetch":
|
|
744
|
-
await cmdFetch(rest);
|
|
745
|
-
return;
|
|
746
|
-
case "list":
|
|
747
|
-
await cmdList(rest);
|
|
748
|
-
return;
|
|
749
|
-
case "update":
|
|
750
|
-
await cmdUpdate(rest);
|
|
751
|
-
return;
|
|
752
|
-
case "publish":
|
|
753
|
-
await cmdPublish(rest);
|
|
754
|
-
return;
|
|
755
|
-
case "unpublish":
|
|
756
|
-
await cmdUnpublish(rest);
|
|
757
|
-
return;
|
|
758
|
-
case "subjects":
|
|
759
|
-
await cmdSubjects(rest);
|
|
760
|
-
return;
|
|
761
|
-
case "memories":
|
|
762
|
-
await cmdMemories(rest);
|
|
763
|
-
return;
|
|
764
|
-
case "network":
|
|
765
|
-
await cmdNetwork(rest);
|
|
766
|
-
return;
|
|
767
|
-
case "graphs":
|
|
768
|
-
await cmdGraphs(rest);
|
|
769
|
-
return;
|
|
770
|
-
case "login":
|
|
771
|
-
await cmdLogin(rest);
|
|
772
|
-
return;
|
|
773
|
-
case "logout":
|
|
774
|
-
await cmdLogout(rest);
|
|
775
|
-
return;
|
|
776
|
-
case "status":
|
|
777
|
-
await cmdStatus(rest);
|
|
778
|
-
return;
|
|
779
|
-
case "config":
|
|
780
|
-
cmdConfig(rest);
|
|
781
|
-
return;
|
|
782
|
-
case undefined:
|
|
783
|
-
case "help":
|
|
784
|
-
case "--help":
|
|
785
|
-
case "-h":
|
|
786
|
-
process.stdout.write(usage());
|
|
787
|
-
return;
|
|
788
|
-
case "--version":
|
|
789
|
-
case "-v":
|
|
790
|
-
process.stdout.write(`${packageVersion}\n`);
|
|
791
|
-
return;
|
|
792
|
-
default:
|
|
793
|
-
process.stderr.write(`Unknown command: ${command}\n\n${usage()}`);
|
|
794
|
-
process.exitCode = 2;
|
|
864
|
+
const argv = [...process.argv];
|
|
865
|
+
const args = argv.slice(2);
|
|
866
|
+
if (args[0] === "graphs" &&
|
|
867
|
+
(args.length === 1 || (args[1].startsWith("-") && args[1] !== "-h" && args[1] !== "--help"))) {
|
|
868
|
+
argv.splice(3, 0, "list");
|
|
795
869
|
}
|
|
870
|
+
await buildProgram().parseAsync(argv);
|
|
796
871
|
}
|
|
797
872
|
main().catch((error) => {
|
|
798
873
|
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|