@4ort/cli 0.8.4 → 0.8.6
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/dist/index.js +1 -1
- package/dist/peertube-client.js +40 -13
- package/dist/peertube-client.js.map +1 -1
- package/dist/peertube-refresh.test.d.ts +1 -0
- package/dist/peertube-refresh.test.js +95 -0
- package/dist/peertube-refresh.test.js.map +1 -0
- package/docs/MCP.md +77 -0
- package/docs/MOV.md +136 -0
- package/docs/VAULT.md +86 -0
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -34,7 +34,7 @@ const program = new Command();
|
|
|
34
34
|
program
|
|
35
35
|
.name("4ort")
|
|
36
36
|
.description("Unified CLI for the 4ort ecosystem — hosting, knowledge graph, and more")
|
|
37
|
-
.version("0.8.
|
|
37
|
+
.version("0.8.6");
|
|
38
38
|
// ─────────────────────────────────────────────────────────────────────
|
|
39
39
|
// 4ort.net subdomain hosting
|
|
40
40
|
// ─────────────────────────────────────────────────────────────────────
|
package/dist/peertube-client.js
CHANGED
|
@@ -62,19 +62,46 @@ export async function getToken(server, client, username, password) {
|
|
|
62
62
|
return { accessToken: j.access_token, refreshToken: j.refresh_token };
|
|
63
63
|
}
|
|
64
64
|
async function refresh(cfg) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
65
|
+
let next;
|
|
66
|
+
try {
|
|
67
|
+
const body = new URLSearchParams({
|
|
68
|
+
client_id: cfg.clientId,
|
|
69
|
+
client_secret: cfg.clientSecret,
|
|
70
|
+
grant_type: "refresh_token",
|
|
71
|
+
refresh_token: cfg.refreshToken,
|
|
72
|
+
});
|
|
73
|
+
const j = await asJson(await fetch(`${base(cfg.server)}/api/v1/users/token`, {
|
|
74
|
+
method: "POST",
|
|
75
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
76
|
+
body,
|
|
77
|
+
}));
|
|
78
|
+
next = { ...cfg, accessToken: j.access_token, refreshToken: j.refresh_token };
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
// Refresh tokens are single-use: if a rotated token is ever lost (e.g. a
|
|
82
|
+
// read-only config in a container), refresh dies with invalid_grant
|
|
83
|
+
// forever. Recover with a full password grant when env creds exist.
|
|
84
|
+
const username = process.env.FORT_MOV_USERNAME || cfg.username;
|
|
85
|
+
const password = process.env.FORT_MOV_PASSWORD;
|
|
86
|
+
if (!username || !password)
|
|
87
|
+
throw err;
|
|
88
|
+
const client = await getOAuthClient(cfg.server);
|
|
89
|
+
const tok = await getToken(cfg.server, client, username, password);
|
|
90
|
+
next = {
|
|
91
|
+
...cfg,
|
|
92
|
+
clientId: client.clientId,
|
|
93
|
+
clientSecret: client.clientSecret,
|
|
94
|
+
accessToken: tok.accessToken,
|
|
95
|
+
refreshToken: tok.refreshToken,
|
|
96
|
+
username,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
saveMovConfig(next);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// Read-only config (containerized factory) — keep going with in-memory tokens.
|
|
104
|
+
}
|
|
78
105
|
return next;
|
|
79
106
|
}
|
|
80
107
|
/** Authenticated JSON request with one transparent refresh-on-401 retry. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"peertube-client.js","sourceRoot":"","sources":["../src/peertube-client.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"peertube-client.js","sourceRoot":"","sources":["../src/peertube-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { createServer } from "node:http";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import os from "node:os";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
// Sandbox the config file BEFORE importing anything that touches config.ts.
|
|
8
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "fort-refresh-"));
|
|
9
|
+
process.env.HOME = tmp; // CONFIG_DIR derives from os.homedir()
|
|
10
|
+
const { ptRequest } = await import("./peertube-client.js");
|
|
11
|
+
function listen(handler) {
|
|
12
|
+
return new Promise((resolve) => {
|
|
13
|
+
const srv = createServer(handler);
|
|
14
|
+
srv.listen(0, "127.0.0.1", () => {
|
|
15
|
+
const a = srv.address();
|
|
16
|
+
resolve({ url: `http://127.0.0.1:${a.port}`, close: () => srv.close() });
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
test("dead refresh token recovers via password grant when env creds exist", async () => {
|
|
21
|
+
const grants = [];
|
|
22
|
+
const m = await listen(async (req, res) => {
|
|
23
|
+
res.setHeader("content-type", "application/json");
|
|
24
|
+
if (req.url === "/api/v1/users/token" && req.method === "POST") {
|
|
25
|
+
const chunks = [];
|
|
26
|
+
for await (const c of req)
|
|
27
|
+
chunks.push(c);
|
|
28
|
+
const body = new URLSearchParams(Buffer.concat(chunks).toString());
|
|
29
|
+
grants.push(body.get("grant_type"));
|
|
30
|
+
if (body.get("grant_type") === "refresh_token") {
|
|
31
|
+
res.statusCode = 400;
|
|
32
|
+
return res.end(JSON.stringify({ code: "invalid_grant" }));
|
|
33
|
+
}
|
|
34
|
+
return res.end(JSON.stringify({ access_token: "fresh-atok", refresh_token: "fresh-rtok" }));
|
|
35
|
+
}
|
|
36
|
+
if (req.url === "/api/v1/oauth-clients/local") {
|
|
37
|
+
return res.end(JSON.stringify({ client_id: "cid2", client_secret: "csec2" }));
|
|
38
|
+
}
|
|
39
|
+
if (req.url === "/api/v1/users/me") {
|
|
40
|
+
const auth = req.headers.authorization ?? "";
|
|
41
|
+
if (auth !== "Bearer fresh-atok") {
|
|
42
|
+
res.statusCode = 401;
|
|
43
|
+
return res.end("{}");
|
|
44
|
+
}
|
|
45
|
+
return res.end(JSON.stringify({ ok: true }));
|
|
46
|
+
}
|
|
47
|
+
res.statusCode = 404;
|
|
48
|
+
res.end("{}");
|
|
49
|
+
});
|
|
50
|
+
process.env.FORT_MOV_USERNAME = "video-factory";
|
|
51
|
+
process.env.FORT_MOV_PASSWORD = "pw123";
|
|
52
|
+
try {
|
|
53
|
+
const cfg = {
|
|
54
|
+
server: m.url,
|
|
55
|
+
accessToken: "stale-atok",
|
|
56
|
+
refreshToken: "dead-rtok",
|
|
57
|
+
clientId: "cid",
|
|
58
|
+
clientSecret: "csec",
|
|
59
|
+
};
|
|
60
|
+
const out = await ptRequest(cfg, "/api/v1/users/me");
|
|
61
|
+
assert.equal(out.ok, true);
|
|
62
|
+
// It tried the refresh grant first, then fell back to the password grant.
|
|
63
|
+
assert.deepEqual(grants, ["refresh_token", "password"]);
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
delete process.env.FORT_MOV_USERNAME;
|
|
67
|
+
delete process.env.FORT_MOV_PASSWORD;
|
|
68
|
+
m.close();
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
test("dead refresh token with no env creds still throws", async () => {
|
|
72
|
+
const m = await listen((req, res) => {
|
|
73
|
+
res.setHeader("content-type", "application/json");
|
|
74
|
+
if (req.url === "/api/v1/users/token") {
|
|
75
|
+
res.statusCode = 400;
|
|
76
|
+
return res.end(JSON.stringify({ code: "invalid_grant" }));
|
|
77
|
+
}
|
|
78
|
+
res.statusCode = 401;
|
|
79
|
+
res.end("{}");
|
|
80
|
+
});
|
|
81
|
+
try {
|
|
82
|
+
const cfg = {
|
|
83
|
+
server: m.url,
|
|
84
|
+
accessToken: "stale",
|
|
85
|
+
refreshToken: "dead",
|
|
86
|
+
clientId: "c",
|
|
87
|
+
clientSecret: "s",
|
|
88
|
+
};
|
|
89
|
+
await assert.rejects(ptRequest(cfg, "/api/v1/users/me"), /400/);
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
m.close();
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
//# sourceMappingURL=peertube-refresh.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peertube-refresh.test.js","sourceRoot":"","sources":["../src/peertube-refresh.test.ts"],"names":[],"mappings":"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"}
|
package/docs/MCP.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# 🧠 `4ort mcp` — Run the CLI as an MCP server
|
|
2
|
+
|
|
3
|
+
`@4ort/cli` is **both a CLI and an MCP server** in the same binary. Every
|
|
4
|
+
subcommand surface (`kg`, `mov`, `web`, `vault run`, etc.) becomes an MCP tool
|
|
5
|
+
when the CLI is launched in MCP mode — so any MCP-speaking agent gets the
|
|
6
|
+
entire galaxy toolkit for free, without re-implementing anything.
|
|
7
|
+
|
|
8
|
+
## Two modes
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
4ort mcp stdio # local: pipe to a Claude/agent runner via stdin/stdout
|
|
12
|
+
4ort mcp serve # network: expose the MCP server over HTTP (for remote agents)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## stdio mode (most common)
|
|
16
|
+
|
|
17
|
+
Wire the CLI as an MCP server in a Claude Desktop / Claude Code / Cursor / any
|
|
18
|
+
MCP client config. Example (Claude Code-style):
|
|
19
|
+
|
|
20
|
+
```jsonc
|
|
21
|
+
{
|
|
22
|
+
"mcpServers": {
|
|
23
|
+
"4ort": {
|
|
24
|
+
"command": "4ort",
|
|
25
|
+
"args": ["mcp", "stdio"]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The agent will discover tools like:
|
|
32
|
+
- `4ort.kg.search`, `4ort.kg.ask`, `4ort.kg.entity`, `4ort.kg.match`,
|
|
33
|
+
`4ort.kg.popularity`, `4ort.kg.trending`, `4ort.kg.agent-context`,
|
|
34
|
+
`4ort.kg.article-context`
|
|
35
|
+
- `4ort.mov.publish`, `4ort.mov.render`, `4ort.mov.list`
|
|
36
|
+
- `4ort.web.get`
|
|
37
|
+
- `4ort.search` (smart router)
|
|
38
|
+
- `4ort.run` (vault-resolved subprocess)
|
|
39
|
+
|
|
40
|
+
Identity is the CLI's existing `~/.4ort/config.json` — whichever keys you've
|
|
41
|
+
configured (4ort.net, kg, vault) flow through to the agent.
|
|
42
|
+
|
|
43
|
+
## serve mode (network)
|
|
44
|
+
|
|
45
|
+
For remote agents or shared infrastructure:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
4ort mcp serve --port 8080
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Exposes the same tool surface over HTTP transport. Pair with reverse-proxy +
|
|
52
|
+
auth as needed (the CLI itself doesn't add network auth — bring your own).
|
|
53
|
+
|
|
54
|
+
## Where this fits in the galaxy
|
|
55
|
+
|
|
56
|
+
- **Mission Control panels (ADR-0002 MCP-as-panels)** — the 4ort.ai agent can
|
|
57
|
+
call `4ort.kg.*` and `4ort.mov.*` tools directly via this surface; sidebar
|
|
58
|
+
panels render the results.
|
|
59
|
+
- **The code-command sandbox** ships `@4ort/cli` baked into the image so every
|
|
60
|
+
spawned agent has these tools natively, no MCP wiring needed inside the
|
|
61
|
+
sandbox itself.
|
|
62
|
+
- **The future "MCP Uplink"** property (galaxy plan
|
|
63
|
+
`plans/MCP_UPLINK_PLAN.md`) mounts `@4ort/cli` alongside open MCP servers
|
|
64
|
+
(Gmail, Slack, GitHub, etc.) into a unified MCP gateway.
|
|
65
|
+
|
|
66
|
+
## Composing with the vault
|
|
67
|
+
|
|
68
|
+
`4ort run` is also exposed as an MCP tool — meaning an agent can ask the CLI to
|
|
69
|
+
**run a subprocess with vault-resolved secrets** without ever seeing the raw
|
|
70
|
+
values. Great for "run my SQL migration with the prod DB password" workflows
|
|
71
|
+
where the agent should never touch the secret.
|
|
72
|
+
|
|
73
|
+
## Versioning / surface stability
|
|
74
|
+
|
|
75
|
+
The MCP tool names and schemas track the CLI's commander.js definitions
|
|
76
|
+
directly. When a new subcommand lands in the CLI, it's available as an MCP
|
|
77
|
+
tool in the next published version (`npm install -g @4ort/cli@latest`).
|
package/docs/MOV.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# 🎬 `4ort mov` — Publishing video to 4ort.mov
|
|
2
|
+
|
|
3
|
+
Since `@4ort/cli@0.6.0` (`publish`) + `0.7.0` (`render`). Two complementary
|
|
4
|
+
flows for getting video onto the galaxy's PeerTube host (4ort.mov).
|
|
5
|
+
|
|
6
|
+
## Setup
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
# one-time: mint your OWN 4ort.mov account + render token, then sign in with it
|
|
10
|
+
4ort provision run video
|
|
11
|
+
4ort mov login --provisioned
|
|
12
|
+
|
|
13
|
+
# or sign in to an existing account interactively / non-interactively
|
|
14
|
+
4ort mov login # prompts for username + password
|
|
15
|
+
4ort mov login -u <user> -p <pass> # non-interactive (agents/CI; or env
|
|
16
|
+
# FORT_MOV_USERNAME / FORT_MOV_PASSWORD)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
All credentials persist to `~/.4ort/config.json` (mode `0600`). The CLI
|
|
20
|
+
authenticates via PeerTube's OAuth on `/api/*`, so it never needs a separate
|
|
21
|
+
site/gate credential.
|
|
22
|
+
|
|
23
|
+
## Accounts & channels (per-user)
|
|
24
|
+
|
|
25
|
+
`4ort mov` is **per-account**. Every user/agent has their own 4ort.mov account,
|
|
26
|
+
so videos publish under **their own channel** — not a shared one.
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# one-time: mint your own account + render token
|
|
30
|
+
4ort provision run video
|
|
31
|
+
4ort mov login --provisioned # or: 4ort mov login -u <user> -p <pass>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Which channel does a publish go to?**
|
|
35
|
+
|
|
36
|
+
- No `--channel` → your account's **default (first) channel**.
|
|
37
|
+
- `--channel <name>` → a channel **you own** by that name/displayName (the
|
|
38
|
+
command errors and lists your channels if there's no match).
|
|
39
|
+
- `4ort mov channels --create <name>` → make a new channel under your account.
|
|
40
|
+
|
|
41
|
+
So two agents running `4ort mov publish` land in two different channels — each
|
|
42
|
+
writes only to its own account. (Admin/`root` is just another account; the
|
|
43
|
+
autonomous pipelines historically published as `root`, but provisioned agents
|
|
44
|
+
get their own.)
|
|
45
|
+
|
|
46
|
+
## Two flows
|
|
47
|
+
|
|
48
|
+
### Flow A — Direct publish (you have an MP4)
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
4ort mov publish ./my-video.mp4 \
|
|
52
|
+
--title "My Video" \
|
|
53
|
+
--channel galaxy \
|
|
54
|
+
--description "..." \
|
|
55
|
+
--thumbnail ./thumb.png \
|
|
56
|
+
--privacy unlisted
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- Single-request multipart upload (`POST /api/v1/videos/upload`)
|
|
60
|
+
- Prints the watch URL on success
|
|
61
|
+
- Privacy: `public` / `unlisted` / `private` / `internal` (default `unlisted`)
|
|
62
|
+
|
|
63
|
+
### Flow B — Render-and-publish (you have a HyperFrames composition dir)
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
4ort mov render ./my-composition --publish \
|
|
67
|
+
--title "My Composition" \
|
|
68
|
+
--channel galaxy
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
End-to-end agent publish chain in one command:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
local dir of HyperFrames composition
|
|
75
|
+
│
|
|
76
|
+
▼ tar (gitignore-respecting)
|
|
77
|
+
▼
|
|
78
|
+
POST to factory.4ort.mov (video-factory)
|
|
79
|
+
│
|
|
80
|
+
▼ async job (poll for status)
|
|
81
|
+
▼
|
|
82
|
+
MP4 + preview frames back
|
|
83
|
+
│
|
|
84
|
+
▼ (if --publish)
|
|
85
|
+
▼
|
|
86
|
+
4ort mov publish (under-the-hood)
|
|
87
|
+
│
|
|
88
|
+
▼
|
|
89
|
+
watch URL printed
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
This is the **path that 4ort.ai's agents inside the code-command sandbox use**
|
|
93
|
+
to publish content end-to-end — the bridge spec is in `~/ai/code-command/docs/`
|
|
94
|
+
and the engine is at `~/ai/4ort.mov/engine/`.
|
|
95
|
+
|
|
96
|
+
## Other commands
|
|
97
|
+
|
|
98
|
+
| Command | What it does |
|
|
99
|
+
|---|---|
|
|
100
|
+
| `4ort mov list` | List your videos on 4ort.mov |
|
|
101
|
+
| `4ort mov channels` | List channels; `--create <name>` to make one |
|
|
102
|
+
| `4ort mov delete <id>` | Delete a video (with confirm) |
|
|
103
|
+
|
|
104
|
+
## Where this fits in the galaxy
|
|
105
|
+
|
|
106
|
+
| Property | Role |
|
|
107
|
+
|---|---|
|
|
108
|
+
| **4ort.mov** | The PeerTube host (`~/ai/4ort.mov/`) — final destination for all videos |
|
|
109
|
+
| **video-factory** | Render engine at `factory.4ort.mov` (lives in `~/ai/4ort.mov/engine/`) — turns HyperFrames compositions into MP4s |
|
|
110
|
+
| **4ort-tv** | Long-form video pipeline — outputs HyperFrames compositions that get rendered + published via this CLI |
|
|
111
|
+
| **4ort.stream** | Short-form autonomous pipeline — outputs MP4s directly; uses `4ort mov publish` (Flow A) |
|
|
112
|
+
| **code-command sandbox** | Ships `@4ort/cli` baked in; the `4ort mov render --publish` chain is how spawned agents publish |
|
|
113
|
+
|
|
114
|
+
## Auth model
|
|
115
|
+
|
|
116
|
+
The CLI talks to PeerTube exclusively over `/api/*` using an OAuth bearer
|
|
117
|
+
token (password grant at `4ort mov login`, transparently refreshed on 401).
|
|
118
|
+
Any human-facing password wall on `4ort.mov` carves out `/api/*` (see
|
|
119
|
+
`~/ai/4ort.mov/docs/AS-BUILT.md`, ADR-0009), so **automated publishes need no
|
|
120
|
+
separate gate credential** — the bearer token is the only auth the CLI sends.
|
|
121
|
+
Per-property security posture is in
|
|
122
|
+
`~/ai/4ort-galaxy/property-notes/4ort-mov.md`.
|
|
123
|
+
|
|
124
|
+
## Versioning / what's new
|
|
125
|
+
|
|
126
|
+
- **0.6.0** — `4ort mov publish`: PeerTube upload + login + list/channels/delete
|
|
127
|
+
- **0.7.0** — `4ort mov render`: dir → video-factory → optional publish in one command
|
|
128
|
+
- **0.8.0** — `4ort provision run video` mints a per-agent 4ort.mov account + render
|
|
129
|
+
token; `4ort mov login --provisioned` signs in with it
|
|
130
|
+
- **0.8.4** — shipped a verified, lint-passing render starter template at
|
|
131
|
+
`examples/fact-short.html` (`4ort mov render examples/fact-short.html -q draft`)
|
|
132
|
+
- **0.8.5** — publish reliability: PeerTube token refresh now recovers from an
|
|
133
|
+
expired/rotated refresh token via a password-grant fallback (env or stored
|
|
134
|
+
credentials), so long-lived render hosts keep publishing
|
|
135
|
+
- **0.8.6** — docs: documented the per-account channel model + provisioned login,
|
|
136
|
+
corrected the upload method (multipart, not resumable), refreshed the auth model
|
package/docs/VAULT.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# 🔑 `4ort vault` + `4ort run` — Secrets layer
|
|
2
|
+
|
|
3
|
+
Since `@4ort/cli@0.5.0`. The galaxy's secrets layer, modeled directly on
|
|
4
|
+
**1Password's `op run`** pattern: secrets live server-side in the 4ort.ai
|
|
5
|
+
vault, the CLI fetches them at invocation time, and they're **injected
|
|
6
|
+
into the child process only** — never written to disk.
|
|
7
|
+
|
|
8
|
+
## The model in one line
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
secret ref in env → 4ort run resolves it → child process gets the real value → exit
|
|
12
|
+
↑
|
|
13
|
+
(plaintext never touches disk)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Setup (one time per machine)
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# 1. Get a vault token from Mission Control (4ort.ai → Secrets panel)
|
|
20
|
+
# The token is prefixed `4vt_…`
|
|
21
|
+
|
|
22
|
+
# 2. Link this machine
|
|
23
|
+
4ort vault login
|
|
24
|
+
# → paste the 4vt_ token when prompted
|
|
25
|
+
|
|
26
|
+
# 3. Verify
|
|
27
|
+
4ort vault status
|
|
28
|
+
# → prints: server, vault user, token (masked), connection OK
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Token gets persisted to `~/.4ort/config.json` under `vault.token` (file mode `0600`).
|
|
32
|
+
Vault server defaults to `https://4ort.ai`.
|
|
33
|
+
|
|
34
|
+
## Using it
|
|
35
|
+
|
|
36
|
+
### Reference secrets in env at runtime
|
|
37
|
+
|
|
38
|
+
The reference shape is `4ort://service[/name]`:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# .env or shell:
|
|
42
|
+
OPENAI_API_KEY=4ort://openai
|
|
43
|
+
DATABASE_URL=4ort://postgres/prod
|
|
44
|
+
SLACK_TOKEN=4ort://slack/team-a
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Run a command with refs resolved
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
4ort run -- python my_script.py
|
|
51
|
+
4ort run -- npm start
|
|
52
|
+
4ort run -- /usr/bin/env # see what got injected (for debugging)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
At invocation:
|
|
56
|
+
1. CLI scans the env of the parent shell + any `.env` file in cwd
|
|
57
|
+
2. For each `4ort://…` ref, fetches the real value from the vault
|
|
58
|
+
3. Spawns the child process with the real values in its env
|
|
59
|
+
4. Plaintext exists only in the child's memory; never lands on disk
|
|
60
|
+
|
|
61
|
+
## Other commands
|
|
62
|
+
|
|
63
|
+
| Command | What it does |
|
|
64
|
+
|---|---|
|
|
65
|
+
| `4ort vault login` | Paste a `4vt_` token; persist to `~/.4ort/config.json` |
|
|
66
|
+
| `4ort vault status` | Show current vault identity + connection check |
|
|
67
|
+
| `4ort vault logout` | Wipe the vault token (other identities preserved) |
|
|
68
|
+
|
|
69
|
+
## Where this fits in the galaxy
|
|
70
|
+
|
|
71
|
+
- **Same vault backend as the 4ort.ai Secrets panel** — the CLI is a peer client;
|
|
72
|
+
every UI write is visible to `4ort run` instantly.
|
|
73
|
+
- **The code-command sandbox** uses the CLI inside spawned interpreters via
|
|
74
|
+
`FORT_CLI_CONFIG_B64` env (the config is materialized into the sandbox at
|
|
75
|
+
spawn-time so the sandboxed agent has vault access without seeing the token).
|
|
76
|
+
- **The future "MCP Uplink"** property layers on top: third-party OAuth tokens
|
|
77
|
+
(Gmail / Slack / GitHub) get stored in the same vault, keyed by galaxy JWT
|
|
78
|
+
user-id. See `plans/MCP_UPLINK_PLAN.md` in the galaxy repo.
|
|
79
|
+
|
|
80
|
+
## Security posture
|
|
81
|
+
|
|
82
|
+
- Vault token is the only persistent secret on the machine
|
|
83
|
+
- Per-service secrets are fetched fresh per `4ort run` invocation
|
|
84
|
+
- `0600` perms on `~/.4ort/config.json`
|
|
85
|
+
- Never echo `4ort vault status` output into logs (token is masked but the
|
|
86
|
+
shape gives away the service has one)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@4ort/cli",
|
|
3
|
-
"version": "0.8.
|
|
4
|
-
"description": "Unified CLI for the 4ort ecosystem
|
|
3
|
+
"version": "0.8.6",
|
|
4
|
+
"description": "Unified CLI for the 4ort ecosystem — 4ort.net hosting, knowledge graph, and more",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"4ort": "./dist/index.js"
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
11
11
|
"README.md",
|
|
12
|
-
"examples"
|
|
12
|
+
"examples",
|
|
13
|
+
"docs"
|
|
13
14
|
],
|
|
14
15
|
"scripts": {
|
|
15
16
|
"dev": "tsx src/index.ts",
|