artifacty 0.5.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 +16 -10
- package/docs/integrations.md +7 -6
- package/docs/network-sharing.md +1 -1
- package/docs/release-checklist.md +1 -0
- package/docs/threat-model.md +2 -2
- package/package.json +1 -1
- package/src/cli.js +9 -5
- package/src/lib/background.js +31 -3
package/README.md
CHANGED
|
@@ -27,37 +27,43 @@ artifacty --help
|
|
|
27
27
|
Run it without a global install:
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
-
npx artifacty@latest serve
|
|
30
|
+
npx artifacty@latest serve --foreground
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
Start the local dashboard:
|
|
33
|
+
Start the local dashboard in the background:
|
|
34
34
|
|
|
35
35
|
```bash
|
|
36
36
|
artifacty serve
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
Open the
|
|
39
|
+
Open the `url` printed in the JSON response. Artifacty prefers `http://127.0.0.1:8787`; if that default port is busy and no explicit port was configured, it starts on the next available local port and records the actual URL for CLI and MCP responses.
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
Manage the background server:
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
|
-
artifacty start
|
|
45
44
|
artifacty status
|
|
46
45
|
artifacty stop
|
|
47
46
|
```
|
|
48
47
|
|
|
49
|
-
`artifacty serve --detach`
|
|
48
|
+
`artifacty start` and `artifacty serve --detach` use the same lifecycle path as `artifacty serve`. Logs are written under `~/.artifacty/logs/`.
|
|
50
49
|
These lifecycle commands use Node's detached process support and work on macOS, Linux, and Windows. `artifacty stop` uses Windows `taskkill` on Windows and process-group signals on macOS/Linux.
|
|
51
50
|
|
|
51
|
+
For foreground debugging, keep the process attached:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
artifacty serve --foreground
|
|
55
|
+
npm start
|
|
56
|
+
```
|
|
57
|
+
|
|
52
58
|
Generate an API token at startup when you want to protect HTTP API and browser write routes:
|
|
53
59
|
|
|
54
60
|
```bash
|
|
55
61
|
artifacty serve --generate-token
|
|
56
62
|
artifacty serve --host 0.0.0.0 --share-mode lan --generate-token
|
|
57
|
-
|
|
63
|
+
artifacty serve --foreground --generate-token
|
|
58
64
|
```
|
|
59
65
|
|
|
60
|
-
|
|
66
|
+
Background `serve` returns the generated token and ready-to-open `/new?token=...` and `/import?token=...` URLs in JSON. Foreground `serve` prints the same values to stderr. For scripts or long-running services that need a stable token, generate one first:
|
|
61
67
|
|
|
62
68
|
```bash
|
|
63
69
|
artifacty token
|
|
@@ -216,11 +222,11 @@ artifacty integrity
|
|
|
216
222
|
|
|
217
223
|
## API Example
|
|
218
224
|
|
|
219
|
-
Start a protected server
|
|
225
|
+
Start a protected server with a reusable shell token:
|
|
220
226
|
|
|
221
227
|
```bash
|
|
222
|
-
artifacty serve --generate-token
|
|
223
228
|
export ARTIFACTY_API_TOKEN="$(artifacty token --raw)"
|
|
229
|
+
artifacty serve --api-token "$ARTIFACTY_API_TOKEN"
|
|
224
230
|
```
|
|
225
231
|
|
|
226
232
|
```bash
|
package/docs/integrations.md
CHANGED
|
@@ -13,22 +13,23 @@ The dashboard prefers `http://127.0.0.1:8787`. If that port is busy and no expli
|
|
|
13
13
|
Use a generated startup token when running a protected foreground server:
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
node src/cli.js serve --generate-token
|
|
17
|
-
node src/cli.js serve --host 0.0.0.0 --share-mode lan --generate-token
|
|
16
|
+
node src/cli.js serve --foreground --generate-token
|
|
17
|
+
node src/cli.js serve --foreground --host 0.0.0.0 --share-mode lan --generate-token
|
|
18
18
|
npm start -- --generate-token
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Foreground runs print the generated token with ready-to-open create and import URLs. Background runs return the same values in JSON.
|
|
22
22
|
|
|
23
23
|
For prompt-friendly local background runs, use the lifecycle commands:
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
+
node src/cli.js serve --port 8787
|
|
26
27
|
node src/cli.js start --port 8787
|
|
27
28
|
node src/cli.js status
|
|
28
29
|
node src/cli.js stop
|
|
29
30
|
```
|
|
30
31
|
|
|
31
|
-
`serve --detach`
|
|
32
|
+
`serve`, `serve --detach`, and `start` use the same detached-process path. They write `server.pid`, `server.json`, and logs under `ARTIFACTY_HOME` (default `~/.artifacty`). `serve --generate-token` and `start --generate-token` generate the API token in the parent CLI process and return it in JSON along with ready-to-open create/import URLs. Use `serve --foreground` when you want attached logs for debugging.
|
|
32
33
|
|
|
33
34
|
The lifecycle commands are intended to be cross-platform:
|
|
34
35
|
|
|
@@ -105,7 +106,7 @@ Generate a token for protected HTTP routes:
|
|
|
105
106
|
node src/cli.js token
|
|
106
107
|
node src/cli.js serve --generate-token
|
|
107
108
|
npm start -- --generate-token
|
|
108
|
-
ARTIFACTY_API_TOKEN="$(node src/cli.js token --raw)" node src/cli.js serve
|
|
109
|
+
ARTIFACTY_API_TOKEN="$(node src/cli.js token --raw)" node src/cli.js serve --foreground
|
|
109
110
|
```
|
|
110
111
|
|
|
111
112
|
## Claude Code
|
|
@@ -308,7 +309,7 @@ node src/cli.js service install
|
|
|
308
309
|
|
|
309
310
|
The generated service runs `src/server.js` with explicit `--host` and `--home` arguments. It includes `--port` only when you configure a port, which keeps the default port fallback available. Load or unload it manually with the `launchctl` commands returned by `service install`.
|
|
310
311
|
|
|
311
|
-
For background services, prefer a stable `ARTIFACTY_API_TOKEN` in the service environment. `serve --generate-token` is intended for
|
|
312
|
+
For background services, prefer a stable `ARTIFACTY_API_TOKEN` in the service environment. `serve --generate-token` is intended for temporary interactive sessions; the parent CLI returns the generated token in JSON.
|
|
312
313
|
|
|
313
314
|
## Backup and Audit
|
|
314
315
|
|
package/docs/network-sharing.md
CHANGED
|
@@ -30,7 +30,7 @@ The generated token protects HTTP API routes and browser write forms. Prefer the
|
|
|
30
30
|
|
|
31
31
|
Artifacty does not terminate TLS. Do not expose it directly on the public internet. If a shared instance must cross an untrusted network, put it behind a TLS reverse proxy or a private VPN.
|
|
32
32
|
|
|
33
|
-
When Artifacty binds outside loopback, startup output includes a warning that the server is reachable beyond the local machine and that TLS is not provided by Artifacty.
|
|
33
|
+
When Artifacty binds outside loopback, startup output includes a warning that the server is reachable beyond the local machine and that TLS is not provided by Artifacty. Background `serve` returns this warning in JSON; foreground `serve` and `src/server.js` also write it to stderr.
|
|
34
34
|
|
|
35
35
|
## Browser Write Behavior
|
|
36
36
|
|
|
@@ -24,6 +24,7 @@ This runs syntax checks, the full Node test suite, and a local smoke test that s
|
|
|
24
24
|
- Keep the default HTTP bind address at `127.0.0.1`.
|
|
25
25
|
- Require `ARTIFACTY_API_TOKEN` and `ARTIFACTY_SHARE_MODE=lan` or `team` before binding to `0.0.0.0`.
|
|
26
26
|
- Confirm non-loopback startup output includes the LAN/team warning.
|
|
27
|
+
- Confirm `artifacty serve` starts a managed background server and returns prompt-friendly JSON; use `artifacty serve --foreground` for attached log checks.
|
|
27
28
|
- Prefer `x-artifacty-token` or `Authorization: Bearer <token>` over query tokens in scripts.
|
|
28
29
|
- Review secret-scan bypasses. `--allow-secrets` and `ARTIFACTY_ALLOW_SECRETS=true` should be deliberate and temporary.
|
|
29
30
|
- Review [../SECURITY.md](../SECURITY.md) and [threat-model.md](threat-model.md) when changing auth, rendering, MCP, or network-sharing behavior.
|
package/docs/threat-model.md
CHANGED
|
@@ -51,8 +51,8 @@ Controls:
|
|
|
51
51
|
- Browser form token URLs exist only for local convenience.
|
|
52
52
|
- Token comparisons use timing-safe digest comparison.
|
|
53
53
|
|
|
54
|
-
Guidance: rotate tokens after sharing sessions
|
|
55
|
-
tokens for temporary
|
|
54
|
+
Guidance: rotate tokens after sharing sessions, prefer header-based tokens for
|
|
55
|
+
scripts, and use generated startup tokens only for temporary interactive shares.
|
|
56
56
|
|
|
57
57
|
### Cross-Site Request Forgery
|
|
58
58
|
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -47,7 +47,10 @@ async function main() {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
if (command === "serve") {
|
|
50
|
-
if (options.detach) {
|
|
50
|
+
if (options.detach && options.foreground) {
|
|
51
|
+
throw new Error("Use either --foreground or --detach, not both");
|
|
52
|
+
}
|
|
53
|
+
if (!options.foreground) {
|
|
51
54
|
printJson(await startBackgroundServer({
|
|
52
55
|
...serverOptions(options),
|
|
53
56
|
serverPath: path.join(PACKAGE_ROOT, "src", "server.js")
|
|
@@ -314,7 +317,7 @@ function parseArgs(args) {
|
|
|
314
317
|
}
|
|
315
318
|
|
|
316
319
|
const key = arg.slice(2);
|
|
317
|
-
if (key === "raw" || key === "dry-run" || key === "trust" || key === "include-archived" || key === "allow-secrets" || key === "generate-token" || key === "detach" || key === "force") {
|
|
320
|
+
if (key === "raw" || key === "dry-run" || key === "trust" || key === "include-archived" || key === "allow-secrets" || key === "generate-token" || key === "detach" || key === "foreground" || key === "force") {
|
|
318
321
|
options[toCamelCase(key)] = true;
|
|
319
322
|
continue;
|
|
320
323
|
}
|
|
@@ -397,10 +400,11 @@ function printHelp() {
|
|
|
397
400
|
|
|
398
401
|
Usage:
|
|
399
402
|
artifacty token [--bytes 32] [--raw]
|
|
400
|
-
artifacty serve [--host 127.0.0.1] [--port 8787] [--home ~/.artifacty] [--api-token token] [--generate-token] [--bytes 32] [--
|
|
401
|
-
artifacty
|
|
403
|
+
artifacty serve [--host 127.0.0.1] [--port 8787] [--home ~/.artifacty] [--api-token token] [--generate-token] [--bytes 32] [--foreground]
|
|
404
|
+
artifacty serve --foreground [--generate-token]
|
|
405
|
+
artifacty start [--host 127.0.0.1] [--port 8787] [--home ~/.artifacty] [--api-token token] [--generate-token] [--timeout 30000]
|
|
402
406
|
artifacty status [--home ~/.artifacty]
|
|
403
|
-
artifacty stop [--home ~/.artifacty] [--timeout
|
|
407
|
+
artifacty stop [--home ~/.artifacty] [--timeout 30000] [--force]
|
|
404
408
|
artifacty publish --title <title> (--file <path> | --content <text>) [--format html|markdown|text|json|code|svg|mermaid|react] [--source agent] [--tag tag]
|
|
405
409
|
artifacty import --agent claude|codex|gemini|copilot|cursor|auto (--file <path> | --content <text>) [--title <title>] [--format html|markdown|text|json|code|svg|mermaid|react] [--tag tag]
|
|
406
410
|
artifacty install claude|codex|gemini|copilot|cursor|all [--dry-run] [--config <path>] [--server-path <path>] [--url http://127.0.0.1:8787] [--timeout 30000]
|
package/src/lib/background.js
CHANGED
|
@@ -4,14 +4,23 @@ import { readFile } from "node:fs/promises";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { createStore } from "./storage.js";
|
|
6
6
|
import { readServerState, serverStatePath } from "./server-state.js";
|
|
7
|
+
import { exposureWarning, securityConfig } from "./security.js";
|
|
8
|
+
import { generateToken } from "./token.js";
|
|
7
9
|
|
|
8
|
-
const DEFAULT_READY_TIMEOUT_MS =
|
|
10
|
+
const DEFAULT_READY_TIMEOUT_MS = 30000;
|
|
11
|
+
const DEFAULT_HOST = "127.0.0.1";
|
|
9
12
|
|
|
10
13
|
export async function startBackgroundServer(options = {}) {
|
|
11
14
|
if (options.generateToken && options.apiToken) {
|
|
12
15
|
throw new Error("Use either --api-token or --generate-token, not both");
|
|
13
16
|
}
|
|
14
17
|
|
|
18
|
+
const generatedToken = options.generateToken ? generateToken(options) : null;
|
|
19
|
+
const serverOptions = {
|
|
20
|
+
...options,
|
|
21
|
+
apiToken: generatedToken?.token || options.apiToken,
|
|
22
|
+
generateToken: false
|
|
23
|
+
};
|
|
15
24
|
const store = createStore({ home: options.home });
|
|
16
25
|
const paths = backgroundPaths(store);
|
|
17
26
|
const current = await backgroundStatus({ home: store.home });
|
|
@@ -22,7 +31,7 @@ export async function startBackgroundServer(options = {}) {
|
|
|
22
31
|
mkdirSync(paths.logDir, { recursive: true });
|
|
23
32
|
mkdirSync(store.home, { recursive: true });
|
|
24
33
|
|
|
25
|
-
const child = spawnDetachedServer(
|
|
34
|
+
const child = spawnDetachedServer(serverOptions, store, paths);
|
|
26
35
|
|
|
27
36
|
writeFileSync(paths.pidFile, `${child.pid}\n`, "utf8");
|
|
28
37
|
|
|
@@ -39,6 +48,11 @@ export async function startBackgroundServer(options = {}) {
|
|
|
39
48
|
pid: child.pid,
|
|
40
49
|
url: ready.url,
|
|
41
50
|
home: store.home,
|
|
51
|
+
auth: authResponse(generatedToken, ready.url),
|
|
52
|
+
securityWarning: exposureWarning({
|
|
53
|
+
host: serverOptions.host || process.env.ARTIFACTY_HOST || DEFAULT_HOST,
|
|
54
|
+
config: securityConfig(serverOptions)
|
|
55
|
+
}) || undefined,
|
|
42
56
|
logs: {
|
|
43
57
|
stdout: paths.stdoutLog,
|
|
44
58
|
stderr: paths.stderrLog
|
|
@@ -58,6 +72,20 @@ export async function startBackgroundServer(options = {}) {
|
|
|
58
72
|
}
|
|
59
73
|
}
|
|
60
74
|
|
|
75
|
+
function authResponse(generatedToken, url) {
|
|
76
|
+
if (!generatedToken) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
token: generatedToken.token,
|
|
81
|
+
bytes: generatedToken.bytes,
|
|
82
|
+
header: generatedToken.header,
|
|
83
|
+
authorization: generatedToken.authorization,
|
|
84
|
+
createUrl: `${url}/new?token=${encodeURIComponent(generatedToken.token)}`,
|
|
85
|
+
importUrl: `${url}/import?token=${encodeURIComponent(generatedToken.token)}`
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
61
89
|
export async function stopBackgroundServer(options = {}) {
|
|
62
90
|
const store = createStore({ home: options.home });
|
|
63
91
|
const paths = backgroundPaths(store);
|
|
@@ -68,7 +96,7 @@ export async function stopBackgroundServer(options = {}) {
|
|
|
68
96
|
action: "stop",
|
|
69
97
|
stopped: false,
|
|
70
98
|
running: status.running,
|
|
71
|
-
reason: status.pid ? "server was not started by artifacty start" : "server is not running",
|
|
99
|
+
reason: status.pid ? "server was not started by artifacty serve/start" : "server is not running",
|
|
72
100
|
pid: status.pid || null,
|
|
73
101
|
home: store.home
|
|
74
102
|
};
|