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 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 URL printed by the server. 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.
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
- Run it in the background and return to your prompt:
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` is equivalent to `artifacty start`. Logs are written under `~/.artifacty/logs/`.
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
- npm start -- --generate-token
63
+ artifacty serve --foreground --generate-token
58
64
  ```
59
65
 
60
- The server prints the generated token plus `/new?token=...` and `/import?token=...` URLs. For scripts or background services that need a stable token, generate one first:
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 in another terminal, or generate a reusable shell token first:
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
@@ -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
- The generated token is printed with ready-to-open create and import URLs.
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` uses the same detached-process path as `start`. It writes `server.pid`, `server.json`, and logs under `ARTIFACTY_HOME` (default `~/.artifacty`). Prefer `start --api-token "$(node src/cli.js token --raw)"` when a background server needs API protection, because generated startup tokens are only visible in the server log.
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 foreground runs where the operator can read the generated token from startup output.
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
 
@@ -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.
@@ -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 and prefer foreground generated
55
- tokens for temporary LAN use.
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "artifacty",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Local artifact exchange for heterogeneous LLM agents via HTTP and MCP.",
5
5
  "type": "module",
6
6
  "keywords": [
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] [--detach]
401
- artifacty start [--host 127.0.0.1] [--port 8787] [--home ~/.artifacty] [--api-token token] [--timeout 5000]
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 5000] [--force]
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]
@@ -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 = 5000;
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(options, store, paths);
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
  };