artifacty 0.1.2 → 0.3.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
 
@@ -23,6 +23,8 @@ Artifacty shares LLM artifacts over HTTP, CLI, and MCP.
23
23
  - `node src/cli.js import --agent claude --file artifact.html`: convert and store an external artifact.
24
24
  - `node src/cli.js install claude --dry-run`: preview generated MCP config.
25
25
  - `node src/cli.js check`: verify MCP tool discovery.
26
+ - `node src/cli.js index rebuild`: rebuild the optional SQLite FTS5 search index.
27
+ - `node src/cli.js integrity`: verify version files, hashes, and orphaned files.
26
28
 
27
29
  ## Coding Style & Naming Conventions
28
30
 
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
 
@@ -70,6 +70,8 @@ Install MCP configuration for local agents:
70
70
  artifacty install claude
71
71
  artifacty install codex --dry-run
72
72
  artifacty install gemini
73
+ artifacty install copilot
74
+ artifacty install cursor
73
75
  artifacty install all
74
76
  artifacty check
75
77
  ```
@@ -77,7 +79,7 @@ artifacty check
77
79
  Use `artifacty install codex --timeout 30000` or
78
80
  `artifacty install gemini --timeout 30000` to tune supported MCP client timeouts.
79
81
 
80
- 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.
81
83
 
82
84
  ## Quick Start
83
85
 
@@ -113,11 +115,14 @@ Import an artifact produced by another agent and convert it to Artifacty format:
113
115
  artifacty import --agent claude --file ./deploy-failures.html --tag review
114
116
  artifacty import --agent gemini --content '{"title":"Plan","returnDisplay":"# Plan\n- Ship it"}'
115
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."]}'
116
120
  ```
117
121
 
118
- Codex structured payloads can become `handoff`, `bundle`, `diff-walkthrough`,
119
- `code-review`, or `test-report` artifacts when the payload explicitly identifies
120
- 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
121
126
  `document` unless you pass an explicit `artifactType`.
122
127
 
123
128
  ## Agent Handoff Example
@@ -160,6 +165,7 @@ List artifacts:
160
165
 
161
166
  ```bash
162
167
  artifacty list
168
+ artifacty list --query review --limit 20 --offset 20
163
169
  ```
164
170
 
165
171
  Run the MCP server:
@@ -174,6 +180,8 @@ Operational commands:
174
180
 
175
181
  ```bash
176
182
  artifacty audit --limit 20
183
+ artifacty index rebuild
184
+ artifacty integrity
177
185
  artifacty backup
178
186
  artifacty export --file ./artifacty-backup.json
179
187
  artifacty import-store --file ./artifacty-backup.json
@@ -195,6 +203,13 @@ ARTIFACTY_HOME=/path/to/shared/store artifacty serve
195
203
 
196
204
  Artifact metadata is stored in `artifacty.sqlite`; artifact content is stored as immutable version files under `artifacts/`. The current browser server URL is written to `server.json` so MCP tools can return the correct links when the default port falls back. Existing `index.json` stores are migrated automatically on first access.
197
205
 
206
+ Search uses a SQLite FTS5 index when the local Node SQLite build supports it. The index covers the latest version body plus title, tags, source agent, artifact type, format, and metadata summary. If FTS5 is unavailable, Artifacty keeps working with metadata search. Rebuild or check the store when needed:
207
+
208
+ ```bash
209
+ artifacty index rebuild
210
+ artifacty integrity
211
+ ```
212
+
198
213
  ## API Example
199
214
 
200
215
  Start a protected server in another terminal, or generate a reusable shell token first:
@@ -236,10 +251,17 @@ Browser routes:
236
251
  - `/`: list artifacts with search, tag, and source filters.
237
252
  - `/new`: create an Artifacty-native artifact with the CodeMirror editor.
238
253
  - `/import`: paste an external agent artifact and convert it with automatic editor mode detection.
239
- - `/artifacts/:id/edit`: save a new version with Markdown, HTML, JSON, text, code, SVG, Mermaid, or React syntax support.
254
+ - `/artifacts/:id/edit`: save a new version with Markdown, HTML, JSON, text, code, SVG, Mermaid, React, SARIF, CSV, image, or video syntax support.
240
255
  - `/artifacts/:id/diff`: compare versions.
241
256
  - `/api/audit`: list audit events.
242
257
 
258
+ List APIs support pagination with `limit` and `offset`. Responses keep the top-level `artifacts` array and include `pagination` and `search` metadata:
259
+
260
+ ```bash
261
+ curl -s "http://127.0.0.1:8787/api/artifacts?q=handoff&limit=20&offset=0" \
262
+ -H "x-artifacty-token: $ARTIFACTY_API_TOKEN"
263
+ ```
264
+
243
265
  ## Interface Language
244
266
 
245
267
  The browser UI defaults to English. Add `?lang=ko` to any browser route to use Korean, for example `http://127.0.0.1:8787/new?lang=ko`. Forms and in-app links preserve the selected language. Documentation is maintained in English only.
