artifactsend 0.0.0-stage → 1.0.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/LICENSE +21 -0
- package/README.md +73 -2
- package/bin/artifactsend.mjs +165 -0
- package/package.json +46 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vela Partners
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,74 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ArtifactSend: tracked links and data rooms for AI agents
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Share a document, pitch deck, HTML page or Claude artifact as a link, and see who read it.** Each reader, how far they read, time per section or slide, clicks, copied text, and the questions they asked. A free DocSend alternative, built for agents: an MCP server, agent skills, a Claude Code plugin and a CLI.
|
|
4
|
+
|
|
5
|
+
- Website: https://artifactsend.com
|
|
6
|
+
- MCP server: `https://artifactsend.com/mcp` (Streamable HTTP, OAuth)
|
|
7
|
+
- Official MCP registry: `com.artifactsend/mcp`
|
|
8
|
+
- For agents: https://artifactsend.com/llms.txt
|
|
9
|
+
|
|
10
|
+
## When an agent should use it
|
|
11
|
+
|
|
12
|
+
- "Share this with Dana and tell me when she reads it."
|
|
13
|
+
- "Send the deck to these five investors, one link each."
|
|
14
|
+
- "Publish this HTML page or Claude artifact as a private link."
|
|
15
|
+
- "Make a data room for the Series A with an NDA."
|
|
16
|
+
- "Who read the proposal? What did they ask?"
|
|
17
|
+
- "Read this artifactsend.com link someone sent me."
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
| Where | How |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| Claude Code | `claude mcp add --transport http artifactsend https://artifactsend.com/mcp`, then `/mcp` to sign in |
|
|
24
|
+
| Every agent on this computer | `npx artifactsend setup` (Claude Code, Cursor, VS Code, Windsurf, Gemini CLI, Codex, plus the skills) |
|
|
25
|
+
| Skills | `npx skills add LLM-preneur/skills` |
|
|
26
|
+
| Claude Code plugin | `/plugin marketplace add LLM-preneur/skills`, then `/plugin install artifactsend@llm-preneur` |
|
|
27
|
+
| Cursor | [Add to Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=artifactsend&config=eyJ1cmwiOiJodHRwczovL2FydGlmYWN0c2VuZC5jb20vbWNwIn0=) |
|
|
28
|
+
| VS Code | [Add to VS Code](https://insiders.vscode.dev/redirect/mcp/install?name=artifactsend&config=%7B%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A//artifactsend.com/mcp%22%7D) |
|
|
29
|
+
| Claude.ai | Settings, Connectors, Add custom connector, URL `https://artifactsend.com/mcp` |
|
|
30
|
+
| ChatGPT | Settings, Apps, Developer mode on, Create app, URL `https://artifactsend.com/mcp`, OAuth |
|
|
31
|
+
| Codex | `codex mcp add artifactsend --url https://artifactsend.com/mcp` |
|
|
32
|
+
| Gemini CLI | `gemini mcp add --transport http artifactsend https://artifactsend.com/mcp` |
|
|
33
|
+
| stdio-only clients | `npx -y artifactsend mcp` with `ARTIFACTSEND_TOKEN` set |
|
|
34
|
+
|
|
35
|
+
Sign in once with your email or Google. Links, readers and reports are free.
|
|
36
|
+
|
|
37
|
+
## Skills
|
|
38
|
+
|
|
39
|
+
| Skill | Use it when |
|
|
40
|
+
| --- | --- |
|
|
41
|
+
| [share-with-tracking](https://github.com/LLM-preneur/skills/tree/main/skills/share-with-tracking/SKILL.md) | sharing a file or page and knowing who read it; one link per person; reading reports |
|
|
42
|
+
| [data-room](https://github.com/LLM-preneur/skills/tree/main/skills/data-room/SKILL.md) | several documents behind one link, with folders, an NDA and watermarks |
|
|
43
|
+
| [read-shared-link](https://github.com/LLM-preneur/skills/tree/main/skills/read-shared-link/SKILL.md) | someone sent you an artifactsend.com link |
|
|
44
|
+
|
|
45
|
+
## MCP tools
|
|
46
|
+
|
|
47
|
+
**Share:** `send_artifact` (HTML, React, Markdown, PDF, Word, PowerPoint, Excel or a URL), `update_artifact`, `link_for_person`, `make_data_room`, `upload_file`, `get_artifact`, `update_link`.
|
|
48
|
+
|
|
49
|
+
**See who read it:** `list_links`, `link_report`, `reader_activity`, `recent_activity`, `room_report`, `list_questions`, `list_comments`, `website_visits`, `schedule_digest`.
|
|
50
|
+
|
|
51
|
+
**Read what others share with you:** `open_link`, `read_shared`, `ask_shared`, `message_shared_sender`, `shared_with_me`.
|
|
52
|
+
|
|
53
|
+
Reading tools are marked read-only. Tools that change things are marked so the app asks first.
|
|
54
|
+
|
|
55
|
+
## CLI
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npx artifactsend setup # add ArtifactSend to your agents
|
|
59
|
+
export ARTIFACTSEND_TOKEN=as_... # from https://artifactsend.com/app/settings
|
|
60
|
+
npx artifactsend send deck.pdf --title "Seed deck" --access email
|
|
61
|
+
npx artifactsend send page.html --allow @acme.com --expires 14
|
|
62
|
+
npx artifactsend links
|
|
63
|
+
npx artifactsend report https://artifactsend.com/d/ab12cd34
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Readers and their AI
|
|
67
|
+
|
|
68
|
+
Readers open a link in the browser, or through their own AI. Every link also has its own MCP address (the link plus `/mcp`) that needs no key. By default a reader's AI gets the outline and only the parts that answer each question, so the sender sees every question and no full copy leaves. Readers are told what the sender sees, and never their chat or their AI's answers. Rules: https://artifactsend.com/ai-rules
|
|
69
|
+
|
|
70
|
+
## Price
|
|
71
|
+
|
|
72
|
+
Free and unlimited for links, readers, doors, reports and data rooms. Sending and updating through MCP is free. AI answers to readers are paid per answer. https://artifactsend.com/pricing
|
|
73
|
+
|
|
74
|
+
Made by [Vela Partners](https://vela.partners). MIT licensed.
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// ArtifactSend from the command line: add the MCP server to your agents, send a file as a tracked link,
|
|
3
|
+
// read who opened it, or bridge stdio-only MCP clients to https://artifactsend.com/mcp. No dependencies.
|
|
4
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync, copyFileSync } from 'node:fs';
|
|
5
|
+
import { homedir, platform } from 'node:os';
|
|
6
|
+
import { join, dirname, basename, extname } from 'node:path';
|
|
7
|
+
import { spawnSync } from 'node:child_process';
|
|
8
|
+
import { createInterface } from 'node:readline';
|
|
9
|
+
|
|
10
|
+
const ORIGIN = (process.env.ARTIFACTSEND_URL || 'https://artifactsend.com').replace(/\/$/, '');
|
|
11
|
+
const MCP = ORIGIN + '/mcp';
|
|
12
|
+
const SKILLS = 'LLM-preneur/skills';
|
|
13
|
+
const VERSION = '1.0.0';
|
|
14
|
+
const [cmd, ...rest] = process.argv.slice(2);
|
|
15
|
+
|
|
16
|
+
const HELP = `ArtifactSend: the link that tells you who read it.
|
|
17
|
+
|
|
18
|
+
npx artifactsend setup Add ArtifactSend to Claude Code, Cursor, VS Code, Windsurf, Gemini CLI and Codex
|
|
19
|
+
npx artifactsend send <file> Share a file as a tracked link (HTML, Markdown, PDF, Word, PowerPoint, Excel, JSX)
|
|
20
|
+
--title "Seed deck" --access public|email|verified --allow @acme.com,dana@x.com
|
|
21
|
+
--expires 14 --folder Investors --ai questions|full|off --link <existing link to update>
|
|
22
|
+
npx artifactsend links Your links with views and last open
|
|
23
|
+
npx artifactsend report <link> Who read it, how far, time per section, what they asked
|
|
24
|
+
npx artifactsend mcp Run as a stdio MCP server (bridges to ${MCP})
|
|
25
|
+
|
|
26
|
+
send, links, report and mcp need ARTIFACTSEND_TOKEN (make one at ${ORIGIN}/app/settings).
|
|
27
|
+
In Claude Code you can skip the token: claude mcp add --transport http artifactsend ${MCP}, then /mcp to sign in.
|
|
28
|
+
Claude.ai and ChatGPT: add a custom connector with the URL ${MCP}.`;
|
|
29
|
+
|
|
30
|
+
const flags = (args) => {
|
|
31
|
+
const o = { _: [] };
|
|
32
|
+
for (let i = 0; i < args.length; i++) {
|
|
33
|
+
const a = args[i];
|
|
34
|
+
if (a.startsWith('--')) { const k = a.slice(2); const n = args[i + 1]; if (n === undefined || n.startsWith('--')) o[k] = true; else { o[k] = n; i++; } } else o._.push(a);
|
|
35
|
+
}
|
|
36
|
+
return o;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// ---------- setup ----------
|
|
40
|
+
const readJson = (f) => { if (!existsSync(f)) return {}; const t = readFileSync(f, 'utf8').trim(); return t ? JSON.parse(t) : {}; };
|
|
41
|
+
const writeJson = (f, o) => { mkdirSync(dirname(f), { recursive: true }); if (existsSync(f)) copyFileSync(f, f + '.bak'); writeFileSync(f, JSON.stringify(o, null, 2) + '\n'); };
|
|
42
|
+
const has = (bin) => spawnSync(platform() === 'win32' ? 'where' : 'which', [bin], { stdio: 'ignore' }).status === 0;
|
|
43
|
+
|
|
44
|
+
function addJson(label, file, key, entry, dirMustExist) {
|
|
45
|
+
if (!existsSync(dirMustExist)) return null;
|
|
46
|
+
let o;
|
|
47
|
+
try { o = readJson(file); } catch { return `${label}: skipped, ${file} is not plain JSON. Add ${JSON.stringify({ artifactsend: entry })} under "${key}" yourself.`; }
|
|
48
|
+
o[key] = o[key] || {};
|
|
49
|
+
if (o[key].artifactsend) return `${label}: already added`;
|
|
50
|
+
o[key].artifactsend = entry;
|
|
51
|
+
writeJson(file, o);
|
|
52
|
+
return `${label}: added to ${file}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function setup(opts) {
|
|
56
|
+
const h = homedir();
|
|
57
|
+
const out = [];
|
|
58
|
+
if (has('claude')) {
|
|
59
|
+
const r = spawnSync('claude', ['mcp', 'add', '--transport', 'http', '--scope', 'user', 'artifactsend', MCP], { encoding: 'utf8' });
|
|
60
|
+
const said = (r.stdout + r.stderr).toLowerCase();
|
|
61
|
+
out.push(r.status === 0 ? 'Claude Code: added. Run /mcp in Claude Code and choose artifactsend to sign in.' : said.includes('already exists') ? 'Claude Code: already added' : 'Claude Code: could not add (' + said.trim().split('\n')[0] + ')');
|
|
62
|
+
}
|
|
63
|
+
out.push(addJson('Cursor', join(h, '.cursor', 'mcp.json'), 'mcpServers', { url: MCP }, join(h, '.cursor')));
|
|
64
|
+
out.push(addJson('Windsurf', join(h, '.codeium', 'windsurf', 'mcp_config.json'), 'mcpServers', { serverUrl: MCP }, join(h, '.codeium', 'windsurf')));
|
|
65
|
+
out.push(addJson('Gemini CLI', join(h, '.gemini', 'settings.json'), 'mcpServers', { httpUrl: MCP }, join(h, '.gemini')));
|
|
66
|
+
const code = platform() === 'darwin' ? join(h, 'Library', 'Application Support', 'Code', 'User') : platform() === 'win32' ? join(process.env.APPDATA || '', 'Code', 'User') : join(h, '.config', 'Code', 'User');
|
|
67
|
+
out.push(addJson('VS Code', join(code, 'mcp.json'), 'servers', { type: 'http', url: MCP }, code));
|
|
68
|
+
const codex = join(h, '.codex');
|
|
69
|
+
if (existsSync(codex)) {
|
|
70
|
+
const f = join(codex, 'config.toml');
|
|
71
|
+
const t = existsSync(f) ? readFileSync(f, 'utf8') : '';
|
|
72
|
+
if (/^\[mcp_servers\.artifactsend\]/m.test(t)) out.push('Codex: already added');
|
|
73
|
+
else { if (t) copyFileSync(f, f + '.bak'); writeFileSync(f, t + (t && !t.endsWith('\n') ? '\n' : '') + `\n[mcp_servers.artifactsend]\nurl = "${MCP}"\n`); out.push(`Codex: added to ${f}`); }
|
|
74
|
+
}
|
|
75
|
+
const done = out.filter(Boolean);
|
|
76
|
+
if (!opts['no-skills']) {
|
|
77
|
+
const r = spawnSync('npx', ['-y', 'skills', 'add', SKILLS, '-g', '-y'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], shell: platform() === 'win32' });
|
|
78
|
+
done.push(r.status === 0 ? `Skills: installed ${SKILLS} (share-with-tracking, data-room, read-shared-link)` : `Skills: run npx skills add ${SKILLS} to install them`);
|
|
79
|
+
}
|
|
80
|
+
console.log(done.length ? done.join('\n') : 'No agents found on this computer.');
|
|
81
|
+
console.log(`\nClaude.ai and ChatGPT: add a custom connector with the URL ${MCP}\nThen ask your agent: "Share this as a tracked link and tell me who reads it."`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ---------- MCP over HTTP ----------
|
|
85
|
+
const token = () => {
|
|
86
|
+
const t = process.env.ARTIFACTSEND_TOKEN;
|
|
87
|
+
if (!t) { console.error(`Set ARTIFACTSEND_TOKEN first. Make one at ${ORIGIN}/app/settings`); process.exit(2); }
|
|
88
|
+
return t;
|
|
89
|
+
};
|
|
90
|
+
let rpcId = 0;
|
|
91
|
+
async function rpc(method, params, tk = token()) {
|
|
92
|
+
const r = await fetch(MCP, { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json, text/event-stream', Authorization: 'Bearer ' + tk, 'User-Agent': 'artifactsend-cli/' + VERSION }, body: JSON.stringify({ jsonrpc: '2.0', id: ++rpcId, method, params }) });
|
|
93
|
+
const text = await r.text();
|
|
94
|
+
let body;
|
|
95
|
+
try { body = JSON.parse(text.startsWith('event:') || text.startsWith('data:') ? text.split('\n').filter((l) => l.startsWith('data:')).pop().slice(5) : text); } catch { throw new Error(`HTTP ${r.status}: ${text.slice(0, 200)}`); }
|
|
96
|
+
if (body.error) throw new Error(body.error.message);
|
|
97
|
+
return body.result;
|
|
98
|
+
}
|
|
99
|
+
async function call(name, args) {
|
|
100
|
+
const res = await rpc('tools/call', { name, arguments: args });
|
|
101
|
+
const text = (res.content || []).map((c) => c.text || '').join('\n');
|
|
102
|
+
if (res.isError) throw new Error(text);
|
|
103
|
+
try { return JSON.parse(text); } catch { return text; }
|
|
104
|
+
}
|
|
105
|
+
const print = (v) => console.log(typeof v === 'string' ? v : JSON.stringify(v, null, 2));
|
|
106
|
+
|
|
107
|
+
const DOCS = new Set(['.pdf', '.doc', '.docx', '.ppt', '.pptx', '.xls', '.xlsx', '.key', '.odt', '.odp', '.ods']);
|
|
108
|
+
async function send(o) {
|
|
109
|
+
const file = o._[0];
|
|
110
|
+
if (!file) { console.error('Usage: npx artifactsend send <file> [--title ...]'); process.exit(2); }
|
|
111
|
+
const ext = extname(file).toLowerCase();
|
|
112
|
+
const a = {};
|
|
113
|
+
if (/^https?:\/\//.test(file)) a.url = file;
|
|
114
|
+
else if (DOCS.has(ext)) a.document = { name: basename(file), base64: readFileSync(file).toString('base64') };
|
|
115
|
+
else if (ext === '.md' || ext === '.markdown') a.markdown = readFileSync(file, 'utf8');
|
|
116
|
+
else if (ext === '.jsx' || ext === '.tsx') a.react = readFileSync(file, 'utf8');
|
|
117
|
+
else a.html = readFileSync(file, 'utf8');
|
|
118
|
+
if (o.title) a.title = o.title;
|
|
119
|
+
if (o.access) a.access = o.access;
|
|
120
|
+
if (o.allow) a.allow = String(o.allow).split(',').map((s) => s.trim()).filter(Boolean);
|
|
121
|
+
if (o.expires) a.expires_in_days = Number(o.expires);
|
|
122
|
+
if (o.folder) a.folder = o.folder;
|
|
123
|
+
if (o.ai) a.ai_reading = o.ai;
|
|
124
|
+
if (o.link) a.link = o.link;
|
|
125
|
+
if (o['no-notify']) a.notify = false;
|
|
126
|
+
const r = await call('send_artifact', a);
|
|
127
|
+
if (r && r.url) { console.log(r.url); if (r.settings) for (const [k, v] of Object.entries(r.settings)) if (v !== null && typeof v !== 'object') console.log(` ${k.replace(/_/g, ' ')}: ${v}`); }
|
|
128
|
+
else print(r);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// stdio <-> HTTP bridge, one JSON-RPC message per line.
|
|
132
|
+
async function bridge() {
|
|
133
|
+
const tk = token();
|
|
134
|
+
const rl = createInterface({ input: process.stdin });
|
|
135
|
+
let sid = null;
|
|
136
|
+
for await (const line of rl) {
|
|
137
|
+
if (!line.trim()) continue;
|
|
138
|
+
let msg;
|
|
139
|
+
try { msg = JSON.parse(line); } catch { continue; }
|
|
140
|
+
try {
|
|
141
|
+
const r = await fetch(MCP, { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json, text/event-stream', Authorization: 'Bearer ' + tk, 'User-Agent': 'artifactsend-cli/' + VERSION, ...(sid ? { 'Mcp-Session-Id': sid } : {}) }, body: line });
|
|
142
|
+
sid = r.headers.get('mcp-session-id') || sid;
|
|
143
|
+
const text = await r.text();
|
|
144
|
+
if (!text.trim()) continue;
|
|
145
|
+
const parts = text.startsWith('event:') || text.startsWith('data:') ? text.split('\n').filter((l) => l.startsWith('data:')).map((l) => l.slice(5).trim()) : [text];
|
|
146
|
+
for (const p of parts) process.stdout.write(JSON.stringify(JSON.parse(p)) + '\n');
|
|
147
|
+
} catch (e) {
|
|
148
|
+
if (msg.id !== undefined) process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: msg.id, error: { code: -32603, message: String(e.message || e) } }) + '\n');
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const o = flags(rest);
|
|
154
|
+
try {
|
|
155
|
+
if (cmd === 'setup' || cmd === 'init' || cmd === 'install') setup(o);
|
|
156
|
+
else if (cmd === 'send') await send(o);
|
|
157
|
+
else if (cmd === 'links') print(await call('list_links', o._[0] ? { query: o._.join(' ') } : {}));
|
|
158
|
+
else if (cmd === 'report') { if (!o._[0]) { console.error('Usage: npx artifactsend report <link>'); process.exit(2); } print(await call('link_report', { link: o._[0] })); }
|
|
159
|
+
else if (cmd === 'mcp') await bridge();
|
|
160
|
+
else if (cmd === '--version' || cmd === '-v') console.log(VERSION);
|
|
161
|
+
else console.log(HELP);
|
|
162
|
+
} catch (e) {
|
|
163
|
+
console.error(String(e.message || e));
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,48 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "artifactsend",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Share documents, decks, HTML pages and Claude artifacts as tracked links and data rooms. See who read them and what they asked. MCP server, agent skills and CLI.",
|
|
5
|
+
"mcpName": "com.artifactsend/mcp",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"artifactsend": "bin/artifactsend.mjs"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"bin",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=18"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"mcp",
|
|
20
|
+
"mcp-server",
|
|
21
|
+
"model-context-protocol",
|
|
22
|
+
"agent-skills",
|
|
23
|
+
"claude",
|
|
24
|
+
"claude-code",
|
|
25
|
+
"chatgpt",
|
|
26
|
+
"cursor",
|
|
27
|
+
"docsend",
|
|
28
|
+
"docsend-alternative",
|
|
29
|
+
"document-tracking",
|
|
30
|
+
"data-room",
|
|
31
|
+
"share-html",
|
|
32
|
+
"publish-html",
|
|
33
|
+
"artifacts",
|
|
34
|
+
"pitch-deck",
|
|
35
|
+
"analytics"
|
|
36
|
+
],
|
|
37
|
+
"homepage": "https://artifactsend.com",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/LLM-preneur/skills.git",
|
|
41
|
+
"directory": "artifactsend"
|
|
42
|
+
},
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/LLM-preneur/skills/issues"
|
|
45
|
+
},
|
|
46
|
+
"author": "Vela Partners (https://vela.partners)",
|
|
47
|
+
"license": "MIT"
|
|
48
|
+
}
|