@devness/useai-cli 0.3.4 → 0.3.6
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 +101 -28
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -395,7 +395,7 @@ import chalk6 from "chalk";
|
|
|
395
395
|
|
|
396
396
|
// src/services/tools.ts
|
|
397
397
|
import { execSync } from "child_process";
|
|
398
|
-
import { existsSync as existsSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
398
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, unlinkSync } from "fs";
|
|
399
399
|
import { dirname, join as join2 } from "path";
|
|
400
400
|
import { homedir as homedir2 } from "os";
|
|
401
401
|
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
|
|
@@ -589,6 +589,65 @@ function removeYaml(configPath) {
|
|
|
589
589
|
writeYamlFile(configPath, config);
|
|
590
590
|
}
|
|
591
591
|
}
|
|
592
|
+
var INSTRUCTIONS_START = "<!-- useai:start -->";
|
|
593
|
+
var INSTRUCTIONS_END = "<!-- useai:end -->";
|
|
594
|
+
var USEAI_INSTRUCTIONS = [
|
|
595
|
+
"## UseAI Session Tracking",
|
|
596
|
+
"- At the START of every conversation, call `useai_session_start` with the appropriate task_type.",
|
|
597
|
+
"- For LONG sessions (15+ min), call `useai_heartbeat` periodically.",
|
|
598
|
+
"- 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)."
|
|
599
|
+
].join("\n");
|
|
600
|
+
var USEAI_INSTRUCTIONS_BLOCK = `${INSTRUCTIONS_START}
|
|
601
|
+
${USEAI_INSTRUCTIONS}
|
|
602
|
+
${INSTRUCTIONS_END}`;
|
|
603
|
+
function hasInstructionsBlock(filePath) {
|
|
604
|
+
if (!existsSync4(filePath)) return false;
|
|
605
|
+
try {
|
|
606
|
+
return readFileSync2(filePath, "utf-8").includes(INSTRUCTIONS_START);
|
|
607
|
+
} catch {
|
|
608
|
+
return false;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
function injectInstructions(config) {
|
|
612
|
+
mkdirSync2(dirname(config.path), { recursive: true });
|
|
613
|
+
if (config.method === "create") {
|
|
614
|
+
writeFileSync2(config.path, USEAI_INSTRUCTIONS + "\n");
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
if (hasInstructionsBlock(config.path)) return;
|
|
618
|
+
let existing = "";
|
|
619
|
+
if (existsSync4(config.path)) {
|
|
620
|
+
existing = readFileSync2(config.path, "utf-8");
|
|
621
|
+
}
|
|
622
|
+
const separator = existing && !existing.endsWith("\n") ? "\n\n" : existing ? "\n" : "";
|
|
623
|
+
writeFileSync2(config.path, existing + separator + USEAI_INSTRUCTIONS_BLOCK + "\n");
|
|
624
|
+
}
|
|
625
|
+
function removeInstructions(config) {
|
|
626
|
+
if (config.method === "create") {
|
|
627
|
+
if (existsSync4(config.path)) {
|
|
628
|
+
try {
|
|
629
|
+
unlinkSync(config.path);
|
|
630
|
+
} catch {
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
if (!existsSync4(config.path)) return;
|
|
636
|
+
try {
|
|
637
|
+
const content = readFileSync2(config.path, "utf-8");
|
|
638
|
+
const escaped = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
639
|
+
const regex = new RegExp(
|
|
640
|
+
`\\n?${escaped(INSTRUCTIONS_START)}[\\s\\S]*?${escaped(INSTRUCTIONS_END)}\\n?`
|
|
641
|
+
);
|
|
642
|
+
const cleaned = content.replace(regex, "").trim();
|
|
643
|
+
if (cleaned) {
|
|
644
|
+
writeFileSync2(config.path, cleaned + "\n");
|
|
645
|
+
} else {
|
|
646
|
+
unlinkSync(config.path);
|
|
647
|
+
}
|
|
648
|
+
} catch {
|
|
649
|
+
}
|
|
650
|
+
}
|
|
592
651
|
var formatHandlers = {
|
|
593
652
|
standard: { isConfigured: isConfiguredStandard, install: installStandard, remove: removeStandard },
|
|
594
653
|
vscode: { isConfigured: isConfiguredVscode, install: installVscode, remove: removeVscode },
|
|
@@ -605,8 +664,14 @@ function createTool(def) {
|
|
|
605
664
|
getConfigPath: () => def.configPath,
|
|
606
665
|
detect: def.detect,
|
|
607
666
|
isConfigured: () => handler.isConfigured(def.configPath),
|
|
608
|
-
install: () =>
|
|
609
|
-
|
|
667
|
+
install: () => {
|
|
668
|
+
handler.install(def.configPath);
|
|
669
|
+
if (def.instructions) injectInstructions(def.instructions);
|
|
670
|
+
},
|
|
671
|
+
remove: () => {
|
|
672
|
+
handler.remove(def.configPath);
|
|
673
|
+
if (def.instructions) removeInstructions(def.instructions);
|
|
674
|
+
}
|
|
610
675
|
};
|
|
611
676
|
}
|
|
612
677
|
var appSupport = join2(home, "Library", "Application Support");
|
|
@@ -637,14 +702,8 @@ var AI_TOOLS = [
|
|
|
637
702
|
name: "Claude Code",
|
|
638
703
|
configFormat: "standard",
|
|
639
704
|
configPath: join2(home, ".claude.json"),
|
|
640
|
-
detect: () => hasBinary("claude") || existsSync4(join2(home, ".claude.json"))
|
|
641
|
-
|
|
642
|
-
createTool({
|
|
643
|
-
id: "claude-desktop",
|
|
644
|
-
name: "Claude Desktop",
|
|
645
|
-
configFormat: "standard",
|
|
646
|
-
configPath: join2(appSupport, "Claude", "claude_desktop_config.json"),
|
|
647
|
-
detect: () => existsSync4(join2(appSupport, "Claude")) || existsSync4("/Applications/Claude.app")
|
|
705
|
+
detect: () => hasBinary("claude") || existsSync4(join2(home, ".claude.json")),
|
|
706
|
+
instructions: { method: "append", path: join2(home, ".claude", "CLAUDE.md") }
|
|
648
707
|
}),
|
|
649
708
|
createTool({
|
|
650
709
|
id: "cursor",
|
|
@@ -658,28 +717,32 @@ var AI_TOOLS = [
|
|
|
658
717
|
name: "Windsurf",
|
|
659
718
|
configFormat: "standard",
|
|
660
719
|
configPath: join2(home, ".codeium", "windsurf", "mcp_config.json"),
|
|
661
|
-
detect: () => existsSync4(join2(home, ".codeium", "windsurf"))
|
|
720
|
+
detect: () => existsSync4(join2(home, ".codeium", "windsurf")),
|
|
721
|
+
instructions: { method: "append", path: join2(home, ".codeium", "windsurf", "memories", "global_rules.md") }
|
|
662
722
|
}),
|
|
663
723
|
createTool({
|
|
664
724
|
id: "vscode",
|
|
665
725
|
name: "VS Code",
|
|
666
726
|
configFormat: "vscode",
|
|
667
727
|
configPath: join2(appSupport, "Code", "User", "mcp.json"),
|
|
668
|
-
detect: () => existsSync4(join2(appSupport, "Code"))
|
|
728
|
+
detect: () => existsSync4(join2(appSupport, "Code")),
|
|
729
|
+
instructions: { method: "create", path: join2(appSupport, "Code", "User", "prompts", "useai.instructions.md") }
|
|
669
730
|
}),
|
|
670
731
|
createTool({
|
|
671
732
|
id: "vscode-insiders",
|
|
672
733
|
name: "VS Code Insiders",
|
|
673
734
|
configFormat: "vscode",
|
|
674
735
|
configPath: join2(appSupport, "Code - Insiders", "User", "mcp.json"),
|
|
675
|
-
detect: () => existsSync4(join2(appSupport, "Code - Insiders"))
|
|
736
|
+
detect: () => existsSync4(join2(appSupport, "Code - Insiders")),
|
|
737
|
+
instructions: { method: "create", path: join2(appSupport, "Code - Insiders", "User", "prompts", "useai.instructions.md") }
|
|
676
738
|
}),
|
|
677
739
|
createTool({
|
|
678
740
|
id: "gemini-cli",
|
|
679
741
|
name: "Gemini CLI",
|
|
680
742
|
configFormat: "standard",
|
|
681
743
|
configPath: join2(home, ".gemini", "settings.json"),
|
|
682
|
-
detect: () => hasBinary("gemini")
|
|
744
|
+
detect: () => hasBinary("gemini"),
|
|
745
|
+
instructions: { method: "append", path: join2(home, ".gemini", "GEMINI.md") }
|
|
683
746
|
}),
|
|
684
747
|
createTool({
|
|
685
748
|
id: "zed",
|
|
@@ -703,7 +766,8 @@ var AI_TOOLS = [
|
|
|
703
766
|
),
|
|
704
767
|
detect: () => existsSync4(
|
|
705
768
|
join2(appSupport, "Code", "User", "globalStorage", "saoudrizwan.claude-dev")
|
|
706
|
-
)
|
|
769
|
+
),
|
|
770
|
+
instructions: { method: "create", path: join2(home, "Documents", "Cline", "Rules", "useai.md") }
|
|
707
771
|
}),
|
|
708
772
|
createTool({
|
|
709
773
|
id: "roo-code",
|
|
@@ -720,7 +784,8 @@ var AI_TOOLS = [
|
|
|
720
784
|
),
|
|
721
785
|
detect: () => existsSync4(
|
|
722
786
|
join2(appSupport, "Code", "User", "globalStorage", "rooveterinaryinc.roo-cline")
|
|
723
|
-
)
|
|
787
|
+
),
|
|
788
|
+
instructions: { method: "create", path: join2(home, ".roo", "rules", "useai.md") }
|
|
724
789
|
}),
|
|
725
790
|
createTool({
|
|
726
791
|
id: "amazon-q-cli",
|
|
@@ -741,21 +806,24 @@ var AI_TOOLS = [
|
|
|
741
806
|
name: "Codex",
|
|
742
807
|
configFormat: "toml",
|
|
743
808
|
configPath: join2(home, ".codex", "config.toml"),
|
|
744
|
-
detect: () => hasBinary("codex") || existsSync4(join2(home, ".codex")) || existsSync4("/Applications/Codex.app")
|
|
809
|
+
detect: () => hasBinary("codex") || existsSync4(join2(home, ".codex")) || existsSync4("/Applications/Codex.app"),
|
|
810
|
+
instructions: { method: "append", path: join2(home, ".codex", "AGENTS.md") }
|
|
745
811
|
}),
|
|
746
812
|
createTool({
|
|
747
813
|
id: "goose",
|
|
748
814
|
name: "Goose",
|
|
749
815
|
configFormat: "yaml",
|
|
750
816
|
configPath: join2(home, ".config", "goose", "config.yaml"),
|
|
751
|
-
detect: () => existsSync4(join2(home, ".config", "goose"))
|
|
817
|
+
detect: () => existsSync4(join2(home, ".config", "goose")),
|
|
818
|
+
instructions: { method: "append", path: join2(home, ".config", "goose", ".goosehints") }
|
|
752
819
|
}),
|
|
753
820
|
createTool({
|
|
754
821
|
id: "opencode",
|
|
755
822
|
name: "OpenCode",
|
|
756
823
|
configFormat: "standard",
|
|
757
824
|
configPath: join2(home, ".config", "opencode", "opencode.json"),
|
|
758
|
-
detect: () => hasBinary("opencode") || existsSync4(join2(home, ".config", "opencode"))
|
|
825
|
+
detect: () => hasBinary("opencode") || existsSync4(join2(home, ".config", "opencode")),
|
|
826
|
+
instructions: { method: "append", path: join2(home, ".config", "opencode", "AGENTS.md") }
|
|
759
827
|
}),
|
|
760
828
|
createTool({
|
|
761
829
|
id: "junie",
|
|
@@ -796,17 +864,16 @@ function showStatus(tools) {
|
|
|
796
864
|
}
|
|
797
865
|
async function installFlow(tools, autoYes, explicit) {
|
|
798
866
|
if (explicit) {
|
|
799
|
-
const toInstall2 = tools.filter((t) => !t.isConfigured());
|
|
800
|
-
const alreadyDone = tools.filter((t) => t.isConfigured());
|
|
801
|
-
for (const tool of alreadyDone) {
|
|
802
|
-
console.log(info(`${tool.name} is already configured.`));
|
|
803
|
-
}
|
|
804
|
-
if (toInstall2.length === 0) return;
|
|
805
867
|
console.log();
|
|
806
|
-
for (const tool of
|
|
868
|
+
for (const tool of tools) {
|
|
807
869
|
try {
|
|
870
|
+
const wasConfigured = tool.isConfigured();
|
|
808
871
|
tool.install();
|
|
809
|
-
|
|
872
|
+
if (wasConfigured) {
|
|
873
|
+
console.log(success(`\u2713 ${tool.name.padEnd(18)} ${chalk6.dim("(updated)")}`));
|
|
874
|
+
} else {
|
|
875
|
+
console.log(success(`\u2713 ${tool.name.padEnd(18)} \u2192 ${chalk6.dim(shortenPath(tool.getConfigPath()))}`));
|
|
876
|
+
}
|
|
810
877
|
} catch (err) {
|
|
811
878
|
console.log(error(`\u2717 ${tool.name.padEnd(18)} \u2014 ${err.message}`));
|
|
812
879
|
}
|
|
@@ -870,6 +937,12 @@ async function installFlow(tools, autoYes, explicit) {
|
|
|
870
937
|
console.log(error(`\u2717 ${tool.name.padEnd(18)} \u2014 ${err.message}`));
|
|
871
938
|
}
|
|
872
939
|
}
|
|
940
|
+
for (const tool of alreadyConfigured) {
|
|
941
|
+
try {
|
|
942
|
+
tool.install();
|
|
943
|
+
} catch {
|
|
944
|
+
}
|
|
945
|
+
}
|
|
873
946
|
console.log(`
|
|
874
947
|
Done! UseAI MCP server configured in ${chalk6.bold(String(toInstall.length))} tool${toInstall.length === 1 ? "" : "s"}.
|
|
875
948
|
`);
|