@@ -249,8 +271,9 @@ Schema and storage:
249
271
  - Metadata lives in SQLite with `schemaVersion: 1`, `artifactType`, and `archivedAt`.
250
272
  - Archive hides artifacts from default lists without deleting versions.
251
273
  - Bundle artifacts store multiple files or base64 assets as portable JSON.
252
- - Supported formats are `html`, `markdown`, `text`, `json`, `code`, `svg`, `mermaid`, and `react`.
253
- - Diagram, component, and source snippet artifacts use `diagram`, `component`, and `snippet` artifact types.
274
+ - Supported formats are `html`, `markdown`, `text`, `json`, `code`, `svg`, `mermaid`, `react`, `sarif`, `csv`, `image`, and `video`.
275
+ - Diagram, component, source snippet, analysis report, table, and media assets use `diagram`, `component`, `snippet`, `analysis-report`, `table`, and `asset` artifact types.
276
+ - Copilot/Cursor examples cover PR reviews, screenshots, demo recordings, and visual evidence bundles.
254
277
  - See [docs/artifact-schema-v1.md](docs/artifact-schema-v1.md).
255
278
  - See [docs/sarif-csv-artifact-plan.md](docs/sarif-csv-artifact-plan.md) for the SARIF/CSV output artifact roadmap.
256
279
 
@@ -268,6 +291,9 @@ Schema and storage:
268
291
  - 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.
269
292
  - Mermaid artifacts render with the vendored local Mermaid package in a sandboxed iframe without `allow-same-origin`.
270
293
  - 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.
294
+ - SARIF artifacts render a bounded findings summary and keep the full formatted JSON behind a raw-source details panel.
295
+ - CSV artifacts render as an escaped, bounded table; `/raw` preserves the original text.
296
+ - Image and video artifacts store base64 media inline, render safe previews, and decode bytes through `/raw`.
271
297
  - Artifact content should still be treated as untrusted; use the raw view when handing content back to an agent.
272
298
 
273
299
  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.
@@ -42,7 +42,7 @@ Create artifacts directly in the browser at `http://127.0.0.1:8787/new`.
42
42
 
43
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`.
44
44
 
45
- 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`.
46
46
 
47
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.
48
48
 
@@ -70,6 +70,8 @@ Artifacty can write MCP configuration for supported local agents:
70
70
  node src/cli.js install claude
71
71
  node src/cli.js install codex --dry-run
72
72
  node src/cli.js install gemini
73
+ node src/cli.js install copilot
74
+ node src/cli.js install cursor
73
75
  node src/cli.js install all
74
76
  node src/cli.js check
75
77
  ```
@@ -77,6 +79,8 @@ node src/cli.js check
77
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.
78
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.
79
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.
80
84
  - `--dry-run` returns the generated config without writing it.
81
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.
82
86
  - `check` starts the local MCP server and verifies required tools through `initialize` and `tools/list`.
@@ -114,7 +118,7 @@ Project-scoped `.mcp.json` shape:
114
118
  }
115
119
  ```
116
120
 
117
- 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.
118
122
 
119
123
  Claude Code uses a 30 second MCP startup timeout by default. If a slower
120
124
  environment needs more time, launch Claude Code with a larger `MCP_TIMEOUT`
@@ -181,7 +185,7 @@ Then run `/mcp` inside Gemini CLI to confirm that the Artifacty tools are connec
181
185
 
