artisense 0.1.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/dist/index.js +304 -0
- package/package.json +17 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/commands/skill.ts
|
|
4
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
5
|
+
import { resolve as resolve2, dirname } from "node:path";
|
|
6
|
+
|
|
7
|
+
// src/config.ts
|
|
8
|
+
import { readFile } from "node:fs/promises";
|
|
9
|
+
import { resolve } from "node:path";
|
|
10
|
+
var DEFAULT_BASE_URL = "https://artisense.app";
|
|
11
|
+
function getApiKey() {
|
|
12
|
+
const key = process.env.ARTISENSE_API_KEY;
|
|
13
|
+
if (!key) {
|
|
14
|
+
console.error(`Error: ARTISENSE_API_KEY is not set.
|
|
15
|
+
Set it in your .env or shell environment.`);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
return key;
|
|
19
|
+
}
|
|
20
|
+
async function getBaseUrl() {
|
|
21
|
+
if (process.env.ARTISENSE_BASE_URL) {
|
|
22
|
+
return process.env.ARTISENSE_BASE_URL.replace(/\/$/, "");
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const skillPath = resolve(process.cwd(), "SKILL.md");
|
|
26
|
+
const content = await readFile(skillPath, "utf-8");
|
|
27
|
+
const match = content.match(/^Base URL:\s*(.+)$/m);
|
|
28
|
+
if (match) {
|
|
29
|
+
return match[1].trim().replace(/\/$/, "");
|
|
30
|
+
}
|
|
31
|
+
} catch {}
|
|
32
|
+
return DEFAULT_BASE_URL;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// src/commands/skill.ts
|
|
36
|
+
var TARGETS = {
|
|
37
|
+
claude: {
|
|
38
|
+
path: ".claude/commands/artisense.md",
|
|
39
|
+
label: "Claude Code",
|
|
40
|
+
wrap: (c) => c
|
|
41
|
+
},
|
|
42
|
+
cursor: {
|
|
43
|
+
path: ".cursor/rules/artisense.mdc",
|
|
44
|
+
label: "Cursor",
|
|
45
|
+
wrap: (c) => `---
|
|
46
|
+
description: Artisense API skill for managing documents
|
|
47
|
+
globs:
|
|
48
|
+
alwaysApply: false
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
${c}`
|
|
52
|
+
},
|
|
53
|
+
copilot: {
|
|
54
|
+
path: ".github/copilot-instructions.md",
|
|
55
|
+
label: "GitHub Copilot",
|
|
56
|
+
wrap: (c) => c
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
var ALL_TARGET_KEYS = Object.keys(TARGETS);
|
|
60
|
+
async function skillCommand(args) {
|
|
61
|
+
const { baseUrl, targetKeys } = parseArgs(args);
|
|
62
|
+
const endpoint = `${baseUrl}/api/v1/skill`;
|
|
63
|
+
console.log(`Downloading SKILL.md from ${endpoint} ...`);
|
|
64
|
+
const res = await fetch(endpoint);
|
|
65
|
+
if (!res.ok) {
|
|
66
|
+
console.error(`Error: Failed to download (HTTP ${res.status})`);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
const content = await res.text();
|
|
70
|
+
const cwd = process.cwd();
|
|
71
|
+
const rootPath = resolve2(cwd, "SKILL.md");
|
|
72
|
+
await writeFile(rootPath, content, "utf-8");
|
|
73
|
+
console.log(` Project root: ${rootPath}`);
|
|
74
|
+
for (const key of targetKeys) {
|
|
75
|
+
const target = TARGETS[key];
|
|
76
|
+
const fullPath = resolve2(cwd, target.path);
|
|
77
|
+
try {
|
|
78
|
+
await mkdir(dirname(fullPath), { recursive: true });
|
|
79
|
+
await writeFile(fullPath, target.wrap(content), "utf-8");
|
|
80
|
+
console.log(` ${target.label}: ${fullPath}`);
|
|
81
|
+
} catch {
|
|
82
|
+
console.warn(` ${target.label}: skipped (cannot write)`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
console.log(`
|
|
86
|
+
Next: set your API key:
|
|
87
|
+
ARTISENSE_API_KEY="ask_..."
|
|
88
|
+
`);
|
|
89
|
+
}
|
|
90
|
+
function parseArgs(args) {
|
|
91
|
+
let baseUrl = DEFAULT_BASE_URL;
|
|
92
|
+
const targetKeys = [];
|
|
93
|
+
for (const arg of args) {
|
|
94
|
+
if (arg === "--help" || arg === "-h") {
|
|
95
|
+
printUsage();
|
|
96
|
+
process.exit(0);
|
|
97
|
+
} else if (arg === "--all") {
|
|
98
|
+
targetKeys.push(...ALL_TARGET_KEYS);
|
|
99
|
+
} else if (arg.startsWith("--")) {
|
|
100
|
+
const key = arg.slice(2);
|
|
101
|
+
if (key in TARGETS) {
|
|
102
|
+
targetKeys.push(key);
|
|
103
|
+
} else {
|
|
104
|
+
console.error(`Unknown option: ${arg}`);
|
|
105
|
+
printUsage();
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
baseUrl = arg.replace(/\/$/, "");
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return { baseUrl, targetKeys };
|
|
113
|
+
}
|
|
114
|
+
function printUsage() {
|
|
115
|
+
console.log(`
|
|
116
|
+
Usage: artisense skill [options]
|
|
117
|
+
|
|
118
|
+
Downloads SKILL.md to your project root.
|
|
119
|
+
|
|
120
|
+
Options:
|
|
121
|
+
--claude Also save to .claude/commands/artisense.md
|
|
122
|
+
--cursor Also save to .cursor/rules/artisense.mdc
|
|
123
|
+
--copilot Also save to .github/copilot-instructions.md
|
|
124
|
+
--all All of the above
|
|
125
|
+
|
|
126
|
+
Examples:
|
|
127
|
+
artisense skill
|
|
128
|
+
artisense skill --claude
|
|
129
|
+
artisense skill --claude --cursor
|
|
130
|
+
artisense skill --all
|
|
131
|
+
`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// src/api.ts
|
|
135
|
+
async function request(baseUrl, path, apiKey, options = {}) {
|
|
136
|
+
const res = await fetch(`${baseUrl}${path}`, {
|
|
137
|
+
method: options.method ?? "GET",
|
|
138
|
+
headers: {
|
|
139
|
+
Authorization: `Bearer ${apiKey}`,
|
|
140
|
+
...options.body ? { "Content-Type": "application/json" } : {}
|
|
141
|
+
},
|
|
142
|
+
body: options.body ? JSON.stringify(options.body) : undefined
|
|
143
|
+
});
|
|
144
|
+
const json = await res.json();
|
|
145
|
+
if (!res.ok) {
|
|
146
|
+
const message = json.error ?? `HTTP ${res.status}`;
|
|
147
|
+
console.error(`Error: ${message}`);
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
return json;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// src/commands/documents.ts
|
|
154
|
+
async function documentsCommand(args) {
|
|
155
|
+
const subcommand = args[0];
|
|
156
|
+
switch (subcommand) {
|
|
157
|
+
case "list":
|
|
158
|
+
case "ls":
|
|
159
|
+
case undefined:
|
|
160
|
+
return listDocuments();
|
|
161
|
+
case "get":
|
|
162
|
+
case "read":
|
|
163
|
+
return getDocument(args[1]);
|
|
164
|
+
case "create":
|
|
165
|
+
return createDocument(args.slice(1));
|
|
166
|
+
case "update":
|
|
167
|
+
return updateDocument(args[1], args.slice(2));
|
|
168
|
+
case "delete":
|
|
169
|
+
case "rm":
|
|
170
|
+
return deleteDocument(args[1]);
|
|
171
|
+
default:
|
|
172
|
+
console.error(`Unknown subcommand: ${subcommand}`);
|
|
173
|
+
printUsage2();
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
async function listDocuments() {
|
|
178
|
+
const [baseUrl, apiKey] = await Promise.all([getBaseUrl(), getApiKey()]);
|
|
179
|
+
const result = await request(baseUrl, "/api/v1/documents", apiKey);
|
|
180
|
+
if (result.data.length === 0) {
|
|
181
|
+
console.log("No documents found.");
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
for (const doc of result.data) {
|
|
185
|
+
const title = doc.title || "(Untitled)";
|
|
186
|
+
console.log(`${doc.id} ${title} [${doc.type}] ${doc.updatedAt}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async function getDocument(id) {
|
|
190
|
+
if (!id) {
|
|
191
|
+
console.error("Usage: artisense docs get <document-id>");
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
const [baseUrl, apiKey] = await Promise.all([getBaseUrl(), getApiKey()]);
|
|
195
|
+
const result = await request(baseUrl, `/api/v1/documents/${id}`, apiKey);
|
|
196
|
+
console.log(JSON.stringify(result.data, null, 2));
|
|
197
|
+
}
|
|
198
|
+
async function createDocument(args) {
|
|
199
|
+
const body = parseFlags(args, ["title", "type", "parentId"]);
|
|
200
|
+
const [baseUrl, apiKey] = await Promise.all([getBaseUrl(), getApiKey()]);
|
|
201
|
+
const result = await request(baseUrl, "/api/v1/documents", apiKey, {
|
|
202
|
+
method: "POST",
|
|
203
|
+
body
|
|
204
|
+
});
|
|
205
|
+
console.log(`Created: ${result.data.id} ${result.data.title || "(Untitled)"}`);
|
|
206
|
+
}
|
|
207
|
+
async function updateDocument(id, args) {
|
|
208
|
+
if (!id) {
|
|
209
|
+
console.error("Usage: artisense docs update <document-id> --title '...' --content '...'");
|
|
210
|
+
process.exit(1);
|
|
211
|
+
}
|
|
212
|
+
const body = parseFlags(args, ["title", "content"]);
|
|
213
|
+
if (Object.keys(body).length === 0) {
|
|
214
|
+
console.error("Provide at least one of: --title, --content");
|
|
215
|
+
process.exit(1);
|
|
216
|
+
}
|
|
217
|
+
const [baseUrl, apiKey] = await Promise.all([getBaseUrl(), getApiKey()]);
|
|
218
|
+
const result = await request(baseUrl, `/api/v1/documents/${id}`, apiKey, { method: "PATCH", body });
|
|
219
|
+
console.log(`Updated: ${result.data.id} ${result.data.title || "(Untitled)"}`);
|
|
220
|
+
}
|
|
221
|
+
async function deleteDocument(id) {
|
|
222
|
+
if (!id) {
|
|
223
|
+
console.error("Usage: artisense docs delete <document-id>");
|
|
224
|
+
process.exit(1);
|
|
225
|
+
}
|
|
226
|
+
const [baseUrl, apiKey] = await Promise.all([getBaseUrl(), getApiKey()]);
|
|
227
|
+
await request(baseUrl, `/api/v1/documents/${id}`, apiKey, {
|
|
228
|
+
method: "DELETE"
|
|
229
|
+
});
|
|
230
|
+
console.log(`Deleted: ${id}`);
|
|
231
|
+
}
|
|
232
|
+
function parseFlags(args, allowedKeys) {
|
|
233
|
+
const result = {};
|
|
234
|
+
for (let i = 0;i < args.length; i++) {
|
|
235
|
+
const arg = args[i];
|
|
236
|
+
if (arg.startsWith("--")) {
|
|
237
|
+
const key = arg.slice(2);
|
|
238
|
+
if (allowedKeys.includes(key) && i + 1 < args.length) {
|
|
239
|
+
result[key] = args[++i];
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return result;
|
|
244
|
+
}
|
|
245
|
+
function printUsage2() {
|
|
246
|
+
console.log(`
|
|
247
|
+
Usage: artisense docs <command>
|
|
248
|
+
|
|
249
|
+
Commands:
|
|
250
|
+
list List all documents
|
|
251
|
+
get <id> Get a document
|
|
252
|
+
create --title "..." [--type "..."] [--parentId "..."]
|
|
253
|
+
Create a document
|
|
254
|
+
update <id> --title "..." --content "..."
|
|
255
|
+
Update a document
|
|
256
|
+
delete <id> Delete a document
|
|
257
|
+
`);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// src/index.ts
|
|
261
|
+
var args = process.argv.slice(2);
|
|
262
|
+
var command = args[0];
|
|
263
|
+
switch (command) {
|
|
264
|
+
case "skill":
|
|
265
|
+
await skillCommand(args.slice(1));
|
|
266
|
+
break;
|
|
267
|
+
case "docs":
|
|
268
|
+
case "documents":
|
|
269
|
+
await documentsCommand(args.slice(1));
|
|
270
|
+
break;
|
|
271
|
+
case "help":
|
|
272
|
+
case "--help":
|
|
273
|
+
case "-h":
|
|
274
|
+
case undefined:
|
|
275
|
+
printHelp();
|
|
276
|
+
break;
|
|
277
|
+
default:
|
|
278
|
+
console.error(`Unknown command: ${command}`);
|
|
279
|
+
printHelp();
|
|
280
|
+
process.exit(1);
|
|
281
|
+
}
|
|
282
|
+
function printHelp() {
|
|
283
|
+
console.log(`
|
|
284
|
+
artisense — CLI for Artisense
|
|
285
|
+
|
|
286
|
+
Usage: artisense <command>
|
|
287
|
+
|
|
288
|
+
Commands:
|
|
289
|
+
skill Download SKILL.md for AI agents
|
|
290
|
+
docs Manage documents (list, get, create, update, delete)
|
|
291
|
+
help Show this help
|
|
292
|
+
|
|
293
|
+
Environment:
|
|
294
|
+
ARTISENSE_API_KEY Your API key (required for docs commands)
|
|
295
|
+
|
|
296
|
+
Examples:
|
|
297
|
+
artisense skill --claude
|
|
298
|
+
artisense docs list
|
|
299
|
+
artisense docs get <id>
|
|
300
|
+
artisense docs create --title "Meeting Notes"
|
|
301
|
+
artisense docs update <id> --content "Updated content"
|
|
302
|
+
artisense docs delete <id>
|
|
303
|
+
`);
|
|
304
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "artisense",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI for Artisense — manage documents from your terminal or AI agent",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"bin": {
|
|
7
|
+
"artisense": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"type": "module",
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "bun build src/index.ts --outdir dist --target node",
|
|
15
|
+
"dev": "bun run src/index.ts"
|
|
16
|
+
}
|
|
17
|
+
}
|