@4ort/cli 0.4.0 → 0.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.
Files changed (85) hide show
  1. package/README.md +286 -0
  2. package/dist/commands/kg/agent-context.d.ts +3 -0
  3. package/dist/commands/kg/agent-context.js +54 -0
  4. package/dist/commands/kg/agent-context.js.map +1 -0
  5. package/dist/commands/kg/article-context.d.ts +3 -0
  6. package/dist/commands/kg/article-context.js +51 -0
  7. package/dist/commands/kg/article-context.js.map +1 -0
  8. package/dist/commands/kg/ask.d.ts +5 -0
  9. package/dist/commands/kg/ask.js +121 -0
  10. package/dist/commands/kg/ask.js.map +1 -0
  11. package/dist/commands/kg/auth.d.ts +9 -0
  12. package/dist/commands/kg/auth.js +95 -0
  13. package/dist/commands/kg/auth.js.map +1 -0
  14. package/dist/commands/kg/entity.d.ts +4 -0
  15. package/dist/commands/kg/entity.js +33 -0
  16. package/dist/commands/kg/entity.js.map +1 -0
  17. package/dist/commands/kg/match.d.ts +5 -0
  18. package/dist/commands/kg/match.js +44 -0
  19. package/dist/commands/kg/match.js.map +1 -0
  20. package/dist/commands/kg/popularity.d.ts +3 -0
  21. package/dist/commands/kg/popularity.js +42 -0
  22. package/dist/commands/kg/popularity.js.map +1 -0
  23. package/dist/commands/kg/search.d.ts +4 -0
  24. package/dist/commands/kg/search.js +34 -0
  25. package/dist/commands/kg/search.js.map +1 -0
  26. package/dist/commands/kg/trending.d.ts +6 -0
  27. package/dist/commands/kg/trending.js +35 -0
  28. package/dist/commands/kg/trending.js.map +1 -0
  29. package/dist/commands/mcp.d.ts +5 -0
  30. package/dist/commands/mcp.js +24 -0
  31. package/dist/commands/mcp.js.map +1 -0
  32. package/dist/commands/mov.d.ts +17 -0
  33. package/dist/commands/mov.js +124 -0
  34. package/dist/commands/mov.js.map +1 -0
  35. package/dist/commands/run.d.ts +10 -0
  36. package/dist/commands/run.js +74 -0
  37. package/dist/commands/run.js.map +1 -0
  38. package/dist/commands/search.d.ts +7 -0
  39. package/dist/commands/search.js +105 -0
  40. package/dist/commands/search.js.map +1 -0
  41. package/dist/commands/vault.d.ts +7 -0
  42. package/dist/commands/vault.js +62 -0
  43. package/dist/commands/vault.js.map +1 -0
  44. package/dist/commands/web.d.ts +6 -0
  45. package/dist/commands/web.js +44 -0
  46. package/dist/commands/web.js.map +1 -0
  47. package/dist/config.d.ts +38 -0
  48. package/dist/config.js +97 -1
  49. package/dist/config.js.map +1 -1
  50. package/dist/config.mov.test.d.ts +1 -0
  51. package/dist/config.mov.test.js +23 -0
  52. package/dist/config.mov.test.js.map +1 -0
  53. package/dist/index.js +195 -37
  54. package/dist/index.js.map +1 -1
  55. package/dist/kg-client.d.ts +42 -0
  56. package/dist/kg-client.js +125 -0
  57. package/dist/kg-client.js.map +1 -0
  58. package/dist/kg-output.d.ts +33 -0
  59. package/dist/kg-output.js +132 -0
  60. package/dist/kg-output.js.map +1 -0
  61. package/dist/mcp-server.d.ts +5 -0
  62. package/dist/mcp-server.js +363 -0
  63. package/dist/mcp-server.js.map +1 -0
  64. package/dist/peertube-client.d.ts +47 -0
  65. package/dist/peertube-client.js +144 -0
  66. package/dist/peertube-client.js.map +1 -0
  67. package/dist/peertube-client.test.d.ts +1 -0
  68. package/dist/peertube-client.test.js +92 -0
  69. package/dist/peertube-client.test.js.map +1 -0
  70. package/dist/web-client.d.ts +20 -0
  71. package/dist/web-client.js +335 -0
  72. package/dist/web-client.js.map +1 -0
  73. package/package.json +21 -4
  74. package/src/api-client.ts +0 -51
  75. package/src/commands/delete.ts +0 -15
  76. package/src/commands/list.ts +0 -25
  77. package/src/commands/mail.ts +0 -79
  78. package/src/commands/provision.ts +0 -106
  79. package/src/commands/push.ts +0 -63
  80. package/src/commands/recover.ts +0 -37
  81. package/src/commands/register.ts +0 -40
  82. package/src/commands/whoami.ts +0 -20
  83. package/src/config.ts +0 -40
  84. package/src/index.ts +0 -114
  85. package/tsconfig.json +0 -8
