artifacty 0.1.1 → 0.2.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/AGENTS.md +2 -2
- package/README.md +32 -9
- package/docs/artifact-schema-v1.md +27 -5
- package/docs/integrations.md +39 -4
- package/docs/sarif-csv-artifact-plan.md +44 -65
- package/package.json +1 -1
- package/src/cli.js +67 -6
- package/src/client/editor.js +76 -4
- package/src/lib/background.js +344 -0
- package/src/lib/converters.js +429 -44
- package/src/lib/installer.js +58 -4
- package/src/lib/render.js +404 -2
- package/src/lib/storage.js +52 -3
- package/src/mcp-server.js +2 -2
- package/src/server.js +41 -2
package/AGENTS.md
CHANGED
|
@@ -8,11 +8,11 @@ Artifacty shares LLM artifacts over HTTP, CLI, and MCP.
|
|
|
8
8
|
- `src/mcp-server.js`: MCP stdio server exposing Artifacty tools.
|
|
9
9
|
- `src/cli.js`: command-line interface for serving, publishing, importing, listing, and reading artifacts.
|
|
10
10
|
- `src/lib/storage.js`: SQLite metadata store and immutable version-file handling.
|
|
11
|
-
- `src/lib/converters.js`: agent artifact conversion rules for Claude, Codex, Gemini, and generic payloads.
|
|
11
|
+
- `src/lib/converters.js`: agent artifact conversion rules for Claude, Codex, Gemini, GitHub Copilot, Cursor, and generic payloads.
|
|
12
12
|
- `src/lib/installer.js`: MCP config installers for Claude, Codex, and Gemini.
|
|
13
13
|
- `src/lib/render.js`: server-rendered dashboard, viewer, and editor HTML.
|
|
14
14
|
- `test/*.test.js`: Node test runner suites.
|
|
15
|
-
- `docs/integrations.md`: setup notes for Claude Code, Codex,
|
|
15
|
+
- `docs/integrations.md`: setup notes for Claude Code, Codex, Gemini CLI, GitHub Copilot in VS Code, and Cursor.
|
|
16
16
|
|
|
17
17
|
## Build, Test, and Development Commands
|
|
18
18
|
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
[](package.json)
|
|
7
7
|
|
|
8
|
-
Artifacty is a local, agent-to-agent artifact exchange for LLM workflows. Claude, Codex, Gemini, and other MCP-capable tools can publish an artifact once, then other agents can list, read, update, and continue from it without copying content through chat.
|
|
8
|
+
Artifacty is a local, agent-to-agent artifact exchange for LLM workflows. Claude, Codex, Gemini, GitHub Copilot, Cursor, and other MCP-capable tools can publish an artifact once, then other agents can list, read, update, and continue from it without copying content through chat.
|
|
9
9
|
|
|
10
10
|

|
|
11
11
|
|
|
@@ -38,6 +38,17 @@ artifacty serve
|
|
|
38
38
|
|
|
39
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.
|
|
40
40
|
|
|
41
|
+
Run it in the background and return to your prompt:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
artifacty start
|
|
45
|
+
artifacty status
|
|
46
|
+
artifacty stop
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`artifacty serve --detach` is equivalent to `artifacty start`. Logs are written under `~/.artifacty/logs/`.
|
|
50
|
+
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
|
+
|
|
41
52
|
Generate an API token at startup when you want to protect HTTP API and browser write routes:
|
|
42
53
|
|
|
43
54
|
```bash
|
|
@@ -50,7 +61,7 @@ The server prints the generated token plus `/new?token=...` and `/import?token=.
|
|
|
50
61
|
|
|
51
62
|
```bash
|
|
52
63
|
artifacty token
|
|
53
|
-
|
|
64
|
+
artifacty start --api-token "$(artifacty token --raw)"
|
|
54
65
|
```
|
|
55
66
|
|
|
56
67
|
Install MCP configuration for local agents:
|
|
@@ -59,6 +70,8 @@ Install MCP configuration for local agents:
|
|
|
59
70
|
artifacty install claude
|
|
60
71
|
artifacty install codex --dry-run
|
|
61
72
|
artifacty install gemini
|
|
73
|
+
artifacty install copilot
|
|
74
|
+
artifacty install cursor
|
|
62
75
|
artifacty install all
|
|
63
76
|
artifacty check
|
|
64
77
|
```
|
|
@@ -66,7 +79,7 @@ artifacty check
|
|
|
66
79
|
Use `artifacty install codex --timeout 30000` or
|
|
67
80
|
`artifacty install gemini --timeout 30000` to tune supported MCP client timeouts.
|
|
68
81
|
|
|
69
|
-
See [docs/integrations.md](docs/integrations.md) for Claude Code, Codex,
|
|
82
|
+
See [docs/integrations.md](docs/integrations.md) for Claude Code, Codex, Gemini CLI, GitHub Copilot in VS Code, and Cursor setup.
|
|
70
83
|
|
|
71
84
|
## Quick Start
|
|
72
85
|
|
|
@@ -102,11 +115,14 @@ Import an artifact produced by another agent and convert it to Artifacty format:
|
|
|
102
115
|
artifacty import --agent claude --file ./deploy-failures.html --tag review
|
|
103
116
|
artifacty import --agent gemini --content '{"title":"Plan","returnDisplay":"# Plan\n- Ship it"}'
|
|
104
117
|
artifacty import --agent codex --content '{"agent":"codex","title":"Implementation Handoff","goal":"Continue Phase 3","changedFiles":[{"path":"src/lib/render.js","status":"modified"}],"nextSteps":["Add CodeMirror read-only viewer"]}'
|
|
118
|
+
artifacty import --agent copilot --content '{"agent":"github-copilot","title":"PR Review","findings":[{"severity":"medium","file":"src/app.js","line":42,"title":"Handle missing state"}]}'
|
|
119
|
+
artifacty import --agent cursor --content '{"sourceAgent":"cursor","title":"Cursor Handoff","summary":"Editor pass complete.","nextSteps":["Run visual QA."]}'
|
|
105
120
|
```
|
|
106
121
|
|
|
107
|
-
Codex structured payloads can become `handoff`,
|
|
108
|
-
`code-review`, or `test-report` artifacts when
|
|
109
|
-
|
|
122
|
+
Codex, GitHub Copilot, and Cursor structured payloads can become `handoff`,
|
|
123
|
+
`bundle`, `diff-walkthrough`, `code-review`, or `test-report` artifacts when
|
|
124
|
+
the payload explicitly identifies the agent through `agent` or `sourceAgent`.
|
|
125
|
+
Plain Markdown from these agents stays a normal
|
|
110
126
|
`document` unless you pass an explicit `artifactType`.
|
|
111
127
|
|
|
112
128
|
## Agent Handoff Example
|
|
@@ -166,6 +182,9 @@ artifacty audit --limit 20
|
|
|
166
182
|
artifacty backup
|
|
167
183
|
artifacty export --file ./artifacty-backup.json
|
|
168
184
|
artifacty import-store --file ./artifacty-backup.json
|
|
185
|
+
artifacty start
|
|
186
|
+
artifacty status
|
|
187
|
+
artifacty stop
|
|
169
188
|
artifacty service install --dry-run
|
|
170
189
|
```
|
|
171
190
|
|
|
@@ -222,7 +241,7 @@ Browser routes:
|
|
|
222
241
|
- `/`: list artifacts with search, tag, and source filters.
|
|
223
242
|
- `/new`: create an Artifacty-native artifact with the CodeMirror editor.
|
|
224
243
|
- `/import`: paste an external agent artifact and convert it with automatic editor mode detection.
|
|
225
|
-
- `/artifacts/:id/edit`: save a new version with Markdown, HTML, JSON, text, code, SVG, Mermaid, or
|
|
244
|
+
- `/artifacts/:id/edit`: save a new version with Markdown, HTML, JSON, text, code, SVG, Mermaid, React, SARIF, CSV, image, or video syntax support.
|
|
226
245
|
- `/artifacts/:id/diff`: compare versions.
|
|
227
246
|
- `/api/audit`: list audit events.
|
|
228
247
|
|
|
@@ -235,8 +254,9 @@ Schema and storage:
|
|
|
235
254
|
- Metadata lives in SQLite with `schemaVersion: 1`, `artifactType`, and `archivedAt`.
|
|
236
255
|
- Archive hides artifacts from default lists without deleting versions.
|
|
237
256
|
- Bundle artifacts store multiple files or base64 assets as portable JSON.
|
|
238
|
-
- Supported formats are `html`, `markdown`, `text`, `json`, `code`, `svg`, `mermaid`, and `
|
|
239
|
-
- Diagram, component,
|
|
257
|
+
- Supported formats are `html`, `markdown`, `text`, `json`, `code`, `svg`, `mermaid`, `react`, `sarif`, `csv`, `image`, and `video`.
|
|
258
|
+
- Diagram, component, source snippet, analysis report, table, and media assets use `diagram`, `component`, `snippet`, `analysis-report`, `table`, and `asset` artifact types.
|
|
259
|
+
- Copilot/Cursor examples cover PR reviews, screenshots, demo recordings, and visual evidence bundles.
|
|
240
260
|
- See [docs/artifact-schema-v1.md](docs/artifact-schema-v1.md).
|
|
241
261
|
- See [docs/sarif-csv-artifact-plan.md](docs/sarif-csv-artifact-plan.md) for the SARIF/CSV output artifact roadmap.
|
|
242
262
|
|
|
@@ -254,6 +274,9 @@ Schema and storage:
|
|
|
254
274
|
- SVG artifacts render in a scriptless sandboxed iframe and are sanitized for `<script>`, `on*` attributes, and `javascript:` links in the viewer. The raw source remains unchanged.
|
|
255
275
|
- Mermaid artifacts render with the vendored local Mermaid package in a sandboxed iframe without `allow-same-origin`.
|
|
256
276
|
- React artifacts are source-only by default. Set `ARTIFACTY_ENABLE_REACT_RENDERER=true` to execute them in a sandboxed frame with a frame-scoped CSP that permits JSX transformation.
|
|
277
|
+
- SARIF artifacts render a bounded findings summary and keep the full formatted JSON behind a raw-source details panel.
|
|
278
|
+
- CSV artifacts render as an escaped, bounded table; `/raw` preserves the original text.
|
|
279
|
+
- Image and video artifacts store base64 media inline, render safe previews, and decode bytes through `/raw`.
|
|
257
280
|
- Artifact content should still be treated as untrusted; use the raw view when handing content back to an agent.
|
|
258
281
|
|
|
259
282
|
See [docs/release-checklist.md](docs/release-checklist.md) before publishing or running a shared instance.
|
|
@@ -35,6 +35,8 @@ Allowed `artifactType` values:
|
|
|
35
35
|
- `diagram`
|
|
36
36
|
- `component`
|
|
37
37
|
- `snippet`
|
|
38
|
+
- `analysis-report`
|
|
39
|
+
- `table`
|
|
38
40
|
- `unknown`
|
|
39
41
|
|
|
40
42
|
Unknown legacy or external types should be mapped to `unknown`, not rejected during conversion. Native create/update rejects unsupported explicit types.
|
|
@@ -57,7 +59,11 @@ Each version is immutable and points at one content file.
|
|
|
57
59
|
```
|
|
58
60
|
|
|
59
61
|
Allowed `format` values are `html`, `markdown`, `text`, `json`, `code`, `svg`,
|
|
60
|
-
`mermaid`, and `
|
|
62
|
+
`mermaid`, `react`, `sarif`, `csv`, `image`, and `video`.
|
|
63
|
+
|
|
64
|
+
Common `artifactType` values include `document`, `handoff`, `code-review`,
|
|
65
|
+
`test-report`, `dashboard`, `bundle`, `diagram`, `component`, `snippet`,
|
|
66
|
+
`analysis-report`, and `table`.
|
|
61
67
|
|
|
62
68
|
## Renderer Policy
|
|
63
69
|
|
|
@@ -74,6 +80,11 @@ viewer concern and must treat all source as untrusted:
|
|
|
74
80
|
- `react`: source-only by default. `ARTIFACTY_ENABLE_REACT_RENDERER=true`
|
|
75
81
|
enables a separate sandboxed frame with frame-scoped CSP for JSX transform and
|
|
76
82
|
execution.
|
|
83
|
+
- `sarif`: bounded findings summary plus a formatted raw JSON details panel.
|
|
84
|
+
- `csv`: RFC 4180-style escaped table rendering with bounded rows and columns.
|
|
85
|
+
- `image`: base64 media source rendered with `<img>`; `/raw` decodes bytes.
|
|
86
|
+
- `video`: base64 media source rendered with `<video controls>`; `/raw` decodes
|
|
87
|
+
bytes.
|
|
77
88
|
|
|
78
89
|
## Metadata
|
|
79
90
|
|
|
@@ -85,9 +96,12 @@ Metadata is free-form JSON, but converter-generated metadata uses these keys:
|
|
|
85
96
|
- `bundlePolicy`: how bundled files were preserved.
|
|
86
97
|
- `language`: source language for code or component artifacts when supplied by an
|
|
87
98
|
upstream agent.
|
|
88
|
-
- `
|
|
89
|
-
commands, tests, blockers, decisions, next
|
|
90
|
-
residual risk.
|
|
99
|
+
- `continuation`: structured handoff/review/verification metadata for agent
|
|
100
|
+
outputs, including changed files, commands, tests, blockers, decisions, next
|
|
101
|
+
steps, findings, diff text, and residual risk.
|
|
102
|
+
- `<agent>Continuation`: compatibility mirror for structured continuation
|
|
103
|
+
metadata, such as `codexContinuation`, `copilotContinuation`, or
|
|
104
|
+
`cursorContinuation`.
|
|
91
105
|
|
|
92
106
|
## Archive Semantics
|
|
93
107
|
|
|
@@ -118,4 +132,12 @@ Gemini multimodal payloads use the same bundle type with `parts` and `assets`.
|
|
|
118
132
|
|
|
119
133
|
## Asset Policy
|
|
120
134
|
|
|
121
|
-
Base64 assets are preserved inline inside bundle JSON with `encoding: "base64"`, `mimeType`, `sizeBytes`, and `sha256`. Consumers must treat decoded assets as untrusted.
|
|
135
|
+
Base64 assets are preserved inline inside bundle JSON with `encoding: "base64"`, `mimeType`, `sizeBytes`, and `sha256`. Consumers must treat decoded assets as untrusted.
|
|
136
|
+
|
|
137
|
+
First-class `image` and `video` artifacts store base64 content in the immutable
|
|
138
|
+
version file. Importers should set `metadata.encoding: "base64"` and
|
|
139
|
+
`metadata.mimeType` to one of the supported media types. Browser `/raw` decodes
|
|
140
|
+
the stored base64 into bytes with the media content type, while API and MCP reads
|
|
141
|
+
return the stored base64 string. Supported media types are PNG, JPEG, GIF, WebP,
|
|
142
|
+
MP4, and WebM. Large binary externalization is intentionally deferred; schema v1
|
|
143
|
+
keeps converted assets inspectable and portable.
|
package/docs/integrations.md
CHANGED
|
@@ -20,11 +20,29 @@ npm start -- --generate-token
|
|
|
20
20
|
|
|
21
21
|
The generated token is printed with ready-to-open create and import URLs.
|
|
22
22
|
|
|
23
|
+
For prompt-friendly local background runs, use the lifecycle commands:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
node src/cli.js start --port 8787
|
|
27
|
+
node src/cli.js status
|
|
28
|
+
node src/cli.js stop
|
|
29
|
+
```
|
|
30
|
+
|
|
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
|
+
|
|
33
|
+
The lifecycle commands are intended to be cross-platform:
|
|
34
|
+
|
|
35
|
+
- macOS and Linux: `stop` signals the detached process group first, then falls back to the server process id.
|
|
36
|
+
- Windows: `start` hides the child console window, and `stop` uses `taskkill /PID <pid> /T`; `--force` adds `/F`.
|
|
37
|
+
- All platforms: `status` combines the managed pid file with the HTTP `/health` endpoint, so a stale pid alone is not reported as healthy.
|
|
38
|
+
|
|
39
|
+
For login/startup persistence, use the operating system's service manager. Artifacty's `service` command currently generates a macOS LaunchAgent plist; Linux systemd user units and Windows Task Scheduler/Service wrappers should be configured explicitly until first-class installers are added.
|
|
40
|
+
|
|
23
41
|
Create artifacts directly in the browser at `http://127.0.0.1:8787/new`.
|
|
24
42
|
|
|
25
43
|
For LAN or VPN sharing, keep the default local binding unless you intentionally need another machine to reach the server. See [network-sharing.md](network-sharing.md) before using `--host 0.0.0.0`.
|
|
26
44
|
|
|
27
|
-
The browser create/import/edit screens use CodeMirror 6 for Markdown, HTML, JSON, source-like text, SVG, Mermaid, and
|
|
45
|
+
The browser create/import/edit screens use CodeMirror 6 for Markdown, HTML, JSON, source-like text, SVG, Mermaid, React, SARIF, CSV, image, and video artifact editing. Editor and renderer assets are served from local npm dependencies through `/assets/*.js` and allowlisted `/vendor/npm/*` module routes. For sandboxed iframe imports, `Origin: null` requests receive `Access-Control-Allow-Origin: null`, which lets opaque-origin iframes import local ESM without `allow-same-origin`.
|
|
28
46
|
|
|
29
47
|
The browser UI defaults to English. Add `?lang=ko` to browser routes to use Korean UI labels; API and MCP payloads are not localized.
|
|
30
48
|
|
|
@@ -52,6 +70,8 @@ Artifacty can write MCP configuration for supported local agents:
|
|
|
52
70
|
node src/cli.js install claude
|
|
53
71
|
node src/cli.js install codex --dry-run
|
|
54
72
|
node src/cli.js install gemini
|
|
73
|
+
node src/cli.js install copilot
|
|
74
|
+
node src/cli.js install cursor
|
|
55
75
|
node src/cli.js install all
|
|
56
76
|
node src/cli.js check
|
|
57
77
|
```
|
|
@@ -59,6 +79,8 @@ node src/cli.js check
|
|
|
59
79
|
- Claude: writes project `.mcp.json`. Claude Code's startup timeout is controlled by the parent `MCP_TIMEOUT` environment variable and defaults to 30 seconds, so Artifacty does not add a per-server `.mcp.json` `timeout` field.
|
|
60
80
|
- Codex: writes or replaces the `[mcp_servers.artifacty]` block in `~/.codex/config.toml` unless `--config` is provided. The generated block uses a 30 second startup timeout so slower Windows or cold-start environments can load the MCP server reliably.
|
|
61
81
|
- Gemini: writes project `.gemini/settings.json` with a 30 second timeout.
|
|
82
|
+
- GitHub Copilot in VS Code: writes workspace `.vscode/mcp.json` using the VS Code `servers` shape. Pass `--config` to target a user-profile `mcp.json` instead.
|
|
83
|
+
- Cursor: writes project `.cursor/mcp.json` using the Cursor `mcpServers` shape. Pass `--config ~/.cursor/mcp.json` for global Cursor setup.
|
|
62
84
|
- `--dry-run` returns the generated config without writing it.
|
|
63
85
|
- `--timeout <ms>` adjusts Codex `startup_timeout_sec` and Gemini `timeout`. It does not change Claude Code startup behavior; set `MCP_TIMEOUT` before launching Claude Code if you need a larger value there.
|
|
64
86
|
- `check` starts the local MCP server and verifies required tools through `initialize` and `tools/list`.
|
|
@@ -96,7 +118,7 @@ Project-scoped `.mcp.json` shape:
|
|
|
96
118
|
}
|
|
97
119
|
```
|
|
98
120
|
|
|
99
|
-
Claude plugins can bundle MCP servers, so this MCP server can later be wrapped as a plugin. The MVP keeps the server standalone so Claude, Codex, Gemini, and other MCP clients use the same integration surface.
|
|
121
|
+
Claude plugins can bundle MCP servers, so this MCP server can later be wrapped as a plugin. The MVP keeps the server standalone so Claude, Codex, Gemini, GitHub Copilot, Cursor, and other MCP clients use the same integration surface.
|
|
100
122
|
|
|
101
123
|
Claude Code uses a 30 second MCP startup timeout by default. If a slower
|
|
102
124
|
environment needs more time, launch Claude Code with a larger `MCP_TIMEOUT`
|
|
@@ -163,7 +185,7 @@ Then run `/mcp` inside Gemini CLI to confirm that the Artifacty tools are connec
|
|
|
163
185
|
|
|
164
186
|
- `artifacty_create`: create a new Artifacty-native artifact.
|
|
165
187
|
- `artifacty_publish`: backwards-compatible alias for `artifacty_create`.
|
|
166
|
-
- `artifacty_import`: convert a Claude, Codex, Gemini, Artifacty, or generic artifact payload into Artifacty format and save it.
|
|
188
|
+
- `artifacty_import`: convert a Claude, Codex, Gemini, GitHub Copilot, Cursor, Artifacty, or generic artifact payload into Artifacty format and save it.
|
|
167
189
|
- `artifacty_list`: discover artifacts by query, tag, or source agent.
|
|
168
190
|
- `artifacty_get`: read artifact metadata and content.
|
|
169
191
|
- `artifacty_update`: append a new version.
|
|
@@ -182,6 +204,10 @@ Use `artifacty_import` or the CLI `import` command when the artifact was produce
|
|
|
182
204
|
node src/cli.js import --agent claude --file ./artifact.html --tag review
|
|
183
205
|
node src/cli.js import --agent codex --file ./handoff.md --tag handoff
|
|
184
206
|
node src/cli.js import --agent codex --content '{"agent":"codex","title":"Verification","verification":{"status":"passed","commands":[{"command":"npm test","status":"passed"}]}}'
|
|
207
|
+
node src/cli.js import --agent copilot --content '{"agent":"github-copilot","title":"PR Review","findings":[{"severity":"medium","file":"src/app.js","line":42,"title":"Handle missing state"}]}'
|
|
208
|
+
node src/cli.js import --agent cursor --content '{"sourceAgent":"cursor","title":"Cursor Handoff","summary":"Editor pass complete.","nextSteps":["Run visual QA."]}'
|
|
209
|
+
node src/cli.js import --agent cursor --file ./browser-screenshot.png --tag visual
|
|
210
|
+
node src/cli.js import --agent cursor --file ./demo.webm --tag demo
|
|
185
211
|
node src/cli.js import --agent gemini --content '{"title":"Options","returnDisplay":"# Options\n- A\n- B"}'
|
|
186
212
|
```
|
|
187
213
|
|
|
@@ -189,11 +215,17 @@ Supported converter inputs:
|
|
|
189
215
|
|
|
190
216
|
- Claude: local `.html`, `.htm`, `.md`, `.svg`, `.mmd`, `.jsx`, `.tsx`, source files, or JSON payloads with `title`/`content`/Claude artifact `type`.
|
|
191
217
|
- Codex: markdown/text/json handoff files; Artifacty-compatible JSON payloads; structured handoff, bundle, diff, review, and verification JSON payloads with `agent` or `sourceAgent` set to `codex`.
|
|
218
|
+
- GitHub Copilot: markdown/text/json outputs; Artifacty-compatible JSON payloads; structured handoff, review, diff, and verification JSON payloads with `agent` or `sourceAgent` set to `github-copilot` or `copilot`.
|
|
219
|
+
- Cursor: markdown/text/json outputs; Artifacty-compatible JSON payloads; structured handoff, review, diff, verification, screenshot, demo/video, and visual evidence bundle JSON payloads with `agent` or `sourceAgent` set to `cursor`.
|
|
192
220
|
- Gemini: `returnDisplay`, `llmContent`, text blocks, or local markdown/text/json files.
|
|
193
|
-
- Generic: file extension, content type, HTML doctype, JSON shape, and markdown headings are used to infer format and title.
|
|
221
|
+
- Generic: file extension, content type, HTML doctype, JSON shape, media data URLs, and markdown headings are used to infer format and title.
|
|
194
222
|
|
|
195
223
|
The converter adds `imported` and source-agent tags, preserves the raw content as an immutable Artifacty version, and records source details under `metadata.artifactyImport`.
|
|
196
224
|
|
|
225
|
+
Fixture examples for Copilot/Cursor PR review, screenshot, demo recording, and
|
|
226
|
+
visual evidence bundle live under `test/fixtures/` and are covered by converter
|
|
227
|
+
tests.
|
|
228
|
+
|
|
197
229
|
## HTTP API
|
|
198
230
|
|
|
199
231
|
- `GET /`: dashboard.
|
|
@@ -227,6 +259,9 @@ Renderer notes:
|
|
|
227
259
|
- `svg` artifacts render in a scriptless sandboxed iframe after viewer-side sanitization; `/raw` still returns the original SVG.
|
|
228
260
|
- `mermaid` artifacts load the vendored local Mermaid bundle from `/vendor/npm/mermaid/...` in a sandboxed iframe without `allow-same-origin`. The JavaScript asset route answers the iframe's `Origin: null` module request with `Access-Control-Allow-Origin: null`.
|
|
229
261
|
- `react` artifacts are source-only unless `ARTIFACTY_ENABLE_REACT_RENDERER=true` is set. When enabled, JSX transformation and React execution happen only in `/artifacts/:id/react-frame`, with `unsafe-eval` scoped to that frame CSP.
|
|
262
|
+
- `sarif` artifacts render a bounded findings summary and keep the complete formatted JSON available in the browser viewer and `/raw`.
|
|
263
|
+
- `csv` artifacts render as an escaped table with bounded rows and columns; `/raw` preserves the original CSV text.
|
|
264
|
+
- `image` and `video` artifacts store base64 content inline, render with native browser media elements, and decode bytes through `/raw`.
|
|
230
265
|
|
|
231
266
|
## Background Service
|
|
232
267
|
|
|
@@ -1,65 +1,44 @@
|
|
|
1
|
-
# SARIF and CSV Artifact Support
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
context, appshots, thread state,
|
|
6
|
-
|
|
7
|
-
##
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
-
|
|
42
|
-
|
|
43
|
-
-
|
|
44
|
-
|
|
45
|
-
Exit criteria: CSV artifacts are readable in the browser and raw fidelity is
|
|
46
|
-
unchanged.
|
|
47
|
-
|
|
48
|
-
## Phase 3: SARIF Summary Viewer
|
|
49
|
-
|
|
50
|
-
- Keep SARIF source as JSON.
|
|
51
|
-
- Add an optional summary above the JSON view: rule id, severity/level, message,
|
|
52
|
-
file URI, region, and result count by level.
|
|
53
|
-
- Avoid implementing the complete SARIF spec in v1; parse only stable top-level
|
|
54
|
-
fields and fail closed to JSON rendering.
|
|
55
|
-
|
|
56
|
-
Exit criteria: SARIF exports are useful for quick triage while preserving the
|
|
57
|
-
full JSON source.
|
|
58
|
-
|
|
59
|
-
## Tests
|
|
60
|
-
|
|
61
|
-
- Converter fixtures: Codex Security SARIF, findings CSV, generic CSV, malformed
|
|
62
|
-
CSV, and large CSV.
|
|
63
|
-
- Storage round trips: content type, extension, size, hash, and `/raw` fidelity.
|
|
64
|
-
- Server rendering: CSV table escaping, truncation notice, SARIF summary fallback.
|
|
65
|
-
- MCP schema and import tests for explicit and inferred artifact types.
|
|
1
|
+
# SARIF and CSV Artifact Support
|
|
2
|
+
|
|
3
|
+
Artifacty supports SARIF and CSV as **output artifacts** that Codex and other
|
|
4
|
+
agents can hand off for downstream review. This scope excludes Codex input
|
|
5
|
+
context, appshots, thread state, and client-specific UI state.
|
|
6
|
+
|
|
7
|
+
## Implemented Behavior
|
|
8
|
+
|
|
9
|
+
- `sarif` and `csv` are first-class `format` values across HTTP, CLI, MCP,
|
|
10
|
+
storage, and browser forms.
|
|
11
|
+
- `.sarif`, `.sarif.json`, `application/sarif+json`, `.csv`, and `text/csv`
|
|
12
|
+
inputs are detected during import.
|
|
13
|
+
- SARIF top-level objects with `version` and `runs[]` are imported as
|
|
14
|
+
`analysis-report` artifacts.
|
|
15
|
+
- CSV inputs default to `table`; CSV files that look like security or review
|
|
16
|
+
findings infer `analysis-report`.
|
|
17
|
+
- `/raw` always returns the original stored source.
|
|
18
|
+
|
|
19
|
+
## Browser Rendering
|
|
20
|
+
|
|
21
|
+
- SARIF renders a bounded findings summary with run, result, error, warning,
|
|
22
|
+
and note counts.
|
|
23
|
+
- SARIF result rows show level, rule id, message, first location, and tool name.
|
|
24
|
+
- The full formatted SARIF JSON remains available in a details panel.
|
|
25
|
+
- CSV renders as an escaped table with bounded rows and columns.
|
|
26
|
+
- Malformed CSV or non-SARIF JSON fails closed to escaped source or formatted
|
|
27
|
+
JSON fallback.
|
|
28
|
+
|
|
29
|
+
## Verification Coverage
|
|
30
|
+
|
|
31
|
+
- Storage round trips cover format enums, content types, extensions, and type
|
|
32
|
+
inference.
|
|
33
|
+
- Converter tests cover SARIF extension/MIME/object detection, findings CSV,
|
|
34
|
+
and generic CSV.
|
|
35
|
+
- Server tests cover SARIF summary rendering, CSV escaping, `/raw` fidelity,
|
|
36
|
+
and browser form options.
|
|
37
|
+
- MCP tests assert the new format and artifact type enums are exposed.
|
|
38
|
+
|
|
39
|
+
## Future Extensions
|
|
40
|
+
|
|
41
|
+
- Add real-world fixtures from CodeQL, Semgrep, Trivy, and other scanners.
|
|
42
|
+
- Add sorting/filtering for SARIF levels and CSV columns.
|
|
43
|
+
- Add optional download helpers for filtered CSV/SARIF views without changing
|
|
44
|
+
immutable source storage.
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -17,6 +17,7 @@ import { convertAgentArtifact } from "./lib/converters.js";
|
|
|
17
17
|
import { checkMcpTools } from "./lib/check.js";
|
|
18
18
|
import { installAgent } from "./lib/installer.js";
|
|
19
19
|
import { serviceCommand } from "./lib/service.js";
|
|
20
|
+
import { backgroundStatus, startBackgroundServer, stopBackgroundServer } from "./lib/background.js";
|
|
20
21
|
import { resolvePublicBaseUrl } from "./lib/server-state.js";
|
|
21
22
|
import { generateToken } from "./lib/token.js";
|
|
22
23
|
import { startServer } from "./server.js";
|
|
@@ -44,6 +45,13 @@ async function main() {
|
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
if (command === "serve") {
|
|
48
|
+
if (options.detach) {
|
|
49
|
+
printJson(await startBackgroundServer({
|
|
50
|
+
...serverOptions(options),
|
|
51
|
+
serverPath: path.join(PACKAGE_ROOT, "src", "server.js")
|
|
52
|
+
}));
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
47
55
|
if (options.generateToken && options.apiToken) {
|
|
48
56
|
throw new Error("Use either --api-token or --generate-token, not both");
|
|
49
57
|
}
|
|
@@ -67,6 +75,28 @@ async function main() {
|
|
|
67
75
|
return;
|
|
68
76
|
}
|
|
69
77
|
|
|
78
|
+
if (command === "start") {
|
|
79
|
+
printJson(await startBackgroundServer({
|
|
80
|
+
...serverOptions(options),
|
|
81
|
+
serverPath: path.join(PACKAGE_ROOT, "src", "server.js")
|
|
82
|
+
}));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (command === "stop") {
|
|
87
|
+
printJson(await stopBackgroundServer({
|
|
88
|
+
home: options.home,
|
|
89
|
+
timeout: options.timeout,
|
|
90
|
+
force: options.force
|
|
91
|
+
}));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (command === "status") {
|
|
96
|
+
printJson(await backgroundStatus({ home: options.home }));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
70
100
|
if (command === "publish") {
|
|
71
101
|
const content = await readContent(options);
|
|
72
102
|
const artifact = await createArtifact(store, {
|
|
@@ -115,7 +145,7 @@ async function main() {
|
|
|
115
145
|
if (command === "install") {
|
|
116
146
|
const agent = options._[0];
|
|
117
147
|
if (!agent) {
|
|
118
|
-
throw new Error("install requires an agent: claude, codex, gemini, or all");
|
|
148
|
+
throw new Error("install requires an agent: claude, codex, gemini, copilot, cursor, or all");
|
|
119
149
|
}
|
|
120
150
|
const result = await installAgent(agent, {
|
|
121
151
|
projectDir: options.projectDir || process.cwd(),
|
|
@@ -256,7 +286,7 @@ function parseArgs(args) {
|
|
|
256
286
|
}
|
|
257
287
|
|
|
258
288
|
const key = arg.slice(2);
|
|
259
|
-
if (key === "raw" || key === "dry-run" || key === "trust" || key === "include-archived" || key === "allow-secrets" || key === "generate-token") {
|
|
289
|
+
if (key === "raw" || key === "dry-run" || key === "trust" || key === "include-archived" || key === "allow-secrets" || key === "generate-token" || key === "detach" || key === "force") {
|
|
260
290
|
options[toCamelCase(key)] = true;
|
|
261
291
|
continue;
|
|
262
292
|
}
|
|
@@ -281,7 +311,11 @@ function parseArgs(args) {
|
|
|
281
311
|
|
|
282
312
|
async function readContent(options) {
|
|
283
313
|
if (options.file) {
|
|
284
|
-
|
|
314
|
+
const filePath = path.resolve(options.file);
|
|
315
|
+
if (shouldReadFileAsBase64(options, filePath)) {
|
|
316
|
+
return (await readFile(filePath)).toString("base64");
|
|
317
|
+
}
|
|
318
|
+
return readFile(filePath, "utf8");
|
|
285
319
|
}
|
|
286
320
|
if (options.content !== undefined) {
|
|
287
321
|
return options.content;
|
|
@@ -289,6 +323,16 @@ async function readContent(options) {
|
|
|
289
323
|
throw new Error("Provide --file or --content");
|
|
290
324
|
}
|
|
291
325
|
|
|
326
|
+
function shouldReadFileAsBase64(options, filePath) {
|
|
327
|
+
const format = String(options.format || "").toLowerCase();
|
|
328
|
+
const contentType = String(options.contentType || "").toLowerCase();
|
|
329
|
+
return format === "image" ||
|
|
330
|
+
format === "video" ||
|
|
331
|
+
contentType.startsWith("image/") ||
|
|
332
|
+
contentType.startsWith("video/") ||
|
|
333
|
+
/\.(png|jpe?g|gif|webp|mp4|webm)$/i.test(filePath);
|
|
334
|
+
}
|
|
335
|
+
|
|
292
336
|
async function withUrls(store, artifact) {
|
|
293
337
|
const publicBaseUrl = await resolvePublicBaseUrl(store);
|
|
294
338
|
return {
|
|
@@ -314,10 +358,13 @@ function printHelp() {
|
|
|
314
358
|
|
|
315
359
|
Usage:
|
|
316
360
|
artifacty token [--bytes 32] [--raw]
|
|
317
|
-
artifacty serve [--host 127.0.0.1] [--port 8787] [--home ~/.artifacty] [--generate-token] [--bytes 32]
|
|
361
|
+
artifacty serve [--host 127.0.0.1] [--port 8787] [--home ~/.artifacty] [--api-token token] [--generate-token] [--bytes 32] [--detach]
|
|
362
|
+
artifacty start [--host 127.0.0.1] [--port 8787] [--home ~/.artifacty] [--api-token token] [--timeout 5000]
|
|
363
|
+
artifacty status [--home ~/.artifacty]
|
|
364
|
+
artifacty stop [--home ~/.artifacty] [--timeout 5000] [--force]
|
|
318
365
|
artifacty publish --title <title> (--file <path> | --content <text>) [--format html|markdown|text|json|code|svg|mermaid|react] [--source agent] [--tag tag]
|
|
319
|
-
artifacty import --agent claude|codex|gemini|auto (--file <path> | --content <text>) [--title <title>] [--format html|markdown|text|json|code|svg|mermaid|react] [--tag tag]
|
|
320
|
-
artifacty install claude|codex|gemini|all [--dry-run] [--config <path>] [--server-path <path>] [--url http://127.0.0.1:8787] [--timeout 30000]
|
|
366
|
+
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]
|
|
367
|
+
artifacty install claude|codex|gemini|copilot|cursor|all [--dry-run] [--config <path>] [--server-path <path>] [--url http://127.0.0.1:8787] [--timeout 30000]
|
|
321
368
|
artifacty check [--server-path <path>] [--timeout 5000]
|
|
322
369
|
artifacty update <id> (--file <path> | --content <text>) [--title <title>] [--format html|markdown|text|json|code|svg|mermaid|react]
|
|
323
370
|
artifacty archive <id>
|
|
@@ -353,6 +400,20 @@ function stripInstallContentUnlessDryRun(result) {
|
|
|
353
400
|
return rest;
|
|
354
401
|
}
|
|
355
402
|
|
|
403
|
+
function serverOptions(options) {
|
|
404
|
+
return {
|
|
405
|
+
host: options.host,
|
|
406
|
+
port: options.port,
|
|
407
|
+
home: options.home,
|
|
408
|
+
apiToken: options.apiToken,
|
|
409
|
+
shareMode: options.shareMode,
|
|
410
|
+
allowSecrets: options.allowSecrets,
|
|
411
|
+
generateToken: options.generateToken,
|
|
412
|
+
bytes: options.bytes,
|
|
413
|
+
timeout: options.timeout
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
|
|
356
417
|
function toCamelCase(value) {
|
|
357
418
|
return value.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
358
419
|
}
|