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 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, and Gemini CLI.
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: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
6
  [![Node.js >=22.5](https://img.shields.io/badge/node-%3E%3D22.5-339933.svg)](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
  ![Artifacty overview showing multiple AI agents sharing artifacts through a local exchange](docs/assets/artifacty.png)
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
- ARTIFACTY_API_TOKEN="$(artifacty token --raw)" artifacty serve
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, and Gemini CLI setup.
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`, `bundle`, `diff-walkthrough`,
108
- `code-review`, or `test-report` artifacts when the payload explicitly identifies
109
- Codex through `agent` or `sourceAgent`. Plain Codex Markdown stays a normal
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 React syntax support.
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 `react`.
239
- - Diagram, component, and source snippet artifacts use `diagram`, `component`, and `snippet` artifact types.
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 `react`.
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
- - `codexContinuation`: structured Codex handoff metadata such as changed files,
89
- commands, tests, blockers, decisions, next steps, findings, diff text, and
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. Large binary asset externalization is intentionally deferred; schema v1 keeps all converted assets inspectable and portable.
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.
@@ -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 React 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`.
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 Plan
2
-
3
- This plan scopes SARIF and CSV support to **output artifacts** that Codex or
4
- other agents generate for downstream review. It does not cover Codex input
5
- context, appshots, thread state, or client-specific UI state.
6
-
7
- ## Goals
8
-
9
- - Preserve SARIF and CSV files as immutable Artifacty versions.
10
- - Classify common Codex Security exports without requiring manual
11
- `artifactType` overrides.
12
- - Render CSV outputs in a readable table view while keeping `/raw` unchanged.
13
- - Keep SARIF as JSON-first, with future room for a findings-focused viewer.
14
-
15
- ## Current Behavior
16
-
17
- - `.sarif` content is stored as `json` when the payload is valid JSON, but it
18
- currently falls back to `artifactType: "unknown"`.
19
- - `.csv` and `text/csv` content can be stored as `text`, but there is no CSV
20
- detection, table renderer, or artifact-type inference.
21
- - Security findings exported as JSON, CSV, or SARIF can be shared today, but the
22
- browsing experience is not yet tailored to review workflows.
23
-
24
- ## Phase 1: Detection and Taxonomy
25
-
26
- - Detect `.sarif` and `application/sarif+json` as `json`.
27
- - Detect SARIF shape (`version`, `runs[]`, `tool.driver`) and classify as
28
- `code-review`.
29
- - Detect `.csv` and `text/csv` as either a new `csv` format or `text` with
30
- `metadata.delimitedText`.
31
- - Infer `code-review` for CSV/SARIF files named like `findings`, `security`,
32
- `review`, or containing columns such as `severity`, `file`, and `message`.
33
-
34
- Exit criteria: CLI, HTTP, and MCP imports classify SARIF and common findings CSV
35
- without explicit overrides.
36
-
37
- ## Phase 2: CSV Viewer
38
-
39
- - Add a lightweight RFC 4180-style CSV parser for browser rendering.
40
- - Render CSV as a scrollable table with sticky headers and escaped cell content.
41
- - Cap rendered rows and columns for very large files, with a visible truncation
42
- notice and a link to `/raw`.
43
- - Preserve plain text fallback when parsing fails.
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "artifacty",
3
- "version": "0.1.1",
3
+ "version": "0.2.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
@@ -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
- return readFile(options.file, "utf8");
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
  }