182
186
  - `artifacty_create`: create a new Artifacty-native artifact.
183
187
  - `artifacty_publish`: backwards-compatible alias for `artifacty_create`.
184
- - `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.
185
189
  - `artifacty_list`: discover artifacts by query, tag, or source agent.
186
190
  - `artifacty_get`: read artifact metadata and content.
187
191
  - `artifacty_update`: append a new version.
@@ -200,6 +204,10 @@ Use `artifacty_import` or the CLI `import` command when the artifact was produce
200
204
  node src/cli.js import --agent claude --file ./artifact.html --tag review
201
205
  node src/cli.js import --agent codex --file ./handoff.md --tag handoff
202
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
203
211
  node src/cli.js import --agent gemini --content '{"title":"Options","returnDisplay":"# Options\n- A\n- B"}'
204
212
  ```
205
213
 
@@ -207,11 +215,17 @@ Supported converter inputs:
207
215
 
208
216
  - Claude: local `.html`, `.htm`, `.md`, `.svg`, `.mmd`, `.jsx`, `.tsx`, source files, or JSON payloads with `title`/`content`/Claude artifact `type`.
209
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`.
210
220
  - Gemini: `returnDisplay`, `llmContent`, text blocks, or local markdown/text/json files.
211
- - 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.
212
222
 
213
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`.
214
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
+
215
229
  ## HTTP API
216
230
 
217
231
  - `GET /`: dashboard.
@@ -245,6 +259,9 @@ Renderer notes:
245
259
  - `svg` artifacts render in a scriptless sandboxed iframe after viewer-side sanitization; `/raw` still returns the original SVG.
246
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`.
247
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`.
248
265
 
249
266
  ## Background Service
250
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.2",
3
+ "version": "0.3.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
@@ -4,11 +4,13 @@ import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import {
6
6
  archiveArtifact,
7
+ checkStoreIntegrity,
7
8
  createArtifact,
8
9
  createStore,
9
10
  getArtifact,
10
11
  listAuditEvents,
11
- listArtifacts,
12
+ listArtifactsPage,
13
+ rebuildSearchIndex,
12
14
  restoreArtifact,
13
15
  updateArtifact
14
16
  } from "./lib/storage.js";