@@ -0,0 +1,33 @@
1
+ /**
2
+ * 4ort kg entity <key>
3
+ *
4
+ * GET /api/v1/entities/{key}?detail=tiny|small|medium|full
5
+ */
6
+ import { requireKgConfig } from "../../config.js";
7
+ import { kgRequest } from "../../kg-client.js";
8
+ import { printEntity, printJson } from "../../kg-output.js";
9
+ const VALID_DETAIL = ["tiny", "small", "medium", "full"];
10
+ export async function kgEntity(key, options) {
11
+ const cfg = requireKgConfig();
12
+ const detail = options.detail ?? "medium";
13
+ if (!VALID_DETAIL.includes(detail)) {
14
+ console.error(`Invalid --detail. Must be one of: ${VALID_DETAIL.join(", ")}`);
15
+ process.exit(1);
16
+ }
17
+ try {
18
+ const data = await kgRequest(cfg, `/api/v1/entities/${encodeURIComponent(key)}`, {
19
+ query: { detail },
20
+ });
21
+ if (options.json) {
22
+ printJson(data);
23
+ }
24
+ else {
25
+ printEntity(data);
26
+ }
27
+ }
28
+ catch (err) {
29
+ console.error(`✗ ${err.message}`);
30
+ process.exit(1);
31
+ }
32
+ }
33
+ //# sourceMappingURL=entity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity.js","sourceRoot":"","sources":["../../../src/commands/kg/entity.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE5D,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAU,CAAC;AAElE,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAW,EAAE,OAA4C;IACtF,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,QAAQ,CAAC;IAC1C,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAa,CAAC,EAAE,CAAC;QAC1C,OAAO,CAAC,KAAK,CAAC,qCAAqC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,SAAS,CAAM,GAAG,EAAE,oBAAoB,kBAAkB,CAAC,GAAG,CAAC,EAAE,EAAE;YACpF,KAAK,EAAE,EAAE,MAAM,EAAE;SAClB,CAAC,CAAC;QACH,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,SAAS,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;aAAM,CAAC;YACN,WAAW,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function kgMatch(text: string, options: {
2
+ limit?: string;
3
+ types?: string;
4
+ json?: boolean;
5
+ }): Promise<void>;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * 4ort kg match <text>
3
+ *
4
+ * POST /api/v1/match → ranked entity candidates with confidence scores.
5
+ */
6
+ import { requireKgConfig } from "../../config.js";
7
+ import { kgRequest } from "../../kg-client.js";
8
+ import { printJson, printTable, truncate } from "../../kg-output.js";
9
+ export async function kgMatch(text, options) {
10
+ const cfg = requireKgConfig();
11
+ const limit = options.limit ? parseInt(options.limit, 10) : 5;
12
+ const entity_types = options.types
13
+ ? options.types.split(",").map((t) => t.trim()).filter(Boolean)
14
+ : undefined;
15
+ try {
16
+ const res = await kgRequest(cfg, "/api/v1/match", {
17
+ method: "POST",
18
+ body: { text, entity_types, limit },
19
+ });
20
+ if (options.json) {
21
+ printJson(res);
22
+ return;
23
+ }
24
+ console.log(`Match for "${res.query}" (${res.latency_ms}ms)\n`);
25
+ if (res.primary) {
26
+ console.log(`✓ primary: ${res.primary.name}${res.primary.slug ? ` (${res.primary.slug})` : ""} conf=${res.primary.confidence.toFixed(2)}\n`);
27
+ }
28
+ else {
29
+ console.log("(no primary match — confidence below 0.7 threshold)\n");
30
+ }
31
+ printTable(res.candidates, [
32
+ ["NAME", (r) => r.name],
33
+ ["SLUG", (r) => r.slug || ""],
34
+ ["TYPE", (r) => r.type || ""],
35
+ ["SUMMARY", (r) => truncate(r.summary, 80)],
36
+ ["CONF", (r) => r.confidence.toFixed(2)],
37
+ ]);
38
+ }
39
+ catch (err) {
40
+ console.error(`✗ ${err.message}`);
41
+ process.exit(1);
42
+ }
43
+ }
44
+ //# sourceMappingURL=match.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.js","sourceRoot":"","sources":["../../../src/commands/kg/match.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAgBrE,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,IAAY,EACZ,OAA2D;IAE3D,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK;QAChC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;QAC/D,CAAC,CAAC,SAAS,CAAC;IAEd,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,SAAS,CAAgB,GAAG,EAAE,eAAe,EAAE;YAC/D,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE;SACpC,CAAC,CAAC;QAEH,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,SAAS,CAAC,GAAG,CAAC,CAAC;YACf,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,cAAc,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC,UAAU,OAAO,CAAC,CAAC;QACjE,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,cAAc,GAAG,CAAC,OAAO,CAAC,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,UAAU,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAChJ,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,uDAAuD,CAAC,CAAC;QACvE,CAAC;QACD,UAAU,CAAC,GAAG,CAAC,UAAU,EAAE;YACzB,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YACvB,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;YAC7B,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;YAC7B,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAC3C,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;SACzC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function kgPopularity(key: string, options: {
2
+ json?: boolean;
3
+ }): Promise<void>;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * 4ort kg popularity <key>
3
+ *
4
+ * GET /api/v1/popularity/{key} — Wikipedia-pageview-derived "real-world
5
+ * search volume" (Ahrefs / SEMrush style metric, but measured + CC0).
6
+ */
7
+ import { requireKgConfig } from "../../config.js";
8
+ import { kgRequest } from "../../kg-client.js";
9
+ import { fmtFloat, fmtInt, printJson } from "../../kg-output.js";
10
+ export async function kgPopularity(key, options) {
11
+ const cfg = requireKgConfig();
12
+ try {
13
+ const res = await kgRequest(cfg, `/api/v1/popularity/${encodeURIComponent(key)}`);
14
+ if (options.json) {
15
+ printJson(res);
16
+ return;
17
+ }
18
+ console.log(`${res.name}${res.slug ? ` (${res.slug})` : ""}`);
19
+ console.log(` monthly volume: ${fmtInt(res.monthly_volume)}`);
20
+ if (res.annual_volume !== undefined)
21
+ console.log(` annual volume: ${fmtInt(res.annual_volume)}`);
22
+ if (res.trailing_12mo_avg !== undefined)
23
+ console.log(` trailing 12mo avg: ${fmtInt(res.trailing_12mo_avg)}`);
24
+ if (res.trend_direction)
25
+ console.log(` trend: ${res.trend_direction}`);
26
+ if (res.yoy_change_pct !== undefined)
27
+ console.log(` YoY change: ${fmtFloat(res.yoy_change_pct, 1)}%`);
28
+ if (res.rank_within_domain !== undefined && res.domain_size !== undefined) {
29
+ console.log(` rank in domain: #${res.rank_within_domain} of ${fmtInt(res.domain_size)}`);
30
+ }
31
+ if (res.trend_12mo.length > 0) {
32
+ console.log(`\n 12-month trend:`);
33
+ for (const p of res.trend_12mo)
34
+ console.log(` ${p.month} ${fmtInt(p.views)}`);
35
+ }
36
+ }
37
+ catch (err) {
38
+ console.error(`✗ ${err.message}`);
39
+ process.exit(1);
40
+ }
41
+ }
42
+ //# sourceMappingURL=popularity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"popularity.js","sourceRoot":"","sources":["../../../src/commands/kg/popularity.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAiBjE,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAW,EAAE,OAA2B;IACzE,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAE9B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,SAAS,CACzB,GAAG,EACH,sBAAsB,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAChD,CAAC;QAEF,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,SAAS,CAAC,GAAG,CAAC,CAAC;YACf,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC/D,OAAO,CAAC,GAAG,CAAC,2BAA2B,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;QACrE,IAAI,GAAG,CAAC,aAAa,KAAK,SAAS;YAAE,OAAO,CAAC,GAAG,CAAC,2BAA2B,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACzG,IAAI,GAAG,CAAC,iBAAiB,KAAK,SAAS;YAAE,OAAO,CAAC,GAAG,CAAC,2BAA2B,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;QACjH,IAAI,GAAG,CAAC,eAAe;YAAE,OAAO,CAAC,GAAG,CAAC,2BAA2B,GAAG,CAAC,eAAe,EAAE,CAAC,CAAC;QACvF,IAAI,GAAG,CAAC,cAAc,KAAK,SAAS;YAAE,OAAO,CAAC,GAAG,CAAC,2BAA2B,QAAQ,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;QACjH,IAAI,GAAG,CAAC,kBAAkB,KAAK,SAAS,IAAI,GAAG,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;YAC1E,OAAO,CAAC,GAAG,CAAC,4BAA4B,GAAG,CAAC,kBAAkB,OAAO,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAClG,CAAC;QACD,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;YACnC,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,UAAU;gBAAE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACpF,CAAC;IACH,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function kgSearch(query: string, options: {
2
+ limit?: string;
3
+ json?: boolean;
4
+ }): Promise<void>;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * 4ort kg search <query>
3
+ *
4
+ * GET /api/v1/search?q=...&limit=...
5
+ */
6
+ import { requireKgConfig } from "../../config.js";
7
+ import { kgRequest } from "../../kg-client.js";
8
+ import { printJson, printTable, truncate } from "../../kg-output.js";
9
+ export async function kgSearch(query, options) {
10
+ const cfg = requireKgConfig();
11
+ const limit = options.limit ? parseInt(options.limit, 10) : 20;
12
+ try {
13
+ const res = await kgRequest(cfg, "/api/v1/search", {
14
+ query: { q: query, limit },
15
+ });
16
+ if (options.json) {
17
+ printJson(res);
18
+ return;
19
+ }
20
+ console.log(`${res.total_returned} results for "${res.query}" (${res.latency_ms}ms)\n`);
21
+ printTable(res.hits, [
22
+ ["NAME", (r) => r.name],
23
+ ["SLUG", (r) => r.slug || ""],
24
+ ["TYPE", (r) => r.type || ""],
25
+ ["SUMMARY", (r) => truncate(r.summary, 80)],
26
+ ["SCORE", (r) => r.score.toFixed(3)],
27
+ ]);
28
+ }
29
+ catch (err) {
30
+ console.error(`✗ ${err.message}`);
31
+ process.exit(1);
32
+ }
33
+ }
34
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../../src/commands/kg/search.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAkBrE,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,KAAa,EAAE,OAA2C;IACvF,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE/D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,SAAS,CAAiB,GAAG,EAAE,gBAAgB,EAAE;YACjE,KAAK,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE;SAC3B,CAAC,CAAC;QAEH,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,SAAS,CAAC,GAAG,CAAC,CAAC;YACf,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,cAAc,iBAAiB,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC,UAAU,OAAO,CAAC,CAAC;QACzF,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE;YACnB,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YACvB,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;YAC7B,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;YAC7B,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAC3C,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;SACrC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ export declare function kgTrending(options: {
2
+ hours?: string;
3
+ limit?: string;
4
+ domain?: string;
5
+ json?: boolean;
6
+ }): Promise<void>;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * 4ort kg trending
3
+ *
4
+ * GET /api/v1/trending — top entities by Wikipedia pageview velocity.
5
+ */
6
+ import { requireKgConfig } from "../../config.js";
7
+ import { kgRequest } from "../../kg-client.js";
8
+ import { fmtFloat, fmtInt, printJson, printTable } from "../../kg-output.js";
9
+ export async function kgTrending(options) {
10
+ const cfg = requireKgConfig();
11
+ const hours = options.hours ? parseInt(options.hours, 10) : 1;
12
+ const limit = options.limit ? parseInt(options.limit, 10) : 50;
13
+ try {
14
+ const res = await kgRequest(cfg, "/api/v1/trending", {
15
+ query: { hours, limit, domain: options.domain },
16
+ });
17
+ if (options.json) {
18
+ printJson(res);
19
+ return;
20
+ }
21
+ console.log(`Trending (last ${res.window_hours}h) generated ${res.generated_at}\n`);
22
+ printTable(res.entities, [
23
+ ["NAME", (r) => r.name],
24
+ ["DOMAIN", (r) => r.domain || ""],
25
+ ["VIEWS", (r) => fmtInt(r.views_in_window)],
26
+ ["VELOCITY", (r) => fmtFloat(r.velocity_score ?? null, 2)],
27
+ ["WHY", (r) => r.why_trending || ""],
28
+ ]);
29
+ }
30
+ catch (err) {
31
+ console.error(`✗ ${err.message}`);
32
+ process.exit(1);
33
+ }
34
+ }
35
+ //# sourceMappingURL=trending.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trending.js","sourceRoot":"","sources":["../../../src/commands/kg/trending.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAiB7E,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAKhC;IACC,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE/D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,SAAS,CAAmB,GAAG,EAAE,kBAAkB,EAAE;YACrE,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE;SAChD,CAAC,CAAC;QAEH,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,SAAS,CAAC,GAAG,CAAC,CAAC;YACf,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,CAAC,YAAY,iBAAiB,GAAG,CAAC,YAAY,IAAI,CAAC,CAAC;QACrF,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE;YACvB,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YACvB,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC;YACjC,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;YAC3C,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;YAC1D,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,IAAI,EAAE,CAAC;SACrC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function mcpStdioCommand(): Promise<void>;
2
+ export declare function mcpServeCommand(opts: {
3
+ port?: string;
4
+ host?: string;
5
+ }): Promise<void>;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * 4ort mcp [stdio] — run the 4ort MCP server over stdio (Claude Desktop etc.):
3
+ * { "mcpServers": { "4ort": { "command": "4ort", "args": ["mcp"] } } }
4
+ * 4ort mcp serve — run it as a Streamable HTTP server (deploy behind a
5
+ * reverse proxy → mcp.4ort.xyz). Default 127.0.0.1:8003.
6
+ *
7
+ * Tools (both transports): kg_search, web_get, kg_entity, kg_match, kg_agent_context.
8
+ * kg_search + web_get work keyless; the kg_* entity tools use whatever 4ort.xyz
9
+ * key the server's ~/.4ort/config.json has (run `4ort kg auth login` on the host).
10
+ */
11
+ import { runMcpStdio, runMcpHttp } from "../mcp-server.js";
12
+ export async function mcpStdioCommand() {
13
+ await runMcpStdio();
14
+ }
15
+ export async function mcpServeCommand(opts) {
16
+ const port = opts.port ? parseInt(opts.port, 10) : 8003;
17
+ const host = opts.host || "127.0.0.1";
18
+ if (!Number.isFinite(port) || port <= 0 || port > 65535) {
19
+ console.error(`Invalid --port: ${opts.port}`);
20
+ process.exit(1);
21
+ }
22
+ await runMcpHttp({ host, port });
23
+ }
24
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE3D,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,WAAW,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAsC;IAC1E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,WAAW,CAAC;IACtC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QACxD,OAAO,CAAC,KAAK,CAAC,mBAAmB,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AACnC,CAAC"}
@@ -0,0 +1,17 @@
1
+ export declare function movLogin(options: {
2
+ server?: string;
3
+ username?: string;
4
+ password?: string;
5
+ }): Promise<void>;
6
+ export declare function movPublish(file: string, options: {
7
+ title?: string;
8
+ channel?: string;
9
+ description?: string;
10
+ thumbnail?: string;
11
+ privacy?: string;
12
+ }): Promise<void>;
13
+ export declare function movList(): Promise<void>;
14
+ export declare function movChannels(options: {
15
+ create?: string;
16
+ }): Promise<void>;
17
+ export declare function movDelete(id: string): Promise<void>;
@@ -0,0 +1,124 @@
1
+ /**
2
+ * 4ort mov — publish & manage videos on 4ort.mov (PeerTube).
3
+ *
4
+ * login — OAuth password grant, persists tokens to ~/.4ort/config.json
5
+ * publish — upload a finished video file
6
+ * list — list your videos
7
+ * channels — list channels (or --create one)
8
+ * delete — delete a video by id
9
+ */
10
+ import readline from "node:readline/promises";
11
+ import { stdin as input, stdout as output } from "node:process";
12
+ import { saveMovConfig, optionalMovConfig } from "../config.js";
13
+ import { getOAuthClient, getToken, uploadVideo, listMyChannels, createChannel, listMyVideos, deleteVideo, resolveChannelId, privacyToEnum, buildWatchUrl, } from "../peertube-client.js";
14
+ const DEFAULT_SERVER = "https://4ort.mov";
15
+ export async function movLogin(options) {
16
+ const server = options.server || DEFAULT_SERVER;
17
+ // Non-interactive (agents/CI): flags or env. Falls back to prompts for humans.
18
+ let username = options.username || process.env.FORT_MOV_USERNAME;
19
+ let password = options.password || process.env.FORT_MOV_PASSWORD;
20
+ let rl;
21
+ try {
22
+ if (!username || !password) {
23
+ rl = readline.createInterface({ input, output });
24
+ if (!username)
25
+ username = (await rl.question("PeerTube username (e.g. root): ")).trim();
26
+ if (!password)
27
+ password = (await rl.question("Password: ")).trim();
28
+ }
29
+ if (!username || !password) {
30
+ console.error("username and password required (use --username/--password or env FORT_MOV_USERNAME/FORT_MOV_PASSWORD)");
31
+ process.exit(1);
32
+ }
33
+ console.log(`\nAuthenticating to ${server}...`);
34
+ const client = await getOAuthClient(server);
35
+ const tok = await getToken(server, client, username, password);
36
+ saveMovConfig({
37
+ server,
38
+ accessToken: tok.accessToken,
39
+ refreshToken: tok.refreshToken,
40
+ clientId: client.clientId,
41
+ clientSecret: client.clientSecret,
42
+ username,
43
+ });
44
+ console.log("✓ Signed in to 4ort.mov. Try: 4ort mov channels");
45
+ }
46
+ catch (e) {
47
+ console.error(`✗ ${e.message}`);
48
+ process.exit(1);
49
+ }
50
+ finally {
51
+ rl?.close();
52
+ }
53
+ }
54
+ export async function movPublish(file, options) {
55
+ try {
56
+ const cfg = optionalMovConfig();
57
+ if (!options.title) {
58
+ console.error("--title is required");
59
+ process.exit(1);
60
+ }
61
+ const channels = await listMyChannels(cfg);
62
+ const channelId = resolveChannelId(channels, options.channel);
63
+ const privacy = privacyToEnum(options.privacy || "unlisted");
64
+ console.log(`Uploading ${file}...`);
65
+ const v = await uploadVideo(cfg, {
66
+ file,
67
+ name: options.title,
68
+ channelId,
69
+ privacy,
70
+ description: options.description,
71
+ thumbnail: options.thumbnail,
72
+ });
73
+ console.log(`✓ Published: ${buildWatchUrl(cfg.server, v.shortUUID)}`);
74
+ }
75
+ catch (e) {
76
+ console.error(`✗ ${e.message}`);
77
+ process.exit(1);
78
+ }
79
+ }
80
+ export async function movList() {
81
+ try {
82
+ const cfg = optionalMovConfig();
83
+ const vids = await listMyVideos(cfg);
84
+ if (!vids.length) {
85
+ console.log("(no videos)");
86
+ return;
87
+ }
88
+ for (const v of vids)
89
+ console.log(`${v.id}\t${v.privacy}\t${v.name}\t${buildWatchUrl(cfg.server, v.shortUUID)}`);
90
+ }
91
+ catch (e) {
92
+ console.error(`✗ ${e.message}`);
93
+ process.exit(1);
94
+ }
95
+ }
96
+ export async function movChannels(options) {
97
+ try {
98
+ const cfg = optionalMovConfig();
99
+ if (options.create) {
100
+ const id = await createChannel(cfg, options.create);
101
+ console.log(`✓ created channel '${options.create}' (id ${id})`);
102
+ return;
103
+ }
104
+ const channels = await listMyChannels(cfg);
105
+ for (const c of channels)
106
+ console.log(`${c.id}\t${c.name}\t${c.displayName}`);
107
+ }
108
+ catch (e) {
109
+ console.error(`✗ ${e.message}`);
110
+ process.exit(1);
111
+ }
112
+ }
113
+ export async function movDelete(id) {
114
+ try {
115
+ const cfg = optionalMovConfig();
116
+ await deleteVideo(cfg, Number(id));
117
+ console.log(`✓ deleted video ${id}`);
118
+ }
119
+ catch (e) {
120
+ console.error(`✗ ${e.message}`);
121
+ process.exit(1);
122
+ }
123
+ }
124
+ //# sourceMappingURL=mov.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mov.js","sourceRoot":"","sources":["../../src/commands/mov.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * `4ort run -- <command> [args...]`
3
+ *
4
+ * Resolves any env var whose value is a `4ort://service[/name]` reference into
5
+ * its real secret (fetched from the 4ort.ai vault at runtime), injects the
6
+ * plaintext into the child process's environment ONLY, and runs the command.
7
+ * Plaintext never touches disk — it lives only in the child's memory.
8
+ * Fails closed: if any referenced secret can't be resolved, nothing runs.
9
+ */
10
+ export declare function runCommand(parts: string[]): Promise<void>;
@@ -0,0 +1,74 @@
1
+ import { spawn } from "node:child_process";
2
+ import { requireVaultConfig } from "../config.js";
3
+ const REF_RE = /^4ort:\/\/.+/;
4
+ /**
5
+ * `4ort run -- <command> [args...]`
6
+ *
7
+ * Resolves any env var whose value is a `4ort://service[/name]` reference into
8
+ * its real secret (fetched from the 4ort.ai vault at runtime), injects the
9
+ * plaintext into the child process's environment ONLY, and runs the command.
10
+ * Plaintext never touches disk — it lives only in the child's memory.
11
+ * Fails closed: if any referenced secret can't be resolved, nothing runs.
12
+ */
13
+ export async function runCommand(parts) {
14
+ if (!parts || parts.length === 0) {
15
+ console.error("Usage: 4ort run -- <command> [args...]");
16
+ console.error('Example: GROQ_API_KEY=4ort://groq 4ort run -- node app.js');
17
+ process.exit(1);
18
+ }
19
+ const { token, server } = requireVaultConfig();
20
+ // Collect env vars that hold a 4ort:// reference.
21
+ const refsByEnv = {};
22
+ for (const [key, value] of Object.entries(process.env)) {
23
+ if (typeof value === "string" && REF_RE.test(value.trim())) {
24
+ refsByEnv[key] = value.trim();
25
+ }
26
+ }
27
+ const refs = [...new Set(Object.values(refsByEnv))];
28
+ let resolved = {};
29
+ let missing = [];
30
+ if (refs.length > 0) {
31
+ try {
32
+ const res = await fetch(`${server.replace(/\/$/, "")}/api/secrets/resolve`, {
33
+ method: "POST",
34
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
35
+ body: JSON.stringify({ refs }),
36
+ });
37
+ if (!res.ok) {
38
+ console.error(`✗ vault resolve failed (HTTP ${res.status}). Try: 4ort vault login`);
39
+ process.exit(1);
40
+ }
41
+ const data = (await res.json());
42
+ resolved = data.resolved || {};
43
+ missing = data.missing || [];
44
+ }
45
+ catch (e) {
46
+ console.error(`✗ could not reach the vault: ${e.message}`);
47
+ process.exit(1);
48
+ }
49
+ }
50
+ if (missing.length > 0) {
51
+ console.error(`✗ unresolved secret reference(s): ${missing.join(", ")}`);
52
+ console.error(" add them in the 4ort.ai Secrets panel, or fix the 4ort:// reference.");
53
+ process.exit(1);
54
+ }
55
+ const childEnv = { ...process.env };
56
+ let injected = 0;
57
+ for (const [key, ref] of Object.entries(refsByEnv)) {
58
+ if (resolved[ref] !== undefined) {
59
+ childEnv[key] = resolved[ref];
60
+ injected += 1;
61
+ }
62
+ }
63
+ if (injected > 0) {
64
+ console.error(`4ort: injected ${injected} secret${injected === 1 ? "" : "s"} into the environment`);
65
+ }
66
+ const [cmd, ...args] = parts;
67
+ const child = spawn(cmd, args, { stdio: "inherit", env: childEnv });
68
+ child.on("error", (e) => {
69
+ console.error(`✗ failed to run "${cmd}": ${e.message}`);
70
+ process.exit(1);
71
+ });
72
+ child.on("exit", (code) => process.exit(code ?? 0));
73
+ }
74
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ interface SearchOptions {
2
+ pages?: string;
3
+ sources?: string;
4
+ json?: boolean;
5
+ }
6
+ export declare function searchCommand(query: string, options: SearchOptions): Promise<void>;
7
+ export {};
@@ -0,0 +1,105 @@
1
+ /**
2
+ * 4ort search <query> — the smart router. The front door.
3
+ *
4
+ * GET /api/v1/route?q=...&limit_pages=...&limit_sources=... (public, no key)
5
+ *
6
+ * Returns everything an agent needs to decide where to go next:
7
+ * ● KNOWLEDGE GRAPH — the canonical 4ort.xyz entity the query names (if any),
8
+ * plus that entity's own official site / social links
9
+ * ("straight to the source"). From here: `4ort kg entity
10
+ * <slug>` / `4ort kg ask "..." --scope <slug>`.
11
+ * ☎ AUTHORITATIVE SOURCES — the "phonebook": curated search URLs for the
12
+ * detected vertical (GitHub/Wikipedia/IMDb/SEC/…). The
13
+ * agent can `4ort web get <url>` any of them.
14
+ * ⌕ WEB RESULTS — ranked hits from our Common Crawl index. `4ort web get
15
+ * <url>` to read one.
16
+ *
17
+ * Distinct from `4ort kg search`, which is a pure entity-graph lookup.
18
+ */
19
+ import { optionalKgConfig } from "../config.js";
20
+ import { kgRequest } from "../kg-client.js";
21
+ import { printJson, truncate } from "../kg-output.js";
22
+ function slugFromEntityUrl(u) {
23
+ if (!u)
24
+ return undefined;
25
+ const m = u.match(/\/entity\/([^/?#]+)/);
26
+ return m ? m[1] : undefined;
27
+ }
28
+ export async function searchCommand(query, options) {
29
+ const cfg = optionalKgConfig();
30
+ const limitPages = options.pages ? parseInt(options.pages, 10) : 20;
31
+ const limitSources = options.sources ? parseInt(options.sources, 10) : 12;
32
+ try {
33
+ const res = await kgRequest(cfg, "/api/v1/route", {
34
+ query: { q: query, limit_pages: limitPages, limit_sources: limitSources },
35
+ });
36
+ if (options.json) {
37
+ printJson(res);
38
+ return;
39
+ }
40
+ // ── header / detected intent ──
41
+ console.log(`SEARCH "${res.query}"`);
42
+ const pi = res.primary_intent;
43
+ if (pi) {
44
+ const how = pi.method === "entity"
45
+ ? `exact entity → ${pi.entity_name}`
46
+ : pi.method === "keyword"
47
+ ? `keyword rule${pi.keyword_hits ? ` · ${pi.keyword_hits} hits` : ""}`
48
+ : pi.method === "embedding"
49
+ ? "semantic"
50
+ : pi.method;
51
+ console.log(` intent: ${pi.label} [${how}]`);
52
+ }
53
+ if (res.intent_alternatives?.length) {
54
+ console.log(` or maybe: ${res.intent_alternatives.map((a) => a.label).join(" · ")}`);
55
+ }
56
+ // ── ● knowledge graph ──
57
+ if (res.canonical_entity) {
58
+ const e = res.canonical_entity;
59
+ const slug = slugFromEntityUrl(e.url);
60
+ console.log(`\n● KNOWLEDGE GRAPH`);
61
+ console.log(` ${e.name}${e.summary ? ` — ${e.summary}` : ""}`);
62
+ const views = typeof e.monthly_pageviews === "number" && e.monthly_pageviews > 0
63
+ ? ` ~${e.monthly_pageviews.toLocaleString()} views/mo`
64
+ : "";
65
+ console.log(` ${e.url}${views}`);
66
+ if (slug) {
67
+ console.log(` → 4ort kg entity ${slug} --detail full`);
68
+ console.log(` → 4ort kg ask "<question>" --scope ${slug}`);
69
+ }
70
+ if (e.links?.length) {
71
+ console.log(` straight to the source:`);
72
+ for (const l of e.links)
73
+ console.log(` ${l.icon || "•"} ${l.name}: ${l.url}`);
74
+ }
75
+ }
76
+ // ── ☎ the phonebook ──
77
+ if (res.recommended_sources?.length) {
78
+ console.log(`\n☎ AUTHORITATIVE SOURCES (the phonebook — 4ort web get <url> to read one)`);
79
+ const w = Math.min(22, Math.max(...res.recommended_sources.map((s) => s.name.length)));
80
+ for (const s of res.recommended_sources) {
81
+ console.log(` ${s.name.padEnd(w)} ${s.url}`);
82
+ }
83
+ }
84
+ // ── ⌕ web results ──
85
+ if (res.our_pages?.length) {
86
+ console.log(`\n⌕ WEB RESULTS (${res.our_pages.length} from our index — 4ort web get <url> to read)`);
87
+ for (const p of res.our_pages) {
88
+ console.log(` ${p.title}${p.host ? ` · ${p.host}` : ""}`);
89
+ console.log(` ${p.url}`);
90
+ if (p.snippet)
91
+ console.log(` ${truncate(p.snippet, 140)}`);
92
+ }
93
+ }
94
+ else {
95
+ console.log(`\n⌕ WEB RESULTS (nothing in our index for this query — use the phonebook)`);
96
+ }
97
+ if (res.license)
98
+ console.log(`\n${res.license}`);
99
+ }
100
+ catch (err) {
101
+ console.error(`✗ ${err.message}`);
102
+ process.exit(1);
103
+ }
104
+ }
105
+ //# sourceMappingURL=search.js.map