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 +4 -2
- package/README.md +34 -8
- package/docs/artifact-schema-v1.md +27 -5
- package/docs/integrations.md +21 -4
- package/docs/sarif-csv-artifact-plan.md +44 -65
- package/package.json +1 -1
- package/src/cli.js +62 -10
- package/src/client/editor.js +76 -4
- package/src/lib/converters.js +429 -44
- package/src/lib/i18n.js +8 -0
- package/src/lib/installer.js +58 -4
- package/src/lib/render.js +492 -4
- package/src/lib/storage.js +490 -33
- package/src/mcp-server.js +18 -8
- package/src/server.js +69 -10
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
|
|
|
@@ -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)
|
|
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
|
|
|
@@ -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,
|
|
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`,
|
|
119
|
-
`code-review`, or `test-report` artifacts when
|
|
120
|
-
|
|
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
|
|
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 `
|
|
253
|
-
- Diagram, component,
|
|
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 `
|
|
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
|
@@ -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
|
|
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
|
|
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
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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:
|