@@ -145,7 +147,7 @@ async function main() {
145
147
  if (command === "install") {
146
148
  const agent = options._[0];
147
149
  if (!agent) {
148
- throw new Error("install requires an agent: claude, codex, gemini, or all");
150
+ throw new Error("install requires an agent: claude, codex, gemini, copilot, cursor, or all");
149
151
  }
150
152
  const result = await installAgent(agent, {
151
153
  projectDir: options.projectDir || process.cwd(),
@@ -200,14 +202,37 @@ async function main() {
200
202
  }
201
203
 
202
204
  if (command === "list") {
203
- const artifacts = await listArtifacts(store, {
205
+ const page = await listArtifactsPage(store, {
204
206
  query: options.query,
205
207
  tag: Array.isArray(options.tag) ? options.tag[0] : options.tag,
206
208
  sourceAgent: options.source,
207
209
  includeArchived: options.includeArchived,
208
- limit: options.limit
210
+ limit: options.limit,
211
+ offset: options.offset
212
+ });
213
+ printJson({
214
+ artifacts: page.artifacts,
215
+ pagination: paginationJson(page),
216
+ search: page.search
209
217
  });
210
- printJson({ artifacts });
218
+ return;
219
+ }
220
+
221
+ if ((command === "index" || command === "search") && options._[0] === "rebuild") {
222
+ const result = await rebuildSearchIndex(store);
223
+ printJson(result);
224
+ if (!result.fts5) {
225
+ process.exitCode = 1;
226
+ }
227
+ return;
228
+ }
229
+
230
+ if (command === "integrity" || command === "check-store") {
231
+ const result = await checkStoreIntegrity(store);
232
+ printJson(result);
233
+ if (!result.ok) {
234
+ process.exitCode = 1;
235
+ }
211
236
  return;
212
237
  }
213
238
 
@@ -298,7 +323,7 @@ function parseArgs(args) {
298
323
 
299
324
  if (key === "tag") {
300
325
  options.tag = [...(options.tag || []), value];
301
- } else if (key === "port" || key === "limit" || key === "version" || key === "schema-version" || key === "timeout" || key === "bytes") {
326
+ } else if (key === "port" || key === "limit" || key === "offset" || key === "version" || key === "schema-version" || key === "timeout" || key === "bytes") {
302
327
  options[toCamelCase(key)] = Number(value);
303
328
  } else {
304
329
  options[toCamelCase(key)] = value;
@@ -311,7 +336,11 @@ function parseArgs(args) {
311
336
 
312
337
  async function readContent(options) {
313
338
  if (options.file) {
314
- return readFile(options.file, "utf8");
339
+ const filePath = path.resolve(options.file);
340
+ if (shouldReadFileAsBase64(options, filePath)) {
341
+ return (await readFile(filePath)).toString("base64");
342
+ }
343
+ return readFile(filePath, "utf8");
315
344
  }
316
345
  if (options.content !== undefined) {
317
346
  return options.content;
@@ -319,6 +348,16 @@ async function readContent(options) {
319
348
  throw new Error("Provide --file or --content");
320
349
  }
321
350
 
351
+ function shouldReadFileAsBase64(options, filePath) {
352
+ const format = String(options.format || "").toLowerCase();
353
+ const contentType = String(options.contentType || "").toLowerCase();
354
+ return format === "image" ||
355
+ format === "video" ||
356
+ contentType.startsWith("image/") ||
357
+ contentType.startsWith("video/") ||
358
+ /\.(png|jpe?g|gif|webp|mp4|webm)$/i.test(filePath);
359
+ }
360
+
322
361
  async function withUrls(store, artifact) {
323
362
  const publicBaseUrl = await resolvePublicBaseUrl(store);
324
363
  return {
@@ -328,6 +367,17 @@ async function withUrls(store, artifact) {
328
367
  };
329
368
  }
330
369
 
370
+ function paginationJson(page) {
371
+ return {
372
+ total: page.total,
373
+ limit: page.limit,
374
+ offset: page.offset,
375
+ hasMore: page.hasMore,
376
+ nextOffset: page.nextOffset,
377
+ previousOffset: page.previousOffset
378
+ };
379
+ }
380
+
331
381
  function requireOption(options, name) {
332
382
  if (!options[name]) {
333
383
  throw new Error(`Missing required option --${name}`);
@@ -349,18 +399,20 @@ Usage:
349
399
  artifacty status [--home ~/.artifacty]
350
400
  artifacty stop [--home ~/.artifacty] [--timeout 5000] [--force]
351
401
  artifacty publish --title <title> (--file <path> | --content <text>) [--format html|markdown|text|json|code|svg|mermaid|react] [--source agent] [--tag tag]
352
- artifacty import --agent claude|codex|gemini|auto (--file <path> | --content <text>) [--title <title>] [--format html|markdown|text|json|code|svg|mermaid|react] [--tag tag]
353
- artifacty install claude|codex|gemini|all [--dry-run] [--config <path>] [--server-path <path>] [--url http://127.0.0.1:8787] [--timeout 30000]
402
+ 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]
403
+ artifacty install claude|codex|gemini|copilot|cursor|all [--dry-run] [--config <path>] [--server-path <path>] [--url http://127.0.0.1:8787] [--timeout 30000]
354
404
  artifacty check [--server-path <path>] [--timeout 5000]
355
405
  artifacty update <id> (--file <path> | --content <text>) [--title <title>] [--format html|markdown|text|json|code|svg|mermaid|react]
356
406
  artifacty archive <id>
357
407
  artifacty restore <id>
358
408
  artifacty audit [--artifact <id>] [--limit 100]
409
+ artifacty index rebuild
410
+ artifacty integrity
359
411
  artifacty export --file <path>
360
412
  artifacty backup [--file <path>]
361
413
  artifacty import-store --file <path>
362
414
  artifacty service plist|install|uninstall [--dry-run] [--plist <path>]
363
- artifacty list [--query text] [--tag tag] [--source agent] [--limit 50] [--include-archived]
415
+ artifacty list [--query text] [--tag tag] [--source agent] [--limit 50] [--offset 0] [--include-archived]
364
416
  artifacty show <id> [--version n] [--raw]
365
417
 
366
418
  Environment: