@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.
- package/README.md +286 -0
- package/dist/commands/kg/agent-context.d.ts +3 -0
- package/dist/commands/kg/agent-context.js +54 -0
- package/dist/commands/kg/agent-context.js.map +1 -0
- package/dist/commands/kg/article-context.d.ts +3 -0
- package/dist/commands/kg/article-context.js +51 -0
- package/dist/commands/kg/article-context.js.map +1 -0
- package/dist/commands/kg/ask.d.ts +5 -0
- package/dist/commands/kg/ask.js +121 -0
- package/dist/commands/kg/ask.js.map +1 -0
- package/dist/commands/kg/auth.d.ts +9 -0
- package/dist/commands/kg/auth.js +95 -0
- package/dist/commands/kg/auth.js.map +1 -0
- package/dist/commands/kg/entity.d.ts +4 -0
- package/dist/commands/kg/entity.js +33 -0
- package/dist/commands/kg/entity.js.map +1 -0
- package/dist/commands/kg/match.d.ts +5 -0
- package/dist/commands/kg/match.js +44 -0
- package/dist/commands/kg/match.js.map +1 -0
- package/dist/commands/kg/popularity.d.ts +3 -0
- package/dist/commands/kg/popularity.js +42 -0
- package/dist/commands/kg/popularity.js.map +1 -0
- package/dist/commands/kg/search.d.ts +4 -0
- package/dist/commands/kg/search.js +34 -0
- package/dist/commands/kg/search.js.map +1 -0
- package/dist/commands/kg/trending.d.ts +6 -0
- package/dist/commands/kg/trending.js +35 -0
- package/dist/commands/kg/trending.js.map +1 -0
- package/dist/commands/mcp.d.ts +5 -0
- package/dist/commands/mcp.js +24 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/mov.d.ts +17 -0
- package/dist/commands/mov.js +124 -0
- package/dist/commands/mov.js.map +1 -0
- package/dist/commands/run.d.ts +10 -0
- package/dist/commands/run.js +74 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/search.d.ts +7 -0
- package/dist/commands/search.js +105 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/vault.d.ts +7 -0
- package/dist/commands/vault.js +62 -0
- package/dist/commands/vault.js.map +1 -0
- package/dist/commands/web.d.ts +6 -0
- package/dist/commands/web.js +44 -0
- package/dist/commands/web.js.map +1 -0
- package/dist/config.d.ts +38 -0
- package/dist/config.js +97 -1
- package/dist/config.js.map +1 -1
- package/dist/config.mov.test.d.ts +1 -0
- package/dist/config.mov.test.js +23 -0
- package/dist/config.mov.test.js.map +1 -0
- package/dist/index.js +195 -37
- package/dist/index.js.map +1 -1
- package/dist/kg-client.d.ts +42 -0
- package/dist/kg-client.js +125 -0
- package/dist/kg-client.js.map +1 -0
- package/dist/kg-output.d.ts +33 -0
- package/dist/kg-output.js +132 -0
- package/dist/kg-output.js.map +1 -0
- package/dist/mcp-server.d.ts +5 -0
- package/dist/mcp-server.js +363 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/peertube-client.d.ts +47 -0
- package/dist/peertube-client.js +144 -0
- package/dist/peertube-client.js.map +1 -0
- package/dist/peertube-client.test.d.ts +1 -0
- package/dist/peertube-client.test.js +92 -0
- package/dist/peertube-client.test.js.map +1 -0
- package/dist/web-client.d.ts +20 -0
- package/dist/web-client.js +335 -0
- package/dist/web-client.js.map +1 -0
- package/package.json +21 -4
- package/src/api-client.ts +0 -51
- package/src/commands/delete.ts +0 -15
- package/src/commands/list.ts +0 -25
- package/src/commands/mail.ts +0 -79
- package/src/commands/provision.ts +0 -106
- package/src/commands/push.ts +0 -63
- package/src/commands/recover.ts +0 -37
- package/src/commands/register.ts +0 -40
- package/src/commands/whoami.ts +0 -20
- package/src/config.ts +0 -40
- package/src/index.ts +0 -114
- package/tsconfig.json +0 -8
package/README.md
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
# @4ort/cli
|
|
2
|
+
|
|
3
|
+
The unified command-line interface for the 4ort ecosystem.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install -g @4ort/cli
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
One install. One identity. Every product.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Products
|
|
14
|
+
|
|
15
|
+
| Namespace | What it does |
|
|
16
|
+
| -------------------------- | ---------------------------------------------- |
|
|
17
|
+
| `4ort register / push / …` | 4ort.net subdomain hosting + email + agents |
|
|
18
|
+
| `4ort mail` | Manage your `@4ort.net` inbox from the CLI |
|
|
19
|
+
| `4ort provision` | Auto-provision third-party service accounts |
|
|
20
|
+
| `4ort kg` | 4ort.xyz knowledge graph (Popularity Graph) |
|
|
21
|
+
| `4ort config` | Inspect ~/.4ort/config.json |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Quickstart — knowledge graph
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# one-shot register; no email or browser required
|
|
29
|
+
4ort kg register --name my-agent
|
|
30
|
+
|
|
31
|
+
# ask anything, with cited streaming answers
|
|
32
|
+
4ort kg ask "who founded Apple Inc?"
|
|
33
|
+
|
|
34
|
+
# search, match, fetch
|
|
35
|
+
4ort kg search "Tame Impala" --limit 5
|
|
36
|
+
4ort kg entity apple-inc --detail full
|
|
37
|
+
4ort kg match "Apple"
|
|
38
|
+
|
|
39
|
+
# Wikipedia-pageview-derived "real-world search volume"
|
|
40
|
+
4ort kg popularity tesla-inc
|
|
41
|
+
|
|
42
|
+
# top entities by velocity in the last N hours
|
|
43
|
+
4ort kg trending --hours 24 --limit 10
|
|
44
|
+
|
|
45
|
+
# fat agent / writer bundles
|
|
46
|
+
4ort kg agent-context apple-inc
|
|
47
|
+
4ort kg article-context apple-inc
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Every command supports `--json` for pipe-friendly structured output:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
4ort kg trending --hours 24 --json | jq -r '.entities[].name'
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Quickstart — 4ort.net hosting
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
4ort register myname # claim your subdomain + get an API key + recovery code
|
|
62
|
+
4ort push . # deploy current dir to https://myname.4ort.net
|
|
63
|
+
4ort list # show your sites
|
|
64
|
+
4ort mail inbox # check your @4ort.net inbox
|
|
65
|
+
4ort provision all # auto-provision Tier-A external service accounts
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Authentication
|
|
71
|
+
|
|
72
|
+
Two independent identities live in `~/.4ort/config.json`:
|
|
73
|
+
|
|
74
|
+
```jsonc
|
|
75
|
+
{
|
|
76
|
+
"apiKey": "...", // 4ort.net agent key
|
|
77
|
+
"server": "https://4ort.net",
|
|
78
|
+
"agentName": "ryan",
|
|
79
|
+
"recoveryCode": "...",
|
|
80
|
+
"kg": { // 4ort.xyz knowledge graph (optional)
|
|
81
|
+
"apiKey": "4kg_...",
|
|
82
|
+
"server": "https://4ort.xyz",
|
|
83
|
+
"name": "my-agent",
|
|
84
|
+
"tier": "free",
|
|
85
|
+
"recoveryCode": "..."
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The file is created with mode `0600` and only stores hashes server-side — the
|
|
91
|
+
raw API key and recovery code are shown to you **once** at register time.
|
|
92
|
+
Save the recovery code somewhere safe; it is the only way to rotate a lost key.
|
|
93
|
+
|
|
94
|
+
### Sign-in shortcuts
|
|
95
|
+
|
|
96
|
+
| Command | What it does |
|
|
97
|
+
| ---------------------------- | ----------------------------------------------------- |
|
|
98
|
+
| `4ort register <name>` | Register on 4ort.net, persists `apiKey` + recovery |
|
|
99
|
+
| `4ort kg register --name X` | Register on 4ort.xyz (knowledge graph) |
|
|
100
|
+
| `4ort kg auth login` | Paste an existing 4ort.xyz key (second machine) |
|
|
101
|
+
| `4ort kg auth status` | Show current 4ort.xyz identity + tier |
|
|
102
|
+
| `4ort config` | Inspect both blocks |
|
|
103
|
+
|
|
104
|
+
### Federation
|
|
105
|
+
|
|
106
|
+
A 4ort.net membership grants **bundled access** to the knowledge graph
|
|
107
|
+
automatically. If your config has a 4ort.net `apiKey` but no `kg` block,
|
|
108
|
+
the CLI uses the 4ort.net key against 4ort.xyz endpoints; the 4ort.xyz
|
|
109
|
+
server validates it via 4ort.net's internal partner endpoint and applies
|
|
110
|
+
the bundled tier (~1k requests/day).
|
|
111
|
+
|
|
112
|
+
Standalone 4ort.xyz signups (free tier, ~100 requests/day) get their own
|
|
113
|
+
`4kg_`-prefixed key with no 4ort.net membership required.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Output formats
|
|
118
|
+
|
|
119
|
+
Every `kg` command honors `--json` for piping. The `ask` command also has
|
|
120
|
+
two render modes:
|
|
121
|
+
|
|
122
|
+
| Where output goes | Default behavior |
|
|
123
|
+
| ---------------------- | -------------------------------------------------- |
|
|
124
|
+
| Real terminal (TTY) | `**bold**` and `*italic*` rendered with ANSI |
|
|
125
|
+
| Pipe / redirect / file | Raw markdown unchanged (good for agents, jq, glow) |
|
|
126
|
+
| `--plain` | Strip markdown markers entirely (flat text) |
|
|
127
|
+
|
|
128
|
+
Citation refs like `[11]` are always preserved.
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# pretty in your terminal
|
|
132
|
+
4ort kg ask "who founded Apple?"
|
|
133
|
+
|
|
134
|
+
# raw markdown into a file (LLM-friendly)
|
|
135
|
+
4ort kg ask "who founded Apple?" > answer.md
|
|
136
|
+
|
|
137
|
+
# stripped flat text
|
|
138
|
+
4ort kg ask "who founded Apple?" --plain
|
|
139
|
+
|
|
140
|
+
# full structured payload with citations[]
|
|
141
|
+
4ort kg ask "who founded Apple?" --json | jq '.citations[].source_url'
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Command reference (knowledge graph)
|
|
147
|
+
|
|
148
|
+
### `4ort kg register`
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
Options:
|
|
152
|
+
-n, --name <name> Display name for this key (required)
|
|
153
|
+
-e, --email <email> Optional contact email
|
|
154
|
+
-s, --server <url> KG server URL (default: https://4ort.xyz)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
POSTs `/api/v1/register`. Returns `apiKey` + one-time `recoveryCode`. TOFU
|
|
158
|
+
flow — no email verification, no browser, agent-friendly.
|
|
159
|
+
|
|
160
|
+
### `4ort kg ask <question>`
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
Options:
|
|
164
|
+
-s, --scope <slug> Scope to a specific entity (e.g. apple-inc)
|
|
165
|
+
--json Skip streaming, return one structured payload
|
|
166
|
+
--plain Strip markdown formatting
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Streams cited answers via SSE from `/api/qa/stream`. Citations preserve
|
|
170
|
+
their original external URLs (Wikidata refs).
|
|
171
|
+
|
|
172
|
+
### `4ort kg search <query>`
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
Options:
|
|
176
|
+
-l, --limit <n> Max results (default: 20)
|
|
177
|
+
--json
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Hybrid trigram + popularity search across the entity graph.
|
|
181
|
+
|
|
182
|
+
### `4ort kg entity <key>`
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
Options:
|
|
186
|
+
-d, --detail <level> tiny | small | medium | full (default: medium)
|
|
187
|
+
--json
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Fetch one entity by slug, UUID, or Wikidata Q-id.
|
|
191
|
+
|
|
192
|
+
### `4ort kg match <text>`
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
Options:
|
|
196
|
+
-l, --limit <n> Max candidates (default: 5)
|
|
197
|
+
-t, --types <list> Comma-separated entity-type filter
|
|
198
|
+
--json
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Resolve a string to its canonical entity. Returns ranked candidates with
|
|
202
|
+
confidence scores; `primary` is set when top confidence ≥ 0.7.
|
|
203
|
+
|
|
204
|
+
### `4ort kg popularity <key>`
|
|
205
|
+
|
|
206
|
+
Wikipedia-pageview-derived "real-world search volume" — drop-in alternative
|
|
207
|
+
to Google Keyword Planner / Ahrefs / SEMrush. CC0-licensed, free.
|
|
208
|
+
|
|
209
|
+
### `4ort kg trending`
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
Options:
|
|
213
|
+
-h, --hours <n> Window size in hours (default: 1, max: 168)
|
|
214
|
+
-l, --limit <n> Max results (default: 50)
|
|
215
|
+
-d, --domain <name> Filter to a specific domain
|
|
216
|
+
--json
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Top entities by Wikipedia pageview velocity (rising stars beat plain
|
|
220
|
+
popularity).
|
|
221
|
+
|
|
222
|
+
### `4ort kg agent-context <key>`
|
|
223
|
+
|
|
224
|
+
Memory-bank bundle for autonomous agents: facts grouped by predicate,
|
|
225
|
+
key actors via P169/P112/P50/P175 (CEO/founder/author/performer),
|
|
226
|
+
world context (country, domain rank, monthly views), short + long
|
|
227
|
+
summaries.
|
|
228
|
+
|
|
229
|
+
Privacy boundary: biographical facts only — does **not** package real
|
|
230
|
+
people as agent personas.
|
|
231
|
+
|
|
232
|
+
### `4ort kg article-context <key>`
|
|
233
|
+
|
|
234
|
+
Fat bundle for SEO writers: medium-detail entity card + ranked facts +
|
|
235
|
+
every external citation URL + recent edits + connections + trending
|
|
236
|
+
signals + LLM-synthesized writing hooks.
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Composing with UNIX tools
|
|
241
|
+
|
|
242
|
+
The CLI is designed to chain. Some recipes:
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
# trending → entity slugs → fetch each
|
|
246
|
+
4ort kg trending --hours 24 --json \
|
|
247
|
+
| jq -r '.entities[].slug' \
|
|
248
|
+
| xargs -I {} 4ort kg entity {}
|
|
249
|
+
|
|
250
|
+
# get all source URLs for an article
|
|
251
|
+
4ort kg ask "what does Apple Inc do?" --json \
|
|
252
|
+
| jq -r '.citations[].source_url' \
|
|
253
|
+
| sort -u
|
|
254
|
+
|
|
255
|
+
# pipe answer into another LLM
|
|
256
|
+
4ort kg article-context apple-inc \
|
|
257
|
+
| claude -p "draft a 600-word piece based on these facts"
|
|
258
|
+
|
|
259
|
+
# match a list of brand names from a CSV
|
|
260
|
+
xargs -I {} 4ort kg match {} --json < brands.csv \
|
|
261
|
+
| jq -r '.primary | "\(.name)\t\(.slug)\t\(.confidence)"'
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## Development
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
git clone <repo-url>
|
|
270
|
+
cd cli
|
|
271
|
+
npm install
|
|
272
|
+
npm run build
|
|
273
|
+
node dist/index.js --help
|
|
274
|
+
|
|
275
|
+
# during dev — npm link makes `4ort` global, points to local code
|
|
276
|
+
npm link
|
|
277
|
+
4ort kg ask "test"
|
|
278
|
+
# rebuild after edits — symlink picks up new dist/ automatically
|
|
279
|
+
npm run build
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## License
|
|
285
|
+
|
|
286
|
+
Proprietary. © the 4ort team.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 4ort kg agent-context <key>
|
|
3
|
+
*
|
|
4
|
+
* GET /api/v1/entities/{key}/agent-context — memory bank for agents.
|
|
5
|
+
* Default output is compact human, --json gives the full structured payload.
|
|
6
|
+
*/
|
|
7
|
+
import { requireKgConfig } from "../../config.js";
|
|
8
|
+
import { kgRequest } from "../../kg-client.js";
|
|
9
|
+
import { fmtInt, printJson, truncate } from "../../kg-output.js";
|
|
10
|
+
export async function kgAgentContext(key, options) {
|
|
11
|
+
const cfg = requireKgConfig();
|
|
12
|
+
try {
|
|
13
|
+
const data = await kgRequest(cfg, `/api/v1/entities/${encodeURIComponent(key)}/agent-context`);
|
|
14
|
+
if (options.json) {
|
|
15
|
+
printJson(data);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
console.log(`${data.name}${data.type ? ` (${data.type})` : ""}`);
|
|
19
|
+
if (data.summary_short)
|
|
20
|
+
console.log(`\n ${truncate(data.summary_short, 200)}`);
|
|
21
|
+
if (data.summary_long)
|
|
22
|
+
console.log(`\n ${truncate(data.summary_long, 600)}`);
|
|
23
|
+
if (data.facts_by_predicate && Object.keys(data.facts_by_predicate).length > 0) {
|
|
24
|
+
console.log("\nfacts:");
|
|
25
|
+
for (const [pred, vals] of Object.entries(data.facts_by_predicate)) {
|
|
26
|
+
console.log(` ${pred}: ${vals.join(", ")}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (Array.isArray(data.key_actors) && data.key_actors.length > 0) {
|
|
30
|
+
console.log("\nkey actors:");
|
|
31
|
+
for (const a of data.key_actors)
|
|
32
|
+
console.log(` ${a.role}: ${a.name}`);
|
|
33
|
+
}
|
|
34
|
+
if (data.world_context) {
|
|
35
|
+
const w = data.world_context;
|
|
36
|
+
console.log("\nworld context:");
|
|
37
|
+
if (w.country)
|
|
38
|
+
console.log(` country: ${w.country}`);
|
|
39
|
+
if (w.domain)
|
|
40
|
+
console.log(` domain: ${w.domain}`);
|
|
41
|
+
if (w.monthly_views !== undefined)
|
|
42
|
+
console.log(` monthly views: ${fmtInt(w.monthly_views)}`);
|
|
43
|
+
if (w.domain_rank !== undefined)
|
|
44
|
+
console.log(` domain rank: #${w.domain_rank}`);
|
|
45
|
+
}
|
|
46
|
+
if (data.license)
|
|
47
|
+
console.log(`\nlicense: ${data.license}`);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
console.error(`✗ ${err.message}`);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=agent-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-context.js","sourceRoot":"","sources":["../../../src/commands/kg/agent-context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 4ort kg article-context <key>
|
|
3
|
+
*
|
|
4
|
+
* GET /api/v1/entities/{key}/article-context — fat bundle for SEO writers.
|
|
5
|
+
*/
|
|
6
|
+
import { requireKgConfig } from "../../config.js";
|
|
7
|
+
import { kgRequest } from "../../kg-client.js";
|
|
8
|
+
import { printEntity, printJson, truncate } from "../../kg-output.js";
|
|
9
|
+
export async function kgArticleContext(key, options) {
|
|
10
|
+
const cfg = requireKgConfig();
|
|
11
|
+
try {
|
|
12
|
+
const data = await kgRequest(cfg, `/api/v1/entities/${encodeURIComponent(key)}/article-context`);
|
|
13
|
+
if (options.json) {
|
|
14
|
+
printJson(data);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (data.entity)
|
|
18
|
+
printEntity(data.entity);
|
|
19
|
+
if (Array.isArray(data.writing_hooks) && data.writing_hooks.length > 0) {
|
|
20
|
+
console.log("\nwriting hooks:");
|
|
21
|
+
for (const h of data.writing_hooks)
|
|
22
|
+
console.log(` • ${truncate(h, 200)}`);
|
|
23
|
+
}
|
|
24
|
+
if (Array.isArray(data.citations) && data.citations.length > 0) {
|
|
25
|
+
console.log(`\nsource URLs (${data.citations.length}):`);
|
|
26
|
+
for (const c of data.citations) {
|
|
27
|
+
console.log(` ${c.label || c.predicate_label || ""}`);
|
|
28
|
+
console.log(` ${c.url}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (data.trending_signals) {
|
|
32
|
+
const t = data.trending_signals;
|
|
33
|
+
console.log("\ntrending signals:");
|
|
34
|
+
if (t.monthly_pageviews !== undefined)
|
|
35
|
+
console.log(` monthly pageviews: ${t.monthly_pageviews}`);
|
|
36
|
+
if (t.velocity_score !== undefined)
|
|
37
|
+
console.log(` velocity score: ${t.velocity_score}`);
|
|
38
|
+
if (t.trend_direction)
|
|
39
|
+
console.log(` trend: ${t.trend_direction}`);
|
|
40
|
+
if (t.yoy_change_pct !== undefined)
|
|
41
|
+
console.log(` YoY change: ${t.yoy_change_pct}%`);
|
|
42
|
+
}
|
|
43
|
+
if (data.license)
|
|
44
|
+
console.log(`\nlicense: ${data.license}`);
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
console.error(`✗ ${err.message}`);
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=article-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"article-context.js","sourceRoot":"","sources":["../../../src/commands/kg/article-context.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,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEtE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAW,EAAE,OAA2B;IAC7E,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,SAAS,CAC1B,GAAG,EACH,oBAAoB,kBAAkB,CAAC,GAAG,CAAC,kBAAkB,CAC9D,CAAC;QAEF,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,SAAS,CAAC,IAAI,CAAC,CAAC;YAChB,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,MAAM;YAAE,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE1C,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvE,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;YAChC,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,aAAa;gBAAE,OAAO,CAAC,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QAC7E,CAAC;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/D,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,CAAC;YACzD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBAC/B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,eAAe,IAAI,EAAE,EAAE,CAAC,CAAC;gBACvD,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;QAED,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,MAAM,CAAC,GAAG,IAAI,CAAC,gBAAgB,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;YACnC,IAAI,CAAC,CAAC,iBAAiB,KAAK,SAAS;gBAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC;YAClG,IAAI,CAAC,CAAC,cAAc,KAAK,SAAS;gBAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC;YAC5F,IAAI,CAAC,CAAC,eAAe;gBAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC;YAChF,IAAI,CAAC,CAAC,cAAc,KAAK,SAAS;gBAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,cAAc,GAAG,CAAC,CAAC;QAC/F,CAAC;QAED,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9D,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,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 4ort kg ask <question>
|
|
3
|
+
*
|
|
4
|
+
* POST /api/qa/stream (Server-Sent Events)
|
|
5
|
+
*
|
|
6
|
+
* Streams tokens to stdout as they arrive. Citations are buffered and
|
|
7
|
+
* printed at the end so they don't garble the answer mid-stream. Pass
|
|
8
|
+
* --json to skip streaming and emit a single structured payload.
|
|
9
|
+
* Pass --plain to strip markdown formatting from the answer.
|
|
10
|
+
*
|
|
11
|
+
* Default render: TTY → ANSI bold/italic, pipe → raw markdown
|
|
12
|
+
* (so agents and downstream tools get clean markdown they can re-parse).
|
|
13
|
+
*/
|
|
14
|
+
import { requireKgConfig } from "../../config.js";
|
|
15
|
+
import { kgRequest, streamKgSSE } from "../../kg-client.js";
|
|
16
|
+
import { pickRenderMode, printJson, renderMarkdown, styleHeading, } from "../../kg-output.js";
|
|
17
|
+
export async function kgAsk(question, options) {
|
|
18
|
+
const cfg = requireKgConfig();
|
|
19
|
+
if (options.json) {
|
|
20
|
+
try {
|
|
21
|
+
const res = await kgRequest(cfg, "/api/qa", {
|
|
22
|
+
method: "POST",
|
|
23
|
+
body: { q: question, scope: options.scope },
|
|
24
|
+
});
|
|
25
|
+
printJson(res);
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
console.error(`✗ ${err.message}`);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const mode = pickRenderMode(options.plain);
|
|
34
|
+
const citations = [];
|
|
35
|
+
const entities = [];
|
|
36
|
+
// Per-line buffer so markdown spanning multiple SSE token chunks
|
|
37
|
+
// (e.g. `**Lenovo` then `**`) renders correctly. Tokens accumulate
|
|
38
|
+
// until a newline, then the completed line is rendered + flushed.
|
|
39
|
+
let buf = "";
|
|
40
|
+
const flushUpToLastNewline = () => {
|
|
41
|
+
const idx = buf.lastIndexOf("\n");
|
|
42
|
+
if (idx < 0)
|
|
43
|
+
return;
|
|
44
|
+
const toFlush = buf.slice(0, idx + 1);
|
|
45
|
+
buf = buf.slice(idx + 1);
|
|
46
|
+
process.stdout.write(renderMarkdown(toFlush, mode));
|
|
47
|
+
};
|
|
48
|
+
try {
|
|
49
|
+
await streamKgSSE(cfg, "/api/qa/stream", { q: question, scope: options.scope }, (ev) => {
|
|
50
|
+
if (ev.event === "token" || (!ev.event && ev.data)) {
|
|
51
|
+
// Server emits {"t": "..."} for tokens; older shapes used
|
|
52
|
+
// .text or .token. Fall back to raw string if parse fails.
|
|
53
|
+
let chunk;
|
|
54
|
+
try {
|
|
55
|
+
const parsed = JSON.parse(ev.data);
|
|
56
|
+
if (typeof parsed === "string")
|
|
57
|
+
chunk = parsed;
|
|
58
|
+
else
|
|
59
|
+
chunk = parsed?.t ?? parsed?.text ?? parsed?.token;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
chunk = ev.data;
|
|
63
|
+
}
|
|
64
|
+
if (chunk) {
|
|
65
|
+
buf += chunk;
|
|
66
|
+
flushUpToLastNewline();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else if (ev.event === "citation") {
|
|
70
|
+
try {
|
|
71
|
+
citations.push(JSON.parse(ev.data));
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
/* ignore */
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else if (ev.event === "entity") {
|
|
78
|
+
try {
|
|
79
|
+
entities.push(JSON.parse(ev.data));
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
/* ignore */
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else if (ev.event === "error") {
|
|
86
|
+
process.stderr.write(`\n✗ ${ev.data}\n`);
|
|
87
|
+
}
|
|
88
|
+
// meta and other unknown events: silently ignore
|
|
89
|
+
});
|
|
90
|
+
// Flush any remaining buffered text (when the answer doesn't end on \n)
|
|
91
|
+
if (buf.length > 0) {
|
|
92
|
+
process.stdout.write(renderMarkdown(buf, mode));
|
|
93
|
+
buf = "";
|
|
94
|
+
}
|
|
95
|
+
process.stdout.write("\n");
|
|
96
|
+
if (entities.length > 0) {
|
|
97
|
+
console.log(`\n${styleHeading("Entities mentioned:", mode)}`);
|
|
98
|
+
for (const e of entities) {
|
|
99
|
+
const link = e.slug ? ` (/entity/${e.slug})` : "";
|
|
100
|
+
console.log(` • ${e.name}${link}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (citations.length > 0) {
|
|
104
|
+
console.log(`\n${styleHeading("Sources:", mode)}`);
|
|
105
|
+
for (let i = 0; i < citations.length; i++) {
|
|
106
|
+
const c = citations[i];
|
|
107
|
+
const n = c.n ?? i + 1;
|
|
108
|
+
const label = c.snippet || c.predicate_label || c.predicate || c.label || "(no snippet)";
|
|
109
|
+
const url = c.source_url || c.url || "";
|
|
110
|
+
console.log(` [${n}] ${label}`);
|
|
111
|
+
if (url)
|
|
112
|
+
console.log(` ${url}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
console.error(`\n✗ ${err.message}`);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=ask.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ask.js","sourceRoot":"","sources":["../../../src/commands/kg/ask.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 4ort kg register | auth login | auth status
|
|
3
|
+
*
|
|
4
|
+
* register — TOFU one-shot, hits /api/v1/register, persists key + recovery code
|
|
5
|
+
* login — paste-an-existing-key flow for a second machine
|
|
6
|
+
* status — show current KG identity (server, prefix, tier)
|
|
7
|
+
*/
|
|
8
|
+
import readline from "node:readline/promises";
|
|
9
|
+
import { stdin as input, stdout as output } from "node:process";
|
|
10
|
+
import { kgRegisterRequest, kgRequest } from "../../kg-client.js";
|
|
11
|
+
import { loadConfig, saveKgConfig } from "../../config.js";
|
|
12
|
+
const DEFAULT_KG_SERVER = "https://4ort.xyz";
|
|
13
|
+
export async function kgRegister(options) {
|
|
14
|
+
const server = options.server || DEFAULT_KG_SERVER;
|
|
15
|
+
const rl = readline.createInterface({ input, output });
|
|
16
|
+
try {
|
|
17
|
+
const name = options.name || (await rl.question("Name for this key (e.g. 'my-agent'): ")).trim();
|
|
18
|
+
if (!name) {
|
|
19
|
+
console.error("name is required");
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
console.log(`\nRegistering on ${server}...`);
|
|
23
|
+
const res = await kgRegisterRequest(server, { name, email: options.email });
|
|
24
|
+
saveKgConfig({
|
|
25
|
+
apiKey: res.apiKey,
|
|
26
|
+
recoveryCode: res.recoveryCode,
|
|
27
|
+
server,
|
|
28
|
+
name: res.name,
|
|
29
|
+
tier: res.tier,
|
|
30
|
+
});
|
|
31
|
+
console.log("\n✓ Registered\n");
|
|
32
|
+
console.log(` API key: ${res.apiKey}`);
|
|
33
|
+
console.log(` Recovery code: ${res.recoveryCode}`);
|
|
34
|
+
console.log(` Tier: ${res.tier}\n`);
|
|
35
|
+
console.log("Save the recovery code somewhere safe — it's the ONLY way to rotate");
|
|
36
|
+
console.log("your key if it's lost. The API key is stored in ~/.4ort/config.json.\n");
|
|
37
|
+
console.log(`Try: 4ort kg ask "what's trending in tech right now?"`);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
console.error(`✗ ${err.message}`);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
rl.close();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export async function kgLogin(options) {
|
|
48
|
+
const server = options.server || DEFAULT_KG_SERVER;
|
|
49
|
+
const rl = readline.createInterface({ input, output });
|
|
50
|
+
try {
|
|
51
|
+
const apiKey = (await rl.question("Paste your 4ort.xyz API key: ")).trim();
|
|
52
|
+
if (!apiKey) {
|
|
53
|
+
console.error("API key required");
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
// Verify by hitting an authed endpoint with low cost.
|
|
57
|
+
console.log("Verifying...");
|
|
58
|
+
const cfg = { apiKey, server };
|
|
59
|
+
try {
|
|
60
|
+
await kgRequest(cfg, "/api/v1/trending", { query: { hours: 1, limit: 1 } });
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
console.error(`✗ Key rejected: ${err.message}`);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
saveKgConfig({ apiKey, server });
|
|
67
|
+
console.log("✓ Signed in. Try: 4ort kg ask \"what's hot in tech?\"");
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
rl.close();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export function kgStatus() {
|
|
74
|
+
const config = loadConfig();
|
|
75
|
+
if (!config?.kg?.apiKey && !config?.apiKey) {
|
|
76
|
+
console.log("Not signed in. Run: 4ort kg register");
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (config.kg?.apiKey) {
|
|
80
|
+
console.log(`Signed in to 4ort.xyz`);
|
|
81
|
+
console.log(` server: ${config.kg.server}`);
|
|
82
|
+
console.log(` key: ${config.kg.apiKey.slice(0, 12)}…`);
|
|
83
|
+
if (config.kg.name)
|
|
84
|
+
console.log(` name: ${config.kg.name}`);
|
|
85
|
+
if (config.kg.tier)
|
|
86
|
+
console.log(` tier: ${config.kg.tier}`);
|
|
87
|
+
}
|
|
88
|
+
else if (config.apiKey) {
|
|
89
|
+
console.log(`Using 4ort.net membership (federated)`);
|
|
90
|
+
console.log(` agent: ${config.agentName}`);
|
|
91
|
+
console.log(` key: ${config.apiKey.slice(0, 12)}…`);
|
|
92
|
+
console.log(` tier: bundled`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/commands/kg/auth.ts"],"names":[],"mappings":"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"}
|