@devness/useai 0.3.3 → 0.3.5
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 +130 -38
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ var __export = (target, all) => {
|
|
|
11
11
|
|
|
12
12
|
// src/tools.ts
|
|
13
13
|
import { execSync } from "child_process";
|
|
14
|
-
import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
14
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, unlinkSync } from "fs";
|
|
15
15
|
import { dirname, join as join3 } from "path";
|
|
16
16
|
import { homedir as homedir2 } from "os";
|
|
17
17
|
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
|
|
@@ -200,6 +200,54 @@ function removeYaml(configPath) {
|
|
|
200
200
|
writeYamlFile(configPath, config);
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
|
+
function hasInstructionsBlock(filePath) {
|
|
204
|
+
if (!existsSync3(filePath)) return false;
|
|
205
|
+
try {
|
|
206
|
+
return readFileSync2(filePath, "utf-8").includes(INSTRUCTIONS_START);
|
|
207
|
+
} catch {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function injectInstructions(config) {
|
|
212
|
+
mkdirSync2(dirname(config.path), { recursive: true });
|
|
213
|
+
if (config.method === "create") {
|
|
214
|
+
writeFileSync2(config.path, USEAI_INSTRUCTIONS + "\n");
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (hasInstructionsBlock(config.path)) return;
|
|
218
|
+
let existing = "";
|
|
219
|
+
if (existsSync3(config.path)) {
|
|
220
|
+
existing = readFileSync2(config.path, "utf-8");
|
|
221
|
+
}
|
|
222
|
+
const separator = existing && !existing.endsWith("\n") ? "\n\n" : existing ? "\n" : "";
|
|
223
|
+
writeFileSync2(config.path, existing + separator + USEAI_INSTRUCTIONS_BLOCK + "\n");
|
|
224
|
+
}
|
|
225
|
+
function removeInstructions(config) {
|
|
226
|
+
if (config.method === "create") {
|
|
227
|
+
if (existsSync3(config.path)) {
|
|
228
|
+
try {
|
|
229
|
+
unlinkSync(config.path);
|
|
230
|
+
} catch {
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
if (!existsSync3(config.path)) return;
|
|
236
|
+
try {
|
|
237
|
+
const content = readFileSync2(config.path, "utf-8");
|
|
238
|
+
const escaped = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
239
|
+
const regex = new RegExp(
|
|
240
|
+
`\\n?${escaped(INSTRUCTIONS_START)}[\\s\\S]*?${escaped(INSTRUCTIONS_END)}\\n?`
|
|
241
|
+
);
|
|
242
|
+
const cleaned = content.replace(regex, "").trim();
|
|
243
|
+
if (cleaned) {
|
|
244
|
+
writeFileSync2(config.path, cleaned + "\n");
|
|
245
|
+
} else {
|
|
246
|
+
unlinkSync(config.path);
|
|
247
|
+
}
|
|
248
|
+
} catch {
|
|
249
|
+
}
|
|
250
|
+
}
|
|
203
251
|
function createTool(def) {
|
|
204
252
|
const handler = formatHandlers[def.configFormat];
|
|
205
253
|
return {
|
|
@@ -209,8 +257,14 @@ function createTool(def) {
|
|
|
209
257
|
getConfigPath: () => def.configPath,
|
|
210
258
|
detect: def.detect,
|
|
211
259
|
isConfigured: () => handler.isConfigured(def.configPath),
|
|
212
|
-
install: () =>
|
|
213
|
-
|
|
260
|
+
install: () => {
|
|
261
|
+
handler.install(def.configPath);
|
|
262
|
+
if (def.instructions) injectInstructions(def.instructions);
|
|
263
|
+
},
|
|
264
|
+
remove: () => {
|
|
265
|
+
handler.remove(def.configPath);
|
|
266
|
+
if (def.instructions) removeInstructions(def.instructions);
|
|
267
|
+
}
|
|
214
268
|
};
|
|
215
269
|
}
|
|
216
270
|
function matchesTool(tool, query) {
|
|
@@ -234,7 +288,7 @@ function resolveTools(names) {
|
|
|
234
288
|
}
|
|
235
289
|
return { matched, unmatched };
|
|
236
290
|
}
|
|
237
|
-
var MCP_ENTRY, home, formatHandlers, appSupport, AI_TOOLS;
|
|
291
|
+
var MCP_ENTRY, home, INSTRUCTIONS_START, INSTRUCTIONS_END, USEAI_INSTRUCTIONS, USEAI_INSTRUCTIONS_BLOCK, formatHandlers, appSupport, AI_TOOLS;
|
|
238
292
|
var init_tools = __esm({
|
|
239
293
|
"src/tools.ts"() {
|
|
240
294
|
"use strict";
|
|
@@ -243,6 +297,17 @@ var init_tools = __esm({
|
|
|
243
297
|
args: ["-y", "@devness/useai"]
|
|
244
298
|
};
|
|
245
299
|
home = homedir2();
|
|
300
|
+
INSTRUCTIONS_START = "<!-- useai:start -->";
|
|
301
|
+
INSTRUCTIONS_END = "<!-- useai:end -->";
|
|
302
|
+
USEAI_INSTRUCTIONS = [
|
|
303
|
+
"## UseAI Session Tracking",
|
|
304
|
+
"- At the START of every conversation, call `useai_session_start` with the appropriate task_type.",
|
|
305
|
+
"- For LONG sessions (15+ min), call `useai_heartbeat` periodically.",
|
|
306
|
+
"- At the END of every conversation, call `useai_session_end` with languages used, files_touched_count, and milestones (generic descriptions only \u2014 no project names, file paths, or company names)."
|
|
307
|
+
].join("\n");
|
|
308
|
+
USEAI_INSTRUCTIONS_BLOCK = `${INSTRUCTIONS_START}
|
|
309
|
+
${USEAI_INSTRUCTIONS}
|
|
310
|
+
${INSTRUCTIONS_END}`;
|
|
246
311
|
formatHandlers = {
|
|
247
312
|
standard: { isConfigured: isConfiguredStandard, install: installStandard, remove: removeStandard },
|
|
248
313
|
vscode: { isConfigured: isConfiguredVscode, install: installVscode, remove: removeVscode },
|
|
@@ -257,7 +322,8 @@ var init_tools = __esm({
|
|
|
257
322
|
name: "Claude Code",
|
|
258
323
|
configFormat: "standard",
|
|
259
324
|
configPath: join3(home, ".claude.json"),
|
|
260
|
-
detect: () => hasBinary("claude") || existsSync3(join3(home, ".claude.json"))
|
|
325
|
+
detect: () => hasBinary("claude") || existsSync3(join3(home, ".claude.json")),
|
|
326
|
+
instructions: { method: "append", path: join3(home, ".claude", "CLAUDE.md") }
|
|
261
327
|
}),
|
|
262
328
|
createTool({
|
|
263
329
|
id: "claude-desktop",
|
|
@@ -278,28 +344,32 @@ var init_tools = __esm({
|
|
|
278
344
|
name: "Windsurf",
|
|
279
345
|
configFormat: "standard",
|
|
280
346
|
configPath: join3(home, ".codeium", "windsurf", "mcp_config.json"),
|
|
281
|
-
detect: () => existsSync3(join3(home, ".codeium", "windsurf"))
|
|
347
|
+
detect: () => existsSync3(join3(home, ".codeium", "windsurf")),
|
|
348
|
+
instructions: { method: "append", path: join3(home, ".codeium", "windsurf", "memories", "global_rules.md") }
|
|
282
349
|
}),
|
|
283
350
|
createTool({
|
|
284
351
|
id: "vscode",
|
|
285
352
|
name: "VS Code",
|
|
286
353
|
configFormat: "vscode",
|
|
287
354
|
configPath: join3(appSupport, "Code", "User", "mcp.json"),
|
|
288
|
-
detect: () => existsSync3(join3(appSupport, "Code"))
|
|
355
|
+
detect: () => existsSync3(join3(appSupport, "Code")),
|
|
356
|
+
instructions: { method: "create", path: join3(appSupport, "Code", "User", "prompts", "useai.instructions.md") }
|
|
289
357
|
}),
|
|
290
358
|
createTool({
|
|
291
359
|
id: "vscode-insiders",
|
|
292
360
|
name: "VS Code Insiders",
|
|
293
361
|
configFormat: "vscode",
|
|
294
362
|
configPath: join3(appSupport, "Code - Insiders", "User", "mcp.json"),
|
|
295
|
-
detect: () => existsSync3(join3(appSupport, "Code - Insiders"))
|
|
363
|
+
detect: () => existsSync3(join3(appSupport, "Code - Insiders")),
|
|
364
|
+
instructions: { method: "create", path: join3(appSupport, "Code - Insiders", "User", "prompts", "useai.instructions.md") }
|
|
296
365
|
}),
|
|
297
366
|
createTool({
|
|
298
367
|
id: "gemini-cli",
|
|
299
368
|
name: "Gemini CLI",
|
|
300
369
|
configFormat: "standard",
|
|
301
370
|
configPath: join3(home, ".gemini", "settings.json"),
|
|
302
|
-
detect: () => hasBinary("gemini")
|
|
371
|
+
detect: () => hasBinary("gemini"),
|
|
372
|
+
instructions: { method: "append", path: join3(home, ".gemini", "GEMINI.md") }
|
|
303
373
|
}),
|
|
304
374
|
createTool({
|
|
305
375
|
id: "zed",
|
|
@@ -323,7 +393,8 @@ var init_tools = __esm({
|
|
|
323
393
|
),
|
|
324
394
|
detect: () => existsSync3(
|
|
325
395
|
join3(appSupport, "Code", "User", "globalStorage", "saoudrizwan.claude-dev")
|
|
326
|
-
)
|
|
396
|
+
),
|
|
397
|
+
instructions: { method: "create", path: join3(home, "Documents", "Cline", "Rules", "useai.md") }
|
|
327
398
|
}),
|
|
328
399
|
createTool({
|
|
329
400
|
id: "roo-code",
|
|
@@ -340,7 +411,8 @@ var init_tools = __esm({
|
|
|
340
411
|
),
|
|
341
412
|
detect: () => existsSync3(
|
|
342
413
|
join3(appSupport, "Code", "User", "globalStorage", "rooveterinaryinc.roo-cline")
|
|
343
|
-
)
|
|
414
|
+
),
|
|
415
|
+
instructions: { method: "create", path: join3(home, ".roo", "rules", "useai.md") }
|
|
344
416
|
}),
|
|
345
417
|
createTool({
|
|
346
418
|
id: "amazon-q-cli",
|
|
@@ -361,21 +433,24 @@ var init_tools = __esm({
|
|
|
361
433
|
name: "Codex",
|
|
362
434
|
configFormat: "toml",
|
|
363
435
|
configPath: join3(home, ".codex", "config.toml"),
|
|
364
|
-
detect: () => hasBinary("codex") || existsSync3(join3(home, ".codex")) || existsSync3("/Applications/Codex.app")
|
|
436
|
+
detect: () => hasBinary("codex") || existsSync3(join3(home, ".codex")) || existsSync3("/Applications/Codex.app"),
|
|
437
|
+
instructions: { method: "append", path: join3(home, ".codex", "AGENTS.md") }
|
|
365
438
|
}),
|
|
366
439
|
createTool({
|
|
367
440
|
id: "goose",
|
|
368
441
|
name: "Goose",
|
|
369
442
|
configFormat: "yaml",
|
|
370
443
|
configPath: join3(home, ".config", "goose", "config.yaml"),
|
|
371
|
-
detect: () => existsSync3(join3(home, ".config", "goose"))
|
|
444
|
+
detect: () => existsSync3(join3(home, ".config", "goose")),
|
|
445
|
+
instructions: { method: "append", path: join3(home, ".config", "goose", ".goosehints") }
|
|
372
446
|
}),
|
|
373
447
|
createTool({
|
|
374
448
|
id: "opencode",
|
|
375
449
|
name: "OpenCode",
|
|
376
450
|
configFormat: "standard",
|
|
377
451
|
configPath: join3(home, ".config", "opencode", "opencode.json"),
|
|
378
|
-
detect: () => hasBinary("opencode") || existsSync3(join3(home, ".config", "opencode"))
|
|
452
|
+
detect: () => hasBinary("opencode") || existsSync3(join3(home, ".config", "opencode")),
|
|
453
|
+
instructions: { method: "append", path: join3(home, ".config", "opencode", "AGENTS.md") }
|
|
379
454
|
}),
|
|
380
455
|
createTool({
|
|
381
456
|
id: "junie",
|
|
@@ -438,17 +513,16 @@ function showStatus(tools) {
|
|
|
438
513
|
}
|
|
439
514
|
async function installFlow(tools, autoYes, explicit) {
|
|
440
515
|
if (explicit) {
|
|
441
|
-
const toInstall2 = tools.filter((t) => !t.isConfigured());
|
|
442
|
-
const alreadyDone = tools.filter((t) => t.isConfigured());
|
|
443
|
-
for (const tool of alreadyDone) {
|
|
444
|
-
console.log(dim(`${tool.name} is already configured.`));
|
|
445
|
-
}
|
|
446
|
-
if (toInstall2.length === 0) return;
|
|
447
516
|
console.log();
|
|
448
|
-
for (const tool of
|
|
517
|
+
for (const tool of tools) {
|
|
449
518
|
try {
|
|
519
|
+
const wasConfigured = tool.isConfigured();
|
|
450
520
|
tool.install();
|
|
451
|
-
|
|
521
|
+
if (wasConfigured) {
|
|
522
|
+
console.log(ok(`\u2713 ${tool.name.padEnd(18)} ${chalk.dim("(updated)")}`));
|
|
523
|
+
} else {
|
|
524
|
+
console.log(ok(`\u2713 ${tool.name.padEnd(18)} \u2192 ${chalk.dim(shortenPath(tool.getConfigPath()))}`));
|
|
525
|
+
}
|
|
452
526
|
} catch (e) {
|
|
453
527
|
console.log(err(`\u2717 ${tool.name.padEnd(18)} \u2014 ${e.message}`));
|
|
454
528
|
}
|
|
@@ -481,14 +555,20 @@ async function installFlow(tools, autoYes, explicit) {
|
|
|
481
555
|
if (autoYes) {
|
|
482
556
|
toInstall = unconfigured;
|
|
483
557
|
} else {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
558
|
+
let selected;
|
|
559
|
+
try {
|
|
560
|
+
selected = await checkbox({
|
|
561
|
+
message: "Select tools to configure:",
|
|
562
|
+
choices: unconfigured.map((t) => ({
|
|
563
|
+
name: t.name,
|
|
564
|
+
value: t.id,
|
|
565
|
+
checked: true
|
|
566
|
+
}))
|
|
567
|
+
});
|
|
568
|
+
} catch {
|
|
569
|
+
console.log("\n");
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
492
572
|
toInstall = unconfigured.filter((t) => selected.includes(t.id));
|
|
493
573
|
}
|
|
494
574
|
if (toInstall.length === 0) {
|
|
@@ -506,6 +586,12 @@ async function installFlow(tools, autoYes, explicit) {
|
|
|
506
586
|
console.log(err(`\u2717 ${tool.name.padEnd(18)} \u2014 ${e.message}`));
|
|
507
587
|
}
|
|
508
588
|
}
|
|
589
|
+
for (const tool of alreadyConfigured) {
|
|
590
|
+
try {
|
|
591
|
+
tool.install();
|
|
592
|
+
} catch {
|
|
593
|
+
}
|
|
594
|
+
}
|
|
509
595
|
console.log(`
|
|
510
596
|
Done! UseAI MCP server configured in ${chalk.bold(String(toInstall.length))} tool${toInstall.length === 1 ? "" : "s"}.
|
|
511
597
|
`);
|
|
@@ -560,14 +646,20 @@ async function removeFlow(tools, autoYes, explicit) {
|
|
|
560
646
|
if (autoYes) {
|
|
561
647
|
toRemove = configured;
|
|
562
648
|
} else {
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
649
|
+
let selected;
|
|
650
|
+
try {
|
|
651
|
+
selected = await checkbox({
|
|
652
|
+
message: "Select tools to remove UseAI from:",
|
|
653
|
+
choices: configured.map((t) => ({
|
|
654
|
+
name: t.name,
|
|
655
|
+
value: t.id,
|
|
656
|
+
checked: true
|
|
657
|
+
}))
|
|
658
|
+
});
|
|
659
|
+
} catch {
|
|
660
|
+
console.log("\n");
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
571
663
|
toRemove = configured.filter((t) => selected.includes(t.id));
|
|
572
664
|
}
|
|
573
665
|
if (toRemove.length === 0) {
|