@great-arrow/cli 0.7.0 → 0.7.2
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 +6 -0
- package/dist/index.js +83 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -80,6 +80,12 @@ gad memory delete <id>
|
|
|
80
80
|
cat notes.md | gad memory create --title "Meeting notes"
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
+
`gad memory search` shows a **Source** column for every hit: the original
|
|
84
|
+
document's link (GitHub, Notion, Drive…) when there is one, otherwise the
|
|
85
|
+
memory's page in the web app. `gad ask` prints a numbered **Sources** list of
|
|
86
|
+
the memories its answer was built from, under the answer (`--quiet` hides it;
|
|
87
|
+
`--json` keeps the raw `hits`).
|
|
88
|
+
|
|
83
89
|
### Workspace
|
|
84
90
|
|
|
85
91
|
```bash
|
package/dist/index.js
CHANGED
|
@@ -9483,7 +9483,7 @@ function isNodeError(value) {
|
|
|
9483
9483
|
|
|
9484
9484
|
// src/lib/version.ts
|
|
9485
9485
|
var CLI_PACKAGE_NAME = "@great-arrow/cli";
|
|
9486
|
-
var CLI_VERSION = "0.7.
|
|
9486
|
+
var CLI_VERSION = "0.7.2";
|
|
9487
9487
|
var GAD_INSTALL_VERSION = "2026.08.08";
|
|
9488
9488
|
var GAD_INSTALL_MIN_VERSION = "2026.06.22";
|
|
9489
9489
|
var GAD_INSTALL_HEADER = "X-GAD-Install-Version";
|
|
@@ -10455,7 +10455,7 @@ var Formatter = class {
|
|
|
10455
10455
|
}
|
|
10456
10456
|
if (this.options.quiet) {
|
|
10457
10457
|
const lines = data.map(
|
|
10458
|
-
(row) => columns.map((col) => this.
|
|
10458
|
+
(row) => columns.map((col) => this.tableCell(row, col)).join(" ")
|
|
10459
10459
|
);
|
|
10460
10460
|
const output3 = lines.join("\n");
|
|
10461
10461
|
this.writeStdout(output3);
|
|
@@ -10465,7 +10465,7 @@ var Formatter = class {
|
|
|
10465
10465
|
if (col.width) return col.width;
|
|
10466
10466
|
const headerLen = col.header.length;
|
|
10467
10467
|
const maxDataLen = data.reduce((max, row) => {
|
|
10468
|
-
const val = this.
|
|
10468
|
+
const val = this.tableCell(row, col);
|
|
10469
10469
|
return Math.max(max, val.length);
|
|
10470
10470
|
}, 0);
|
|
10471
10471
|
return Math.max(headerLen, maxDataLen);
|
|
@@ -10473,12 +10473,21 @@ var Formatter = class {
|
|
|
10473
10473
|
const headerRow = columns.map((col, i) => this.color.bold(col.header.padEnd(widths[i]))).join(" ");
|
|
10474
10474
|
const separator = widths.map((w) => "\u2500".repeat(w)).join("\u2500\u2500");
|
|
10475
10475
|
const rows = data.map(
|
|
10476
|
-
(row) => columns.map((col, i) => this.
|
|
10476
|
+
(row) => columns.map((col, i) => this.tableCell(row, col).padEnd(widths[i])).join(" ")
|
|
10477
10477
|
);
|
|
10478
10478
|
const output2 = [headerRow, separator, ...rows].join("\n");
|
|
10479
10479
|
this.writeStdout(output2);
|
|
10480
10480
|
return output2;
|
|
10481
10481
|
}
|
|
10482
|
+
/**
|
|
10483
|
+
* One table cell: always a single line (a newline in a value would split the
|
|
10484
|
+
* row and shift every column after it), cut to the column's declared width.
|
|
10485
|
+
* Columns without a width (links, ids) are never cut.
|
|
10486
|
+
*/
|
|
10487
|
+
tableCell(row, col) {
|
|
10488
|
+
const flat = this.getCellValue(row, col).replace(/[\r\n\t\v\f]+/g, " ");
|
|
10489
|
+
return col.width && flat.length > col.width ? `${flat.slice(0, col.width - 1)}\u2026` : flat;
|
|
10490
|
+
}
|
|
10482
10491
|
/**
|
|
10483
10492
|
* Render key-value pairs for a single object.
|
|
10484
10493
|
*
|
|
@@ -12198,11 +12207,56 @@ function readStdin(stream) {
|
|
|
12198
12207
|
return readStream(input2);
|
|
12199
12208
|
}
|
|
12200
12209
|
|
|
12210
|
+
// src/lib/sources.ts
|
|
12211
|
+
function nonEmpty2(value) {
|
|
12212
|
+
if (typeof value !== "string") return null;
|
|
12213
|
+
const clean = stripControlChars(value).trim();
|
|
12214
|
+
return clean === "" ? null : clean;
|
|
12215
|
+
}
|
|
12216
|
+
function httpUrl(value) {
|
|
12217
|
+
const raw = nonEmpty2(value);
|
|
12218
|
+
if (!raw) return null;
|
|
12219
|
+
try {
|
|
12220
|
+
const parsed = new URL(raw);
|
|
12221
|
+
return parsed.protocol === "https:" || parsed.protocol === "http:" ? parsed.toString() : null;
|
|
12222
|
+
} catch {
|
|
12223
|
+
return null;
|
|
12224
|
+
}
|
|
12225
|
+
}
|
|
12226
|
+
function sourceOf(hit, apiUrl) {
|
|
12227
|
+
const memoryId = nonEmpty2(hit.memoryId);
|
|
12228
|
+
const link = httpUrl(hit.url) ?? (memoryId ? `${apiUrl.replace(/\/$/, "")}/stuff/memories/${encodeURIComponent(memoryId)}` : null);
|
|
12229
|
+
const label = nonEmpty2(hit.fileName) ?? nonEmpty2(hit.memoryTitle) ?? nonEmpty2(hit.title) ?? memoryId ?? "Untitled";
|
|
12230
|
+
return { label, link };
|
|
12231
|
+
}
|
|
12232
|
+
function uniqueSources(hits, apiUrl, max = 5) {
|
|
12233
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12234
|
+
const out2 = [];
|
|
12235
|
+
for (const hit of hits) {
|
|
12236
|
+
const source = sourceOf(hit, apiUrl);
|
|
12237
|
+
const key = source.link ?? source.label;
|
|
12238
|
+
if (seen.has(key)) continue;
|
|
12239
|
+
seen.add(key);
|
|
12240
|
+
out2.push(source);
|
|
12241
|
+
if (out2.length >= max) break;
|
|
12242
|
+
}
|
|
12243
|
+
return out2;
|
|
12244
|
+
}
|
|
12245
|
+
function formatSources(sources) {
|
|
12246
|
+
if (sources.length === 0) return "";
|
|
12247
|
+
const lines = sources.map(
|
|
12248
|
+
(s2, i) => ` [${i + 1}] ${s2.label}${s2.link ? ` \u2014 ${s2.link}` : ""}`
|
|
12249
|
+
);
|
|
12250
|
+
return `Sources:
|
|
12251
|
+
${lines.join("\n")}`;
|
|
12252
|
+
}
|
|
12253
|
+
|
|
12201
12254
|
// src/commands/memory.ts
|
|
12202
12255
|
var searchColumns = [
|
|
12203
12256
|
{ key: "title", header: "Title", width: 30 },
|
|
12204
12257
|
{ key: "layer", header: "Layer", width: 12 },
|
|
12205
12258
|
{ key: "freshness", header: "Freshness", width: 10 },
|
|
12259
|
+
{ key: "source", header: "Source" },
|
|
12206
12260
|
{
|
|
12207
12261
|
key: "preview",
|
|
12208
12262
|
header: "Preview",
|
|
@@ -12298,7 +12352,12 @@ memoryCommand.command("create").description("Create a new memory in the active w
|
|
|
12298
12352
|
});
|
|
12299
12353
|
memoryCommand.command("search <query>").description("Semantic search across memories").option("--json", "Output as JSON").option("-k, --limit <number>", "Max results", "10").option("--layer <layer>", "Filter by layer").action(async (query, opts, command) => {
|
|
12300
12354
|
const g = globalOutputOpts(command);
|
|
12301
|
-
const
|
|
12355
|
+
const auth = await resolveAuth();
|
|
12356
|
+
const client2 = new GadClient({
|
|
12357
|
+
token: auth.token,
|
|
12358
|
+
getToken: auth.getToken,
|
|
12359
|
+
apiUrl: auth.apiUrl
|
|
12360
|
+
});
|
|
12302
12361
|
const args = {
|
|
12303
12362
|
query,
|
|
12304
12363
|
k: Number.parseInt(opts.limit, 10)
|
|
@@ -12312,6 +12371,7 @@ memoryCommand.command("search <query>").description("Semantic search across memo
|
|
|
12312
12371
|
const rows = rawResults.map((item) => ({
|
|
12313
12372
|
...item,
|
|
12314
12373
|
title: item.title ?? item.memoryTitle,
|
|
12374
|
+
source: sourceOf(item, auth.apiUrl).link ?? "",
|
|
12315
12375
|
preview: extractPreview(item)
|
|
12316
12376
|
}));
|
|
12317
12377
|
const fmt = createFormatter({
|
|
@@ -18293,6 +18353,17 @@ function askOutcome(data) {
|
|
|
18293
18353
|
const answer = extractAnswer(data);
|
|
18294
18354
|
return answer.trim() === "" ? { kind: "empty" } : { kind: "ok", text: answer };
|
|
18295
18355
|
}
|
|
18356
|
+
function askSources(data, apiUrl) {
|
|
18357
|
+
if (!data || typeof data !== "object") return "";
|
|
18358
|
+
const hits = data.hits;
|
|
18359
|
+
if (!Array.isArray(hits)) return "";
|
|
18360
|
+
return formatSources(
|
|
18361
|
+
uniqueSources(
|
|
18362
|
+
hits.filter((h) => typeof h === "object" && h !== null),
|
|
18363
|
+
apiUrl
|
|
18364
|
+
)
|
|
18365
|
+
);
|
|
18366
|
+
}
|
|
18296
18367
|
function askCommand() {
|
|
18297
18368
|
const cmd = new Command("ask").description("Ask the orchestrator a question").argument("<question>", "The question to ask").option("--json", "Output raw response as JSON").option("--quiet", "Suppress decorative output").option("--no-color", "Disable color output").action(async (question, options, command) => {
|
|
18298
18369
|
const g = globalOutputOpts(command);
|
|
@@ -18329,6 +18400,10 @@ function askCommand() {
|
|
|
18329
18400
|
const outcome = askOutcome(result);
|
|
18330
18401
|
if (outcome.kind === "ok") {
|
|
18331
18402
|
process.stdout.write(outcome.text + "\n");
|
|
18403
|
+
const sources = g.quiet ? "" : askSources(result, auth.apiUrl);
|
|
18404
|
+
if (sources) process.stdout.write(`
|
|
18405
|
+
${sources}
|
|
18406
|
+
`);
|
|
18332
18407
|
} else if (outcome.kind === "error") {
|
|
18333
18408
|
fmt.warn(`Orchestrator error: ${outcome.message}`);
|
|
18334
18409
|
process.exitCode = 1;
|
|
@@ -20107,7 +20182,7 @@ __export(external_exports, {
|
|
|
20107
20182
|
hash: () => hash,
|
|
20108
20183
|
hex: () => hex2,
|
|
20109
20184
|
hostname: () => hostname4,
|
|
20110
|
-
httpUrl: () =>
|
|
20185
|
+
httpUrl: () => httpUrl2,
|
|
20111
20186
|
iban: () => iban2,
|
|
20112
20187
|
includes: () => _includes,
|
|
20113
20188
|
input: () => input,
|
|
@@ -37046,7 +37121,7 @@ __export(schemas_exports2, {
|
|
|
37046
37121
|
hash: () => hash,
|
|
37047
37122
|
hex: () => hex2,
|
|
37048
37123
|
hostname: () => hostname4,
|
|
37049
|
-
httpUrl: () =>
|
|
37124
|
+
httpUrl: () => httpUrl2,
|
|
37050
37125
|
iban: () => iban2,
|
|
37051
37126
|
instanceof: () => _instanceof,
|
|
37052
37127
|
int: () => int,
|
|
@@ -37594,7 +37669,7 @@ var ZodURL = /* @__PURE__ */ $constructor("ZodURL", (inst, def) => {
|
|
|
37594
37669
|
function url(params) {
|
|
37595
37670
|
return _url(ZodURL, params);
|
|
37596
37671
|
}
|
|
37597
|
-
function
|
|
37672
|
+
function httpUrl2(params) {
|
|
37598
37673
|
return _url(ZodURL, {
|
|
37599
37674
|
protocol: httpProtocol,
|
|
37600
37675
|
hostname: domain,
|