@emaxe/oa 0.1.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 +34 -0
- package/dist/client.js +34 -0
- package/dist/client.js.map +1 -0
- package/dist/commands/artifacts.js +122 -0
- package/dist/commands/artifacts.js.map +1 -0
- package/dist/commands/login.js +55 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/share.js +46 -0
- package/dist/commands/share.js.map +1 -0
- package/dist/config.js +32 -0
- package/dist/config.js.map +1 -0
- package/dist/index.js +57 -0
- package/dist/index.js.map +1 -0
- package/dist/scopes.js +13 -0
- package/dist/scopes.js.map +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# open-artifacts
|
|
2
|
+
|
|
3
|
+
CLI for [Open Artifacts](https://github.com/emaxe/open-artifacts) — a self-hosted, open
|
|
4
|
+
alternative to Claude Artifacts. Publish HTML, Markdown, Mermaid, or SVG content to your own
|
|
5
|
+
instance and get back a shareable link, from any AI agent or script.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @emaxe/oa
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
oa login --server https://artifacts.your-company.com # one-time device-flow authorization
|
|
15
|
+
oa push report.html --title "Q3 Report" --share # publish + print a share URL
|
|
16
|
+
oa list # see what you've published
|
|
17
|
+
oa get <artifact-id> -o report.html # fetch content back
|
|
18
|
+
oa share <artifact-id> --password "..." --expires 7d # a password-protected, expiring link
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Every command supports `--json` for machine-readable output. Run `oa --help` or `oa <command>
|
|
22
|
+
--help` for the full option list.
|
|
23
|
+
|
|
24
|
+
Credentials are saved to `~/.config/open-artifacts/credentials.json` (mode `600`) after `oa
|
|
25
|
+
login`. Alternatively, set `OA_TOKEN` (and `OA_SERVER`) as environment variables to skip the
|
|
26
|
+
device flow entirely — useful for CI or non-interactive agents that already have a key.
|
|
27
|
+
|
|
28
|
+
This CLI requires an Open Artifacts server to talk to — see the
|
|
29
|
+
[main repository](https://github.com/emaxe/open-artifacts) for how to self-host one via Docker
|
|
30
|
+
Compose.
|
|
31
|
+
|
|
32
|
+
## License
|
|
33
|
+
|
|
34
|
+
MIT
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export class CliApiError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
status;
|
|
4
|
+
constructor(code, message, status) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.code = code;
|
|
7
|
+
this.status = status;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export function makeClient(creds) {
|
|
11
|
+
const base = `${creds.server.replace(/\/$/, "")}/api/v1`;
|
|
12
|
+
async function request(path, options = {}) {
|
|
13
|
+
const res = await fetch(`${base}${path}`, {
|
|
14
|
+
...options,
|
|
15
|
+
headers: {
|
|
16
|
+
"Content-Type": "application/json",
|
|
17
|
+
Authorization: `Bearer ${creds.token}`,
|
|
18
|
+
...options.headers,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
const body = (await res.json().catch(() => ({})));
|
|
22
|
+
if (!res.ok) {
|
|
23
|
+
throw new CliApiError(body?.error?.code ?? "unknown_error", body?.error?.message ?? res.statusText, res.status);
|
|
24
|
+
}
|
|
25
|
+
return body;
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
get: (path) => request(path),
|
|
29
|
+
post: (path, body) => request(path, { method: "POST", body: body ? JSON.stringify(body) : undefined }),
|
|
30
|
+
patch: (path, body, headers) => request(path, { method: "PATCH", body: JSON.stringify(body), headers }),
|
|
31
|
+
delete: (path) => request(path, { method: "DELETE" }),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,WAAY,SAAQ,KAAK;IACjB;IAAsC;IAAzD,YAAmB,IAAY,EAAE,OAAe,EAAS,MAAc;QACrE,KAAK,CAAC,OAAO,CAAC,CAAC;QADE,SAAI,GAAJ,IAAI,CAAQ;QAA0B,WAAM,GAAN,MAAM,CAAQ;IAEvE,CAAC;CACF;AAED,MAAM,UAAU,UAAU,CAAC,KAAkB;IAC3C,MAAM,IAAI,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC;IAEzD,KAAK,UAAU,OAAO,CAAI,IAAY,EAAE,UAAuB,EAAE;QAC/D,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,EAAE;YACxC,GAAG,OAAO;YACV,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,KAAK,CAAC,KAAK,EAAE;gBACtC,GAAG,OAAO,CAAC,OAAO;aACnB;SACF,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAoD,CAAC;QACrG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,IAAI,eAAe,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,IAAI,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;QAClH,CAAC;QACD,OAAO,IAAS,CAAC;IACnB,CAAC;IAED,OAAO;QACL,GAAG,EAAE,CAAI,IAAY,EAAE,EAAE,CAAC,OAAO,CAAI,IAAI,CAAC;QAC1C,IAAI,EAAE,CAAI,IAAY,EAAE,IAAc,EAAE,EAAE,CAAC,OAAO,CAAI,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;QAC9H,KAAK,EAAE,CAAI,IAAY,EAAE,IAAc,EAAE,OAAgC,EAAE,EAAE,CAC3E,OAAO,CAAI,IAAI,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;QAC5E,MAAM,EAAE,CAAI,IAAY,EAAE,EAAE,CAAC,OAAO,CAAI,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;KACpE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { extname, basename } from "node:path";
|
|
3
|
+
import { requireCredentials } from "../config.js";
|
|
4
|
+
import { makeClient, CliApiError } from "../client.js";
|
|
5
|
+
function inferKind(filePath) {
|
|
6
|
+
const ext = extname(filePath).toLowerCase();
|
|
7
|
+
if (ext === ".md" || ext === ".markdown")
|
|
8
|
+
return "markdown";
|
|
9
|
+
if (ext === ".svg")
|
|
10
|
+
return "svg";
|
|
11
|
+
if (ext === ".mmd" || ext === ".mermaid")
|
|
12
|
+
return "mermaid";
|
|
13
|
+
return "html";
|
|
14
|
+
}
|
|
15
|
+
function die(message) {
|
|
16
|
+
console.error(message);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
export async function listCommand(opts) {
|
|
20
|
+
const creds = requireCredentials();
|
|
21
|
+
const client = makeClient(creds);
|
|
22
|
+
try {
|
|
23
|
+
const data = await client.get(`/artifacts?orgId=${creds.orgId}`);
|
|
24
|
+
if (opts.json) {
|
|
25
|
+
console.log(JSON.stringify(data.artifacts, null, 2));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
for (const a of data.artifacts) {
|
|
29
|
+
console.log(`${a.id} ${a.kind.padEnd(9)} ${a.visibility.padEnd(8)} ${a.title}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
handleError(err);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export async function pushCommand(filePath, opts) {
|
|
37
|
+
if (!existsSync(filePath))
|
|
38
|
+
die(`File not found: ${filePath}`);
|
|
39
|
+
const content = readFileSync(filePath, "utf8");
|
|
40
|
+
const kind = opts.kind ?? inferKind(filePath);
|
|
41
|
+
const title = opts.title ?? basename(filePath);
|
|
42
|
+
const creds = requireCredentials();
|
|
43
|
+
const client = makeClient(creds);
|
|
44
|
+
try {
|
|
45
|
+
let artifactId = opts.id;
|
|
46
|
+
if (artifactId) {
|
|
47
|
+
await client.patch(`/artifacts/${artifactId}`, { content, message: opts.message });
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
const res = await client.post(`/artifacts?orgId=${creds.orgId}`, {
|
|
51
|
+
title,
|
|
52
|
+
kind,
|
|
53
|
+
content,
|
|
54
|
+
visibility: "private",
|
|
55
|
+
});
|
|
56
|
+
artifactId = res.artifact.id;
|
|
57
|
+
}
|
|
58
|
+
const result = { artifactId };
|
|
59
|
+
if (opts.share) {
|
|
60
|
+
const shareRes = await client.post(`/artifacts/${artifactId}/shares`, {
|
|
61
|
+
mode: opts.password ? "password" : "public",
|
|
62
|
+
password: opts.password,
|
|
63
|
+
});
|
|
64
|
+
result.shareUrl = shareRes.url;
|
|
65
|
+
}
|
|
66
|
+
if (opts.json) {
|
|
67
|
+
console.log(JSON.stringify(result, null, 2));
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
console.log(`Artifact: ${artifactId}`);
|
|
71
|
+
if (result.shareUrl)
|
|
72
|
+
console.log(`Share URL: ${result.shareUrl}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
handleError(err);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export async function getCommand(id, opts) {
|
|
80
|
+
const creds = requireCredentials();
|
|
81
|
+
const client = makeClient(creds);
|
|
82
|
+
try {
|
|
83
|
+
const data = await client.get(`/artifacts/${id}`);
|
|
84
|
+
if (opts.output) {
|
|
85
|
+
writeFileSync(opts.output, data.content, "utf8");
|
|
86
|
+
console.log(`Saved to ${opts.output}`);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
process.stdout.write(data.content);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
handleError(err);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export async function rmCommand(id) {
|
|
97
|
+
const creds = requireCredentials();
|
|
98
|
+
const client = makeClient(creds);
|
|
99
|
+
try {
|
|
100
|
+
await client.delete(`/artifacts/${id}`);
|
|
101
|
+
console.log(`Deleted ${id}`);
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
handleError(err);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
export function handleError(err) {
|
|
108
|
+
if (err instanceof CliApiError) {
|
|
109
|
+
if (err.code === "key_expired") {
|
|
110
|
+
die("Your API key has expired. Run `oa login` again.");
|
|
111
|
+
}
|
|
112
|
+
if (err.code === "quota_exceeded") {
|
|
113
|
+
die("Organization storage quota exceeded.");
|
|
114
|
+
}
|
|
115
|
+
if (err.code === "version_conflict") {
|
|
116
|
+
die("Someone else changed this artifact since you last read it (409). Fetch the latest with `oa get` and retry.");
|
|
117
|
+
}
|
|
118
|
+
die(`Error (${err.code}): ${err.message}`);
|
|
119
|
+
}
|
|
120
|
+
throw err;
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=artifacts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../../src/commands/artifacts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { hostname } from "node:os";
|
|
2
|
+
import { saveCredentials } from "../config.js";
|
|
3
|
+
function sleep(ms) {
|
|
4
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
5
|
+
}
|
|
6
|
+
export async function login(opts) {
|
|
7
|
+
const server = opts.server.replace(/\/$/, "");
|
|
8
|
+
const agentName = opts.name ?? `cli-${hostname()}`;
|
|
9
|
+
const codeRes = await fetch(`${server}/api/v1/oauth/device/code`, {
|
|
10
|
+
method: "POST",
|
|
11
|
+
headers: { "Content-Type": "application/json" },
|
|
12
|
+
body: JSON.stringify({ agentName, scopes: opts.scopes }),
|
|
13
|
+
});
|
|
14
|
+
if (!codeRes.ok) {
|
|
15
|
+
console.error(`Failed to start device authorization: ${codeRes.status} ${await codeRes.text()}`);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
const device = (await codeRes.json());
|
|
19
|
+
console.log(`\nTo authorize this device, open:\n\n ${device.verification_uri_complete}\n`);
|
|
20
|
+
console.log(`If prompted, enter code: ${device.user_code}\n`);
|
|
21
|
+
console.log("Waiting for approval...");
|
|
22
|
+
const deadline = Date.now() + device.expires_in * 1000;
|
|
23
|
+
let interval = device.interval * 1000;
|
|
24
|
+
while (Date.now() < deadline) {
|
|
25
|
+
await sleep(interval);
|
|
26
|
+
const tokenRes = await fetch(`${server}/api/v1/oauth/device/token`, {
|
|
27
|
+
method: "POST",
|
|
28
|
+
headers: { "Content-Type": "application/json" },
|
|
29
|
+
body: JSON.stringify({ deviceCode: device.device_code, grantType: "urn:ietf:params:oauth:grant-type:device_code" }),
|
|
30
|
+
});
|
|
31
|
+
const body = (await tokenRes.json());
|
|
32
|
+
if ("api_key" in body) {
|
|
33
|
+
saveCredentials({ server, token: body.api_key, agentId: body.agent_id, orgId: body.org_id, expiresAt: body.expires_at });
|
|
34
|
+
console.log(`\nLogged in. Credentials saved to ~/.config/open-artifacts/credentials.json`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (body.error === "slow_down") {
|
|
38
|
+
interval += 5000;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (body.error === "authorization_pending")
|
|
42
|
+
continue;
|
|
43
|
+
if (body.error === "access_denied") {
|
|
44
|
+
console.error("Authorization was denied.");
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
if (body.error === "expired_token") {
|
|
48
|
+
console.error("Device code expired. Run `oa login` again.");
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
console.error("Timed out waiting for approval.");
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { requireCredentials } from "../config.js";
|
|
2
|
+
import { makeClient } from "../client.js";
|
|
3
|
+
import { handleError } from "./artifacts.js";
|
|
4
|
+
export async function shareCommand(id, opts) {
|
|
5
|
+
const creds = requireCredentials();
|
|
6
|
+
const client = makeClient(creds);
|
|
7
|
+
try {
|
|
8
|
+
const res = await client.post(`/artifacts/${id}/shares`, {
|
|
9
|
+
mode: opts.password ? "password" : "public",
|
|
10
|
+
password: opts.password,
|
|
11
|
+
expires: opts.expires,
|
|
12
|
+
versionNo: opts.version ? Number(opts.version) : undefined,
|
|
13
|
+
});
|
|
14
|
+
console.log(res.url);
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
handleError(err);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export async function unshareCommand(shareId) {
|
|
21
|
+
const creds = requireCredentials();
|
|
22
|
+
const client = makeClient(creds);
|
|
23
|
+
try {
|
|
24
|
+
await client.delete(`/shares/${shareId}`);
|
|
25
|
+
console.log(`Revoked share ${shareId}`);
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
handleError(err);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export async function whoamiCommand() {
|
|
32
|
+
const creds = requireCredentials();
|
|
33
|
+
const client = makeClient(creds);
|
|
34
|
+
console.log(`Server: ${creds.server}`);
|
|
35
|
+
console.log(`Org: ${creds.orgId}`);
|
|
36
|
+
console.log(`Agent: ${creds.agentId}`);
|
|
37
|
+
console.log(`Expires: ${creds.expiresAt ?? "never"}`);
|
|
38
|
+
try {
|
|
39
|
+
await client.get(`/artifacts?orgId=${creds.orgId}`);
|
|
40
|
+
console.log("Token is valid.");
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
handleError(err);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=share.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"share.js","sourceRoot":"","sources":["../../src/commands/share.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,EAAU,EAAE,IAA+D;IAC5G,MAAM,KAAK,GAAG,kBAAkB,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IACjC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAiC,cAAc,EAAE,SAAS,EAAE;YACvF,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ;YAC3C,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;SAC3D,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,WAAW,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAe;IAClD,MAAM,KAAK,GAAG,kBAAkB,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IACjC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,MAAM,CAAC,WAAW,OAAO,EAAE,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,iBAAiB,OAAO,EAAE,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,WAAW,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,KAAK,GAAG,kBAAkB,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IACjC,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;IACvC,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,CAAC,SAAS,IAAI,OAAO,EAAE,CAAC,CAAC;IACtD,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,GAAG,CAAC,oBAAoB,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,WAAW,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
const CONFIG_DIR = join(homedir(), ".config", "open-artifacts");
|
|
5
|
+
const CREDENTIALS_PATH = join(CONFIG_DIR, "credentials.json");
|
|
6
|
+
export function loadCredentials() {
|
|
7
|
+
const envToken = process.env.OA_TOKEN;
|
|
8
|
+
const envServer = process.env.OA_SERVER;
|
|
9
|
+
if (envToken) {
|
|
10
|
+
return { server: envServer ?? "http://localhost:3000", token: envToken, agentId: "", orgId: "", expiresAt: null };
|
|
11
|
+
}
|
|
12
|
+
if (!existsSync(CREDENTIALS_PATH))
|
|
13
|
+
return null;
|
|
14
|
+
return JSON.parse(readFileSync(CREDENTIALS_PATH, "utf8"));
|
|
15
|
+
}
|
|
16
|
+
export function saveCredentials(creds) {
|
|
17
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
18
|
+
writeFileSync(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), { mode: 0o600 });
|
|
19
|
+
}
|
|
20
|
+
export function requireCredentials() {
|
|
21
|
+
const creds = loadCredentials();
|
|
22
|
+
if (!creds) {
|
|
23
|
+
console.error("Not logged in. Run `oa login` first (or set OA_TOKEN / OA_SERVER env vars).");
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
if (creds.expiresAt && new Date(creds.expiresAt).getTime() <= Date.now()) {
|
|
27
|
+
console.error("Your API key has expired. Run `oa login` again.");
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
return creds;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAUjC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,gBAAgB,CAAC,CAAC;AAChE,MAAM,gBAAgB,GAAG,IAAI,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAC;AAE9D,MAAM,UAAU,eAAe;IAC7B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;IACtC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;IACxC,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,EAAE,MAAM,EAAE,SAAS,IAAI,uBAAuB,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IACpH,CAAC;IACD,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAkB;IAChD,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,aAAa,CAAC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACnF,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;IAChC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,6EAA6E,CAAC,CAAC;QAC7F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,IAAI,KAAK,CAAC,SAAS,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QACzE,OAAO,CAAC,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { isValidScope, API_KEY_SCOPES } from "./scopes.js";
|
|
4
|
+
import { login } from "./commands/login.js";
|
|
5
|
+
import { listCommand, pushCommand, getCommand, rmCommand } from "./commands/artifacts.js";
|
|
6
|
+
import { shareCommand, unshareCommand, whoamiCommand } from "./commands/share.js";
|
|
7
|
+
const program = new Command();
|
|
8
|
+
program.name("oa").description("CLI for Open Artifacts — self-hosted artifact hosting for AI agents").version("0.1.0");
|
|
9
|
+
program
|
|
10
|
+
.command("login")
|
|
11
|
+
.description("Authorize this device via OAuth device flow and save credentials")
|
|
12
|
+
.option("--server <url>", "Open Artifacts server URL", "http://localhost:3000")
|
|
13
|
+
.option("--name <name>", "Name to register this agent as")
|
|
14
|
+
.option("--scopes <scopes>", "Comma-separated scopes to request", "artifacts:read,artifacts:write,shares:write")
|
|
15
|
+
.action(async (opts) => {
|
|
16
|
+
const scopes = String(opts.scopes).split(",").map((s) => s.trim());
|
|
17
|
+
for (const scope of scopes) {
|
|
18
|
+
if (!isValidScope(scope)) {
|
|
19
|
+
console.error(`Invalid scope: ${scope}. Valid scopes: ${API_KEY_SCOPES.join(", ")}`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
await login({ server: opts.server, name: opts.name, scopes });
|
|
24
|
+
});
|
|
25
|
+
program.command("whoami").description("Show the current credentials and verify they work").action(whoamiCommand);
|
|
26
|
+
program
|
|
27
|
+
.command("list")
|
|
28
|
+
.description("List artifacts in your org")
|
|
29
|
+
.option("--json", "Output raw JSON")
|
|
30
|
+
.action(listCommand);
|
|
31
|
+
program
|
|
32
|
+
.command("push <file>")
|
|
33
|
+
.description("Create or update an artifact from a local file")
|
|
34
|
+
.option("--title <title>", "Artifact title (defaults to the filename)")
|
|
35
|
+
.option("--kind <kind>", "html | markdown | mermaid | svg (inferred from extension if omitted)")
|
|
36
|
+
.option("--id <id>", "Update an existing artifact instead of creating a new one")
|
|
37
|
+
.option("--share", "Also create a public share link and print its URL")
|
|
38
|
+
.option("--password <password>", "Create a password-protected share instead of a public one (implies --share)")
|
|
39
|
+
.option("--message <message>", "Version message")
|
|
40
|
+
.option("--json", "Output raw JSON")
|
|
41
|
+
.action((file, opts) => pushCommand(file, { ...opts, share: opts.share || !!opts.password }));
|
|
42
|
+
program
|
|
43
|
+
.command("get <id>")
|
|
44
|
+
.description("Fetch an artifact's current content")
|
|
45
|
+
.option("-o, --output <file>", "Write to a file instead of stdout")
|
|
46
|
+
.action(getCommand);
|
|
47
|
+
program.command("rm <id>").description("Delete an artifact").action(rmCommand);
|
|
48
|
+
program
|
|
49
|
+
.command("share <id>")
|
|
50
|
+
.description("Create a share link for an artifact")
|
|
51
|
+
.option("--password <password>", "Require this password to view")
|
|
52
|
+
.option("--expires <duration>", "e.g. 7d, 12h, 0 for never (default: never)")
|
|
53
|
+
.option("--version <n>", "Pin the share to a specific version number")
|
|
54
|
+
.action(shareCommand);
|
|
55
|
+
program.command("unshare <shareId>").description("Revoke a share link").action(unshareCommand);
|
|
56
|
+
program.parseAsync(process.argv);
|
|
57
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/scopes.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Kept in sync by hand with packages/shared/src/scopes.ts. Duplicated (rather than depended on
|
|
2
|
+
// via a workspace package) so this CLI can be published to npm as a fully standalone package —
|
|
3
|
+
// npm has no notion of pnpm's `workspace:*` protocol.
|
|
4
|
+
export const API_KEY_SCOPES = [
|
|
5
|
+
"artifacts:read",
|
|
6
|
+
"artifacts:write",
|
|
7
|
+
"artifacts:delete",
|
|
8
|
+
"shares:write",
|
|
9
|
+
];
|
|
10
|
+
export function isValidScope(value) {
|
|
11
|
+
return API_KEY_SCOPES.includes(value);
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=scopes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scopes.js","sourceRoot":"","sources":["../src/scopes.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,+FAA+F;AAC/F,sDAAsD;AAEtD,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,gBAAgB;IAChB,iBAAiB;IACjB,kBAAkB;IAClB,cAAc;CACN,CAAC;AAIX,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,OAAQ,cAAoC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC/D,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@emaxe/oa",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI for Open Artifacts — publish HTML/Markdown/Mermaid/SVG content to a self-hosted artifact host and get back a shareable link.",
|
|
5
|
+
"keywords": ["ai-agents", "artifacts", "self-hosted", "cli", "mcp", "claude"],
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "",
|
|
8
|
+
"homepage": "https://github.com/emaxe/open-artifacts#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/emaxe/open-artifacts.git",
|
|
12
|
+
"directory": "packages/cli"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/emaxe/open-artifacts/issues"
|
|
16
|
+
},
|
|
17
|
+
"type": "module",
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=20"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"bin": {
|
|
25
|
+
"oa": "dist/index.js"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"dev": "tsx src/index.ts",
|
|
29
|
+
"build": "tsc -p tsconfig.json",
|
|
30
|
+
"typecheck": "tsc --noEmit",
|
|
31
|
+
"test": "vitest run",
|
|
32
|
+
"prepublishOnly": "pnpm run build"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"commander": "^13.0.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^22.10.5",
|
|
39
|
+
"tsx": "^4.19.2",
|
|
40
|
+
"typescript": "^5.7.3",
|
|
41
|
+
"vitest": "^3.0.5"
|
|
42
|
+
}
|
|
43
|
+
}
|