@devness/useai-cli 0.4.4 → 0.4.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/LICENSE +21 -0
- package/dist/index.js +201 -72
- package/package.json +11 -12
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 useai.dev
|
|
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/dist/index.js
CHANGED
|
@@ -20,6 +20,7 @@ var CONFIG_FILE = join(USEAI_DIR, "config.json");
|
|
|
20
20
|
var SESSIONS_FILE = join(DATA_DIR, "sessions.json");
|
|
21
21
|
var MILESTONES_FILE = join(DATA_DIR, "milestones.json");
|
|
22
22
|
var DAEMON_PID_FILE = join(USEAI_DIR, "daemon.pid");
|
|
23
|
+
var USEAI_HOOKS_DIR = join(USEAI_DIR, "hooks");
|
|
23
24
|
var DAEMON_PORT = 19200;
|
|
24
25
|
var DAEMON_LOG_FILE = join(USEAI_DIR, "daemon.log");
|
|
25
26
|
var DAEMON_MCP_URL = `http://127.0.0.1:${DAEMON_PORT}/mcp`;
|
|
@@ -29,7 +30,7 @@ var SYSTEMD_SERVICE_PATH = join(homedir(), ".config", "systemd", "user", "useai-
|
|
|
29
30
|
var WINDOWS_STARTUP_SCRIPT_PATH = join(process.env["APPDATA"] ?? join(homedir(), "AppData", "Roaming"), "Microsoft", "Windows", "Start Menu", "Programs", "Startup", "useai-daemon.vbs");
|
|
30
31
|
|
|
31
32
|
// ../shared/dist/constants/version.js
|
|
32
|
-
var VERSION = "0.4.
|
|
33
|
+
var VERSION = "0.4.5";
|
|
33
34
|
|
|
34
35
|
// ../shared/dist/constants/defaults.js
|
|
35
36
|
var DEFAULT_CONFIG = {
|
|
@@ -4875,11 +4876,126 @@ function isAutostartInstalled() {
|
|
|
4875
4876
|
}
|
|
4876
4877
|
}
|
|
4877
4878
|
|
|
4879
|
+
// ../shared/dist/hooks/claude-code.js
|
|
4880
|
+
import { existsSync as existsSync7, readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, unlinkSync as unlinkSync3, chmodSync } from "fs";
|
|
4881
|
+
import { join as join3 } from "path";
|
|
4882
|
+
import { homedir as homedir3 } from "os";
|
|
4883
|
+
var STOP_GUARD_PATH = join3(USEAI_HOOKS_DIR, "stop-guard.js");
|
|
4884
|
+
var CLAUDE_SETTINGS_PATH = join3(homedir3(), ".claude", "settings.json");
|
|
4885
|
+
var STOP_GUARD_SCRIPT = `#!/usr/bin/env node
|
|
4886
|
+
'use strict';
|
|
4887
|
+
const { readFileSync } = require('node:fs');
|
|
4888
|
+
let input = '';
|
|
4889
|
+
process.stdin.setEncoding('utf-8');
|
|
4890
|
+
process.stdin.on('data', chunk => input += chunk);
|
|
4891
|
+
process.stdin.on('end', () => {
|
|
4892
|
+
try {
|
|
4893
|
+
const hook = JSON.parse(input);
|
|
4894
|
+
if (hook.stop_hook_active) process.exit(0);
|
|
4895
|
+
if (!hook.transcript_path) process.exit(0);
|
|
4896
|
+
let transcript;
|
|
4897
|
+
try { transcript = readFileSync(hook.transcript_path, 'utf-8'); } catch { process.exit(0); }
|
|
4898
|
+
if (!transcript.includes('useai_session_start')) process.exit(0);
|
|
4899
|
+
if (transcript.includes('useai_session_end')) process.exit(0);
|
|
4900
|
+
process.stdout.write(JSON.stringify({
|
|
4901
|
+
decision: 'block',
|
|
4902
|
+
reason: 'Before ending, call useai_session_end with milestones (generic descriptions of accomplishments), languages used, and files_touched_count.'
|
|
4903
|
+
}));
|
|
4904
|
+
} catch { process.exit(0); }
|
|
4905
|
+
});
|
|
4906
|
+
`;
|
|
4907
|
+
function readSettings() {
|
|
4908
|
+
if (!existsSync7(CLAUDE_SETTINGS_PATH))
|
|
4909
|
+
return {};
|
|
4910
|
+
try {
|
|
4911
|
+
return JSON.parse(readFileSync3(CLAUDE_SETTINGS_PATH, "utf-8"));
|
|
4912
|
+
} catch {
|
|
4913
|
+
return {};
|
|
4914
|
+
}
|
|
4915
|
+
}
|
|
4916
|
+
function writeSettings(settings) {
|
|
4917
|
+
mkdirSync3(join3(homedir3(), ".claude"), { recursive: true });
|
|
4918
|
+
writeFileSync3(CLAUDE_SETTINGS_PATH, JSON.stringify(settings, null, 2) + "\n");
|
|
4919
|
+
}
|
|
4920
|
+
function installClaudeCodeHooks() {
|
|
4921
|
+
mkdirSync3(USEAI_HOOKS_DIR, { recursive: true });
|
|
4922
|
+
writeFileSync3(STOP_GUARD_PATH, STOP_GUARD_SCRIPT);
|
|
4923
|
+
try {
|
|
4924
|
+
chmodSync(STOP_GUARD_PATH, "755");
|
|
4925
|
+
} catch {
|
|
4926
|
+
}
|
|
4927
|
+
const settings = readSettings();
|
|
4928
|
+
const hooks = settings["hooks"] ?? {};
|
|
4929
|
+
const stopCmd = `node "${STOP_GUARD_PATH}"`;
|
|
4930
|
+
const sealCmd = `curl -sf -X POST http://127.0.0.1:${DAEMON_PORT}/api/seal-active --max-time 3 2>/dev/null || true`;
|
|
4931
|
+
let changed = false;
|
|
4932
|
+
if (!hooks["Stop"])
|
|
4933
|
+
hooks["Stop"] = [];
|
|
4934
|
+
const stopArr = hooks["Stop"];
|
|
4935
|
+
const hasStop = stopArr.some((g) => {
|
|
4936
|
+
const inner = g["hooks"];
|
|
4937
|
+
return inner?.some((h) => h["command"]?.includes("stop-guard"));
|
|
4938
|
+
});
|
|
4939
|
+
if (!hasStop) {
|
|
4940
|
+
stopArr.push({ hooks: [{ type: "command", command: stopCmd, timeout: 10 }] });
|
|
4941
|
+
changed = true;
|
|
4942
|
+
}
|
|
4943
|
+
if (!hooks["SessionEnd"])
|
|
4944
|
+
hooks["SessionEnd"] = [];
|
|
4945
|
+
const endArr = hooks["SessionEnd"];
|
|
4946
|
+
const hasEnd = endArr.some((g) => {
|
|
4947
|
+
const inner = g["hooks"];
|
|
4948
|
+
return inner?.some((h) => h["command"]?.includes("seal-active"));
|
|
4949
|
+
});
|
|
4950
|
+
if (!hasEnd) {
|
|
4951
|
+
endArr.push({ hooks: [{ type: "command", command: sealCmd, timeout: 5 }] });
|
|
4952
|
+
changed = true;
|
|
4953
|
+
}
|
|
4954
|
+
settings["hooks"] = hooks;
|
|
4955
|
+
writeSettings(settings);
|
|
4956
|
+
return changed;
|
|
4957
|
+
}
|
|
4958
|
+
function removeClaudeCodeHooks() {
|
|
4959
|
+
if (existsSync7(CLAUDE_SETTINGS_PATH)) {
|
|
4960
|
+
try {
|
|
4961
|
+
const settings = readSettings();
|
|
4962
|
+
const hooks = settings["hooks"];
|
|
4963
|
+
if (hooks) {
|
|
4964
|
+
if (hooks["Stop"]) {
|
|
4965
|
+
hooks["Stop"] = hooks["Stop"].filter((g) => {
|
|
4966
|
+
const inner = g["hooks"];
|
|
4967
|
+
return !inner?.some((h) => h["command"]?.includes("stop-guard"));
|
|
4968
|
+
});
|
|
4969
|
+
if (hooks["Stop"].length === 0)
|
|
4970
|
+
delete hooks["Stop"];
|
|
4971
|
+
}
|
|
4972
|
+
if (hooks["SessionEnd"]) {
|
|
4973
|
+
hooks["SessionEnd"] = hooks["SessionEnd"].filter((g) => {
|
|
4974
|
+
const inner = g["hooks"];
|
|
4975
|
+
return !inner?.some((h) => h["command"]?.includes("seal-active"));
|
|
4976
|
+
});
|
|
4977
|
+
if (hooks["SessionEnd"].length === 0)
|
|
4978
|
+
delete hooks["SessionEnd"];
|
|
4979
|
+
}
|
|
4980
|
+
if (Object.keys(hooks).length === 0)
|
|
4981
|
+
delete settings["hooks"];
|
|
4982
|
+
}
|
|
4983
|
+
writeSettings(settings);
|
|
4984
|
+
} catch {
|
|
4985
|
+
}
|
|
4986
|
+
}
|
|
4987
|
+
try {
|
|
4988
|
+
if (existsSync7(STOP_GUARD_PATH))
|
|
4989
|
+
unlinkSync3(STOP_GUARD_PATH);
|
|
4990
|
+
} catch {
|
|
4991
|
+
}
|
|
4992
|
+
}
|
|
4993
|
+
|
|
4878
4994
|
// src/services/tools.ts
|
|
4879
4995
|
import { execSync as execSync3 } from "child_process";
|
|
4880
|
-
import { existsSync as
|
|
4881
|
-
import { dirname as dirname2, join as
|
|
4882
|
-
import { homedir as
|
|
4996
|
+
import { existsSync as existsSync8, readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, unlinkSync as unlinkSync4 } from "fs";
|
|
4997
|
+
import { dirname as dirname2, join as join4 } from "path";
|
|
4998
|
+
import { homedir as homedir4 } from "os";
|
|
4883
4999
|
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
|
|
4884
5000
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
4885
5001
|
var USEAI_INSTRUCTIONS_TEXT = [
|
|
@@ -4895,7 +5011,7 @@ var MCP_ENTRY = {
|
|
|
4895
5011
|
};
|
|
4896
5012
|
var MCP_HTTP_URL = DAEMON_MCP_URL;
|
|
4897
5013
|
var MCP_HTTP_ENTRY = { type: "http", url: MCP_HTTP_URL };
|
|
4898
|
-
var home =
|
|
5014
|
+
var home = homedir4();
|
|
4899
5015
|
function installStandardHttp(configPath) {
|
|
4900
5016
|
const config = readJsonFile(configPath);
|
|
4901
5017
|
const servers = config["mcpServers"] ?? {};
|
|
@@ -4921,9 +5037,9 @@ function hasBinary(name) {
|
|
|
4921
5037
|
}
|
|
4922
5038
|
}
|
|
4923
5039
|
function readJsonFile(path) {
|
|
4924
|
-
if (!
|
|
5040
|
+
if (!existsSync8(path)) return {};
|
|
4925
5041
|
try {
|
|
4926
|
-
const raw =
|
|
5042
|
+
const raw = readFileSync4(path, "utf-8").trim();
|
|
4927
5043
|
if (!raw) return {};
|
|
4928
5044
|
return JSON.parse(raw);
|
|
4929
5045
|
} catch {
|
|
@@ -4931,8 +5047,8 @@ function readJsonFile(path) {
|
|
|
4931
5047
|
}
|
|
4932
5048
|
}
|
|
4933
5049
|
function writeJsonFile(path, data) {
|
|
4934
|
-
|
|
4935
|
-
|
|
5050
|
+
mkdirSync4(dirname2(path), { recursive: true });
|
|
5051
|
+
writeFileSync4(path, JSON.stringify(data, null, 2) + "\n");
|
|
4936
5052
|
}
|
|
4937
5053
|
function isConfiguredStandard(configPath) {
|
|
4938
5054
|
const config = readJsonFile(configPath);
|
|
@@ -5013,9 +5129,9 @@ function removeZed(configPath) {
|
|
|
5013
5129
|
}
|
|
5014
5130
|
}
|
|
5015
5131
|
function readTomlFile(path) {
|
|
5016
|
-
if (!
|
|
5132
|
+
if (!existsSync8(path)) return {};
|
|
5017
5133
|
try {
|
|
5018
|
-
const raw =
|
|
5134
|
+
const raw = readFileSync4(path, "utf-8").trim();
|
|
5019
5135
|
if (!raw) return {};
|
|
5020
5136
|
return parseToml(raw);
|
|
5021
5137
|
} catch {
|
|
@@ -5023,8 +5139,8 @@ function readTomlFile(path) {
|
|
|
5023
5139
|
}
|
|
5024
5140
|
}
|
|
5025
5141
|
function writeTomlFile(path, data) {
|
|
5026
|
-
|
|
5027
|
-
|
|
5142
|
+
mkdirSync4(dirname2(path), { recursive: true });
|
|
5143
|
+
writeFileSync4(path, stringifyToml(data) + "\n");
|
|
5028
5144
|
}
|
|
5029
5145
|
function isConfiguredToml(configPath) {
|
|
5030
5146
|
const config = readTomlFile(configPath);
|
|
@@ -5052,9 +5168,9 @@ function removeToml(configPath) {
|
|
|
5052
5168
|
}
|
|
5053
5169
|
}
|
|
5054
5170
|
function readYamlFile(path) {
|
|
5055
|
-
if (!
|
|
5171
|
+
if (!existsSync8(path)) return {};
|
|
5056
5172
|
try {
|
|
5057
|
-
const raw =
|
|
5173
|
+
const raw = readFileSync4(path, "utf-8").trim();
|
|
5058
5174
|
if (!raw) return {};
|
|
5059
5175
|
return parseYaml(raw) ?? {};
|
|
5060
5176
|
} catch {
|
|
@@ -5062,8 +5178,8 @@ function readYamlFile(path) {
|
|
|
5062
5178
|
}
|
|
5063
5179
|
}
|
|
5064
5180
|
function writeYamlFile(path, data) {
|
|
5065
|
-
|
|
5066
|
-
|
|
5181
|
+
mkdirSync4(dirname2(path), { recursive: true });
|
|
5182
|
+
writeFileSync4(path, stringifyYaml(data));
|
|
5067
5183
|
}
|
|
5068
5184
|
function isConfiguredYaml(configPath) {
|
|
5069
5185
|
const config = readYamlFile(configPath);
|
|
@@ -5109,49 +5225,49 @@ var USEAI_INSTRUCTIONS_BLOCK = `${INSTRUCTIONS_START}
|
|
|
5109
5225
|
${USEAI_INSTRUCTIONS}
|
|
5110
5226
|
${INSTRUCTIONS_END}`;
|
|
5111
5227
|
function hasInstructionsBlock(filePath) {
|
|
5112
|
-
if (!
|
|
5228
|
+
if (!existsSync8(filePath)) return false;
|
|
5113
5229
|
try {
|
|
5114
|
-
return
|
|
5230
|
+
return readFileSync4(filePath, "utf-8").includes(INSTRUCTIONS_START);
|
|
5115
5231
|
} catch {
|
|
5116
5232
|
return false;
|
|
5117
5233
|
}
|
|
5118
5234
|
}
|
|
5119
5235
|
function injectInstructions(config) {
|
|
5120
|
-
|
|
5236
|
+
mkdirSync4(dirname2(config.path), { recursive: true });
|
|
5121
5237
|
if (config.method === "create") {
|
|
5122
|
-
|
|
5238
|
+
writeFileSync4(config.path, USEAI_INSTRUCTIONS + "\n");
|
|
5123
5239
|
return;
|
|
5124
5240
|
}
|
|
5125
5241
|
if (hasInstructionsBlock(config.path)) return;
|
|
5126
5242
|
let existing = "";
|
|
5127
|
-
if (
|
|
5128
|
-
existing =
|
|
5243
|
+
if (existsSync8(config.path)) {
|
|
5244
|
+
existing = readFileSync4(config.path, "utf-8");
|
|
5129
5245
|
}
|
|
5130
5246
|
const separator = existing && !existing.endsWith("\n") ? "\n\n" : existing ? "\n" : "";
|
|
5131
|
-
|
|
5247
|
+
writeFileSync4(config.path, existing + separator + USEAI_INSTRUCTIONS_BLOCK + "\n");
|
|
5132
5248
|
}
|
|
5133
5249
|
function removeInstructions(config) {
|
|
5134
5250
|
if (config.method === "create") {
|
|
5135
|
-
if (
|
|
5251
|
+
if (existsSync8(config.path)) {
|
|
5136
5252
|
try {
|
|
5137
|
-
|
|
5253
|
+
unlinkSync4(config.path);
|
|
5138
5254
|
} catch {
|
|
5139
5255
|
}
|
|
5140
5256
|
}
|
|
5141
5257
|
return;
|
|
5142
5258
|
}
|
|
5143
|
-
if (!
|
|
5259
|
+
if (!existsSync8(config.path)) return;
|
|
5144
5260
|
try {
|
|
5145
|
-
const content =
|
|
5261
|
+
const content = readFileSync4(config.path, "utf-8");
|
|
5146
5262
|
const escaped = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5147
5263
|
const regex = new RegExp(
|
|
5148
5264
|
`\\n?${escaped(INSTRUCTIONS_START)}[\\s\\S]*?${escaped(INSTRUCTIONS_END)}\\n?`
|
|
5149
5265
|
);
|
|
5150
5266
|
const cleaned = content.replace(regex, "").trim();
|
|
5151
5267
|
if (cleaned) {
|
|
5152
|
-
|
|
5268
|
+
writeFileSync4(config.path, cleaned + "\n");
|
|
5153
5269
|
} else {
|
|
5154
|
-
|
|
5270
|
+
unlinkSync4(config.path);
|
|
5155
5271
|
}
|
|
5156
5272
|
} catch {
|
|
5157
5273
|
}
|
|
@@ -5195,7 +5311,7 @@ function createTool(def) {
|
|
|
5195
5311
|
getManualHint: () => def.instructions ? null : def.manualHint ?? null
|
|
5196
5312
|
};
|
|
5197
5313
|
}
|
|
5198
|
-
var appSupport =
|
|
5314
|
+
var appSupport = join4(home, "Library", "Application Support");
|
|
5199
5315
|
function matchesTool(tool, query) {
|
|
5200
5316
|
const q = query.toLowerCase().replace(/[\s-_]+/g, "");
|
|
5201
5317
|
const id = tool.id.toLowerCase().replace(/[\s-_]+/g, "");
|
|
@@ -5222,17 +5338,17 @@ var AI_TOOLS = [
|
|
|
5222
5338
|
id: "claude-code",
|
|
5223
5339
|
name: "Claude Code",
|
|
5224
5340
|
configFormat: "standard",
|
|
5225
|
-
configPath:
|
|
5226
|
-
detect: () => hasBinary("claude") ||
|
|
5227
|
-
instructions: { method: "append", path:
|
|
5341
|
+
configPath: join4(home, ".claude.json"),
|
|
5342
|
+
detect: () => hasBinary("claude") || existsSync8(join4(home, ".claude.json")),
|
|
5343
|
+
instructions: { method: "append", path: join4(home, ".claude", "CLAUDE.md") },
|
|
5228
5344
|
supportsUrl: true
|
|
5229
5345
|
}),
|
|
5230
5346
|
createTool({
|
|
5231
5347
|
id: "cursor",
|
|
5232
5348
|
name: "Cursor",
|
|
5233
5349
|
configFormat: "standard",
|
|
5234
|
-
configPath:
|
|
5235
|
-
detect: () =>
|
|
5350
|
+
configPath: join4(home, ".cursor", "mcp.json"),
|
|
5351
|
+
detect: () => existsSync8(join4(home, ".cursor")),
|
|
5236
5352
|
manualHint: "Open Cursor Settings \u2192 Rules \u2192 User Rules and paste the instructions below.",
|
|
5237
5353
|
supportsUrl: true
|
|
5238
5354
|
}),
|
|
@@ -5240,51 +5356,51 @@ var AI_TOOLS = [
|
|
|
5240
5356
|
id: "windsurf",
|
|
5241
5357
|
name: "Windsurf",
|
|
5242
5358
|
configFormat: "standard",
|
|
5243
|
-
configPath:
|
|
5244
|
-
detect: () =>
|
|
5245
|
-
instructions: { method: "append", path:
|
|
5359
|
+
configPath: join4(home, ".codeium", "windsurf", "mcp_config.json"),
|
|
5360
|
+
detect: () => existsSync8(join4(home, ".codeium", "windsurf")),
|
|
5361
|
+
instructions: { method: "append", path: join4(home, ".codeium", "windsurf", "memories", "global_rules.md") },
|
|
5246
5362
|
supportsUrl: true
|
|
5247
5363
|
}),
|
|
5248
5364
|
createTool({
|
|
5249
5365
|
id: "vscode",
|
|
5250
5366
|
name: "VS Code",
|
|
5251
5367
|
configFormat: "vscode",
|
|
5252
|
-
configPath:
|
|
5253
|
-
detect: () =>
|
|
5254
|
-
instructions: { method: "create", path:
|
|
5368
|
+
configPath: join4(appSupport, "Code", "User", "mcp.json"),
|
|
5369
|
+
detect: () => existsSync8(join4(appSupport, "Code")),
|
|
5370
|
+
instructions: { method: "create", path: join4(appSupport, "Code", "User", "prompts", "useai.instructions.md") },
|
|
5255
5371
|
supportsUrl: true
|
|
5256
5372
|
}),
|
|
5257
5373
|
createTool({
|
|
5258
5374
|
id: "vscode-insiders",
|
|
5259
5375
|
name: "VS Code Insiders",
|
|
5260
5376
|
configFormat: "vscode",
|
|
5261
|
-
configPath:
|
|
5262
|
-
detect: () =>
|
|
5263
|
-
instructions: { method: "create", path:
|
|
5377
|
+
configPath: join4(appSupport, "Code - Insiders", "User", "mcp.json"),
|
|
5378
|
+
detect: () => existsSync8(join4(appSupport, "Code - Insiders")),
|
|
5379
|
+
instructions: { method: "create", path: join4(appSupport, "Code - Insiders", "User", "prompts", "useai.instructions.md") },
|
|
5264
5380
|
supportsUrl: true
|
|
5265
5381
|
}),
|
|
5266
5382
|
createTool({
|
|
5267
5383
|
id: "gemini-cli",
|
|
5268
5384
|
name: "Gemini CLI",
|
|
5269
5385
|
configFormat: "standard",
|
|
5270
|
-
configPath:
|
|
5386
|
+
configPath: join4(home, ".gemini", "settings.json"),
|
|
5271
5387
|
detect: () => hasBinary("gemini"),
|
|
5272
|
-
instructions: { method: "append", path:
|
|
5388
|
+
instructions: { method: "append", path: join4(home, ".gemini", "GEMINI.md") },
|
|
5273
5389
|
supportsUrl: true
|
|
5274
5390
|
}),
|
|
5275
5391
|
createTool({
|
|
5276
5392
|
id: "zed",
|
|
5277
5393
|
name: "Zed",
|
|
5278
5394
|
configFormat: "zed",
|
|
5279
|
-
configPath:
|
|
5280
|
-
detect: () =>
|
|
5395
|
+
configPath: join4(appSupport, "Zed", "settings.json"),
|
|
5396
|
+
detect: () => existsSync8(join4(appSupport, "Zed")),
|
|
5281
5397
|
manualHint: "Open Rules Library (\u2318\u2325L) \u2192 click + \u2192 paste the instructions below."
|
|
5282
5398
|
}),
|
|
5283
5399
|
createTool({
|
|
5284
5400
|
id: "cline",
|
|
5285
5401
|
name: "Cline",
|
|
5286
5402
|
configFormat: "standard",
|
|
5287
|
-
configPath:
|
|
5403
|
+
configPath: join4(
|
|
5288
5404
|
appSupport,
|
|
5289
5405
|
"Code",
|
|
5290
5406
|
"User",
|
|
@@ -5293,17 +5409,17 @@ var AI_TOOLS = [
|
|
|
5293
5409
|
"settings",
|
|
5294
5410
|
"cline_mcp_settings.json"
|
|
5295
5411
|
),
|
|
5296
|
-
detect: () =>
|
|
5297
|
-
|
|
5412
|
+
detect: () => existsSync8(
|
|
5413
|
+
join4(appSupport, "Code", "User", "globalStorage", "saoudrizwan.claude-dev")
|
|
5298
5414
|
),
|
|
5299
|
-
instructions: { method: "create", path:
|
|
5415
|
+
instructions: { method: "create", path: join4(home, "Documents", "Cline", "Rules", "useai.md") },
|
|
5300
5416
|
supportsUrl: true
|
|
5301
5417
|
}),
|
|
5302
5418
|
createTool({
|
|
5303
5419
|
id: "roo-code",
|
|
5304
5420
|
name: "Roo Code",
|
|
5305
5421
|
configFormat: "standard",
|
|
5306
|
-
configPath:
|
|
5422
|
+
configPath: join4(
|
|
5307
5423
|
appSupport,
|
|
5308
5424
|
"Code",
|
|
5309
5425
|
"User",
|
|
@@ -5312,59 +5428,59 @@ var AI_TOOLS = [
|
|
|
5312
5428
|
"settings",
|
|
5313
5429
|
"cline_mcp_settings.json"
|
|
5314
5430
|
),
|
|
5315
|
-
detect: () =>
|
|
5316
|
-
|
|
5431
|
+
detect: () => existsSync8(
|
|
5432
|
+
join4(appSupport, "Code", "User", "globalStorage", "rooveterinaryinc.roo-cline")
|
|
5317
5433
|
),
|
|
5318
|
-
instructions: { method: "create", path:
|
|
5434
|
+
instructions: { method: "create", path: join4(home, ".roo", "rules", "useai.md") },
|
|
5319
5435
|
supportsUrl: true
|
|
5320
5436
|
}),
|
|
5321
5437
|
createTool({
|
|
5322
5438
|
id: "amazon-q-cli",
|
|
5323
5439
|
name: "Amazon Q CLI",
|
|
5324
5440
|
configFormat: "standard",
|
|
5325
|
-
configPath:
|
|
5326
|
-
detect: () => hasBinary("q") ||
|
|
5441
|
+
configPath: join4(home, ".aws", "amazonq", "mcp.json"),
|
|
5442
|
+
detect: () => hasBinary("q") || existsSync8(join4(home, ".aws", "amazonq")),
|
|
5327
5443
|
manualHint: "Create .amazonq/rules/useai.md in your project root with the instructions below."
|
|
5328
5444
|
}),
|
|
5329
5445
|
createTool({
|
|
5330
5446
|
id: "amazon-q-ide",
|
|
5331
5447
|
name: "Amazon Q IDE",
|
|
5332
5448
|
configFormat: "standard",
|
|
5333
|
-
configPath:
|
|
5334
|
-
detect: () =>
|
|
5449
|
+
configPath: join4(home, ".aws", "amazonq", "default.json"),
|
|
5450
|
+
detect: () => existsSync8(join4(home, ".amazonq")) || existsSync8(join4(home, ".aws", "amazonq")),
|
|
5335
5451
|
manualHint: "Create .amazonq/rules/useai.md in your project root with the instructions below."
|
|
5336
5452
|
}),
|
|
5337
5453
|
createTool({
|
|
5338
5454
|
id: "codex",
|
|
5339
5455
|
name: "Codex",
|
|
5340
5456
|
configFormat: "toml",
|
|
5341
|
-
configPath:
|
|
5342
|
-
detect: () => hasBinary("codex") ||
|
|
5343
|
-
instructions: { method: "append", path:
|
|
5457
|
+
configPath: join4(home, ".codex", "config.toml"),
|
|
5458
|
+
detect: () => hasBinary("codex") || existsSync8(join4(home, ".codex")) || existsSync8("/Applications/Codex.app"),
|
|
5459
|
+
instructions: { method: "append", path: join4(home, ".codex", "AGENTS.md") }
|
|
5344
5460
|
}),
|
|
5345
5461
|
createTool({
|
|
5346
5462
|
id: "goose",
|
|
5347
5463
|
name: "Goose",
|
|
5348
5464
|
configFormat: "yaml",
|
|
5349
|
-
configPath:
|
|
5350
|
-
detect: () =>
|
|
5351
|
-
instructions: { method: "append", path:
|
|
5465
|
+
configPath: join4(home, ".config", "goose", "config.yaml"),
|
|
5466
|
+
detect: () => existsSync8(join4(home, ".config", "goose")),
|
|
5467
|
+
instructions: { method: "append", path: join4(home, ".config", "goose", ".goosehints") }
|
|
5352
5468
|
}),
|
|
5353
5469
|
createTool({
|
|
5354
5470
|
id: "opencode",
|
|
5355
5471
|
name: "OpenCode",
|
|
5356
5472
|
configFormat: "standard",
|
|
5357
|
-
configPath:
|
|
5358
|
-
detect: () => hasBinary("opencode") ||
|
|
5359
|
-
instructions: { method: "append", path:
|
|
5473
|
+
configPath: join4(home, ".config", "opencode", "opencode.json"),
|
|
5474
|
+
detect: () => hasBinary("opencode") || existsSync8(join4(home, ".config", "opencode")),
|
|
5475
|
+
instructions: { method: "append", path: join4(home, ".config", "opencode", "AGENTS.md") },
|
|
5360
5476
|
supportsUrl: true
|
|
5361
5477
|
}),
|
|
5362
5478
|
createTool({
|
|
5363
5479
|
id: "junie",
|
|
5364
5480
|
name: "Junie",
|
|
5365
5481
|
configFormat: "standard",
|
|
5366
|
-
configPath:
|
|
5367
|
-
detect: () =>
|
|
5482
|
+
configPath: join4(home, ".junie", "mcp", "mcp.json"),
|
|
5483
|
+
detect: () => existsSync8(join4(home, ".junie")),
|
|
5368
5484
|
manualHint: "Add the instructions below to .junie/guidelines.md in your project root."
|
|
5369
5485
|
})
|
|
5370
5486
|
];
|
|
@@ -5458,6 +5574,14 @@ async function daemonInstallFlow(tools, explicit) {
|
|
|
5458
5574
|
console.log(error(`\u2717 ${tool.name.padEnd(18)} \u2014 ${e.message}`));
|
|
5459
5575
|
}
|
|
5460
5576
|
}
|
|
5577
|
+
try {
|
|
5578
|
+
const hooksInstalled = installClaudeCodeHooks();
|
|
5579
|
+
if (hooksInstalled) {
|
|
5580
|
+
console.log(success("\u2713 Claude Code hooks installed (Stop + SessionEnd)"));
|
|
5581
|
+
}
|
|
5582
|
+
} catch {
|
|
5583
|
+
console.log(chalk6.yellow(" \u26A0 Could not install Claude Code hooks"));
|
|
5584
|
+
}
|
|
5461
5585
|
showManualHints(targetTools);
|
|
5462
5586
|
const mode = useDaemon ? "daemon mode" : "stdio mode";
|
|
5463
5587
|
console.log(`
|
|
@@ -5632,6 +5756,11 @@ async function fullRemoveFlow(tools, autoYes, explicit) {
|
|
|
5632
5756
|
}
|
|
5633
5757
|
}
|
|
5634
5758
|
}
|
|
5759
|
+
try {
|
|
5760
|
+
removeClaudeCodeHooks();
|
|
5761
|
+
console.log(success("\u2713 Claude Code hooks removed"));
|
|
5762
|
+
} catch {
|
|
5763
|
+
}
|
|
5635
5764
|
console.log();
|
|
5636
5765
|
try {
|
|
5637
5766
|
await killDaemon();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devness/useai-cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "CLI tool for useai.dev — stats, sync, publish your AI development workflow",
|
|
5
5
|
"author": "nabeelkausari",
|
|
6
6
|
"license": "MIT",
|
|
@@ -14,14 +14,6 @@
|
|
|
14
14
|
"README.md",
|
|
15
15
|
"LICENSE"
|
|
16
16
|
],
|
|
17
|
-
"scripts": {
|
|
18
|
-
"build": "tsc -p tsconfig.build.json",
|
|
19
|
-
"dev": "tsc --watch",
|
|
20
|
-
"bundle": "tsup src/index.ts --format esm --target node18 --no-splitting",
|
|
21
|
-
"prepublishOnly": "pnpm run bundle",
|
|
22
|
-
"typecheck": "tsc --noEmit",
|
|
23
|
-
"clean": "rm -rf dist"
|
|
24
|
-
},
|
|
25
17
|
"dependencies": {
|
|
26
18
|
"@inquirer/prompts": "^8.2.1",
|
|
27
19
|
"chalk": "^5.4.1",
|
|
@@ -31,9 +23,9 @@
|
|
|
31
23
|
},
|
|
32
24
|
"devDependencies": {
|
|
33
25
|
"@types/node": "^22.13.4",
|
|
34
|
-
"@useai/shared": "workspace:*",
|
|
35
26
|
"tsup": "^8.0.0",
|
|
36
|
-
"typescript": "^5.7.3"
|
|
27
|
+
"typescript": "^5.7.3",
|
|
28
|
+
"@useai/shared": "0.3.0"
|
|
37
29
|
},
|
|
38
30
|
"repository": {
|
|
39
31
|
"type": "git",
|
|
@@ -42,5 +34,12 @@
|
|
|
42
34
|
"homepage": "https://useai.dev",
|
|
43
35
|
"engines": {
|
|
44
36
|
"node": ">=18"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsc -p tsconfig.build.json",
|
|
40
|
+
"dev": "tsc --watch",
|
|
41
|
+
"bundle": "tsup src/index.ts --format esm --target node18 --no-splitting",
|
|
42
|
+
"typecheck": "tsc --noEmit",
|
|
43
|
+
"clean": "rm -rf dist"
|
|
45
44
|
}
|
|
46
|
-
}
|
|
45
|
+
}
|