@staff0rd/assist 0.14.0 → 0.16.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 +162 -58
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -1227,14 +1227,8 @@ function createSettingsJson() {
|
|
|
1227
1227
|
const settings = {
|
|
1228
1228
|
"editor.defaultFormatter": "biomejs.biome",
|
|
1229
1229
|
"editor.formatOnSave": true,
|
|
1230
|
-
"
|
|
1231
|
-
"
|
|
1232
|
-
},
|
|
1233
|
-
"[typescript]": {
|
|
1234
|
-
"editor.defaultFormatter": "biomejs.biome"
|
|
1235
|
-
},
|
|
1236
|
-
"[typescriptreact]": {
|
|
1237
|
-
"editor.defaultFormatter": "biomejs.biome"
|
|
1230
|
+
"editor.codeActionsOnSave": {
|
|
1231
|
+
"source.organizeImports.biome": "explicit"
|
|
1238
1232
|
}
|
|
1239
1233
|
};
|
|
1240
1234
|
const settingsPath = path9.join(process.cwd(), ".vscode", "settings.json");
|
|
@@ -1495,6 +1489,122 @@ function addViteBaseConfig() {
|
|
|
1495
1489
|
}
|
|
1496
1490
|
}
|
|
1497
1491
|
|
|
1492
|
+
// src/lib/readStdin.ts
|
|
1493
|
+
import * as readline from "readline";
|
|
1494
|
+
async function readStdin() {
|
|
1495
|
+
const rl = readline.createInterface({
|
|
1496
|
+
input: process.stdin,
|
|
1497
|
+
output: process.stdout,
|
|
1498
|
+
terminal: false
|
|
1499
|
+
});
|
|
1500
|
+
let inputData = "";
|
|
1501
|
+
for await (const line of rl) {
|
|
1502
|
+
inputData += line;
|
|
1503
|
+
}
|
|
1504
|
+
return inputData;
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
// src/commands/notify/showNotification.ts
|
|
1508
|
+
import notifier from "node-notifier";
|
|
1509
|
+
|
|
1510
|
+
// src/lib/detectPlatform.ts
|
|
1511
|
+
import isWsl from "is-wsl";
|
|
1512
|
+
function detectPlatform() {
|
|
1513
|
+
if (isWsl) return "wsl";
|
|
1514
|
+
switch (process.platform) {
|
|
1515
|
+
case "win32":
|
|
1516
|
+
return "windows";
|
|
1517
|
+
case "darwin":
|
|
1518
|
+
return "macos";
|
|
1519
|
+
case "linux":
|
|
1520
|
+
return "linux";
|
|
1521
|
+
default:
|
|
1522
|
+
return "unknown";
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
// src/commands/notify/showWindowsNotificationFromWsl.ts
|
|
1527
|
+
import { spawn } from "child_process";
|
|
1528
|
+
import fs9 from "fs";
|
|
1529
|
+
import { createRequire } from "module";
|
|
1530
|
+
import path13 from "path";
|
|
1531
|
+
var require2 = createRequire(import.meta.url);
|
|
1532
|
+
function getSnoreToastPath() {
|
|
1533
|
+
const notifierPath = path13.dirname(require2.resolve("node-notifier"));
|
|
1534
|
+
return path13.join(notifierPath, "vendor", "snoreToast", "snoretoast-x64.exe");
|
|
1535
|
+
}
|
|
1536
|
+
function showWindowsNotificationFromWsl(options) {
|
|
1537
|
+
const { title, message, sound } = options;
|
|
1538
|
+
const snoreToastPath = getSnoreToastPath();
|
|
1539
|
+
try {
|
|
1540
|
+
fs9.chmodSync(snoreToastPath, 493);
|
|
1541
|
+
} catch {
|
|
1542
|
+
}
|
|
1543
|
+
const args = ["-t", title, "-m", message];
|
|
1544
|
+
if (sound === "Alarm") {
|
|
1545
|
+
args.push("-s", "ms-winsoundevent:Notification.Looping.Alarm");
|
|
1546
|
+
} else if (sound === "Reminder") {
|
|
1547
|
+
args.push("-s", "ms-winsoundevent:Notification.Reminder");
|
|
1548
|
+
}
|
|
1549
|
+
const child = spawn(snoreToastPath, args, {
|
|
1550
|
+
detached: true,
|
|
1551
|
+
stdio: "ignore"
|
|
1552
|
+
});
|
|
1553
|
+
child.unref();
|
|
1554
|
+
return true;
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
// src/commands/notify/showNotification.ts
|
|
1558
|
+
function showNotification(options) {
|
|
1559
|
+
const { title, message, sound } = options;
|
|
1560
|
+
const platform = detectPlatform();
|
|
1561
|
+
if (platform === "wsl") {
|
|
1562
|
+
return showWindowsNotificationFromWsl({ title, message, sound });
|
|
1563
|
+
}
|
|
1564
|
+
const notificationOptions = {
|
|
1565
|
+
title,
|
|
1566
|
+
message,
|
|
1567
|
+
wait: false
|
|
1568
|
+
};
|
|
1569
|
+
if (platform === "windows") {
|
|
1570
|
+
notificationOptions.appID = "Claude Code";
|
|
1571
|
+
}
|
|
1572
|
+
if (platform === "macos") {
|
|
1573
|
+
notificationOptions.sound = sound === "Alarm" ? "Basso" : "Submarine";
|
|
1574
|
+
}
|
|
1575
|
+
notifier.notify(notificationOptions);
|
|
1576
|
+
return true;
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
// src/commands/notify/index.ts
|
|
1580
|
+
async function notify() {
|
|
1581
|
+
const inputData = await readStdin();
|
|
1582
|
+
const data = JSON.parse(inputData);
|
|
1583
|
+
const { notification_type, cwd, message } = data;
|
|
1584
|
+
const projectName = cwd?.split(/[/\\]/).pop() ?? "Unknown Project";
|
|
1585
|
+
let title;
|
|
1586
|
+
let body;
|
|
1587
|
+
let sound;
|
|
1588
|
+
switch (notification_type) {
|
|
1589
|
+
case "permission_prompt":
|
|
1590
|
+
title = "Claude needs permission";
|
|
1591
|
+
body = `${projectName} - ${message || "Permission required"}`;
|
|
1592
|
+
sound = "Alarm";
|
|
1593
|
+
break;
|
|
1594
|
+
case "idle_prompt":
|
|
1595
|
+
title = "Claude is waiting";
|
|
1596
|
+
body = `${projectName} - Waiting for your input`;
|
|
1597
|
+
sound = "Reminder";
|
|
1598
|
+
break;
|
|
1599
|
+
default:
|
|
1600
|
+
title = "Claude Code";
|
|
1601
|
+
body = message ? `${projectName} - ${message}` : projectName;
|
|
1602
|
+
sound = "Default";
|
|
1603
|
+
}
|
|
1604
|
+
showNotification({ title, message: body, sound });
|
|
1605
|
+
console.log(`Notification sent: ${notification_type} for ${projectName}`);
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1498
1608
|
// src/commands/prs.ts
|
|
1499
1609
|
import { execSync as execSync10 } from "child_process";
|
|
1500
1610
|
import chalk25 from "chalk";
|
|
@@ -1589,22 +1699,22 @@ Page ${page + 1} of ${totalPages} (${pullRequests.length} total)
|
|
|
1589
1699
|
}
|
|
1590
1700
|
|
|
1591
1701
|
// src/commands/refactor/check.ts
|
|
1592
|
-
import { spawn } from "child_process";
|
|
1593
|
-
import * as
|
|
1702
|
+
import { spawn as spawn2 } from "child_process";
|
|
1703
|
+
import * as path14 from "path";
|
|
1594
1704
|
|
|
1595
1705
|
// src/commands/refactor/getViolations.ts
|
|
1596
1706
|
import { execSync as execSync11 } from "child_process";
|
|
1597
|
-
import
|
|
1707
|
+
import fs11 from "fs";
|
|
1598
1708
|
import { minimatch } from "minimatch";
|
|
1599
1709
|
|
|
1600
1710
|
// src/commands/refactor/getIgnoredFiles.ts
|
|
1601
|
-
import
|
|
1711
|
+
import fs10 from "fs";
|
|
1602
1712
|
var REFACTOR_YML_PATH = "refactor.yml";
|
|
1603
1713
|
function parseRefactorYml() {
|
|
1604
|
-
if (!
|
|
1714
|
+
if (!fs10.existsSync(REFACTOR_YML_PATH)) {
|
|
1605
1715
|
return [];
|
|
1606
1716
|
}
|
|
1607
|
-
const content =
|
|
1717
|
+
const content = fs10.readFileSync(REFACTOR_YML_PATH, "utf-8");
|
|
1608
1718
|
const entries = [];
|
|
1609
1719
|
const lines = content.split("\n");
|
|
1610
1720
|
let currentEntry = {};
|
|
@@ -1689,7 +1799,7 @@ Refactor check failed:
|
|
|
1689
1799
|
|
|
1690
1800
|
// src/commands/refactor/getViolations.ts
|
|
1691
1801
|
function countLines(filePath) {
|
|
1692
|
-
const content =
|
|
1802
|
+
const content = fs11.readFileSync(filePath, "utf-8");
|
|
1693
1803
|
return content.split("\n").length;
|
|
1694
1804
|
}
|
|
1695
1805
|
function getGitFiles(options) {
|
|
@@ -1741,12 +1851,12 @@ async function runVerifyQuietly() {
|
|
|
1741
1851
|
return true;
|
|
1742
1852
|
}
|
|
1743
1853
|
const { packageJsonPath, verifyScripts } = result;
|
|
1744
|
-
const packageDir =
|
|
1854
|
+
const packageDir = path14.dirname(packageJsonPath);
|
|
1745
1855
|
const results = await Promise.all(
|
|
1746
1856
|
verifyScripts.map(
|
|
1747
1857
|
(script) => new Promise(
|
|
1748
1858
|
(resolve) => {
|
|
1749
|
-
const child =
|
|
1859
|
+
const child = spawn2("npm", ["run", script], {
|
|
1750
1860
|
stdio: "pipe",
|
|
1751
1861
|
shell: true,
|
|
1752
1862
|
cwd: packageDir
|
|
@@ -1794,25 +1904,25 @@ async function check(pattern2, options) {
|
|
|
1794
1904
|
}
|
|
1795
1905
|
|
|
1796
1906
|
// src/commands/refactor/ignore.ts
|
|
1797
|
-
import
|
|
1907
|
+
import fs12 from "fs";
|
|
1798
1908
|
import chalk27 from "chalk";
|
|
1799
1909
|
var REFACTOR_YML_PATH2 = "refactor.yml";
|
|
1800
1910
|
function ignore(file) {
|
|
1801
|
-
if (!
|
|
1911
|
+
if (!fs12.existsSync(file)) {
|
|
1802
1912
|
console.error(chalk27.red(`Error: File does not exist: ${file}`));
|
|
1803
1913
|
process.exit(1);
|
|
1804
1914
|
}
|
|
1805
|
-
const content =
|
|
1915
|
+
const content = fs12.readFileSync(file, "utf-8");
|
|
1806
1916
|
const lineCount = content.split("\n").length;
|
|
1807
1917
|
const maxLines = lineCount + 10;
|
|
1808
1918
|
const entry = `- file: ${file}
|
|
1809
1919
|
maxLines: ${maxLines}
|
|
1810
1920
|
`;
|
|
1811
|
-
if (
|
|
1812
|
-
const existing =
|
|
1813
|
-
|
|
1921
|
+
if (fs12.existsSync(REFACTOR_YML_PATH2)) {
|
|
1922
|
+
const existing = fs12.readFileSync(REFACTOR_YML_PATH2, "utf-8");
|
|
1923
|
+
fs12.writeFileSync(REFACTOR_YML_PATH2, existing + entry);
|
|
1814
1924
|
} else {
|
|
1815
|
-
|
|
1925
|
+
fs12.writeFileSync(REFACTOR_YML_PATH2, entry);
|
|
1816
1926
|
}
|
|
1817
1927
|
console.log(
|
|
1818
1928
|
chalk27.green(
|
|
@@ -1822,7 +1932,7 @@ function ignore(file) {
|
|
|
1822
1932
|
}
|
|
1823
1933
|
|
|
1824
1934
|
// src/commands/run.ts
|
|
1825
|
-
import { spawn as
|
|
1935
|
+
import { spawn as spawn3 } from "child_process";
|
|
1826
1936
|
function run(name, args) {
|
|
1827
1937
|
const config = loadConfig();
|
|
1828
1938
|
if (!config.run || config.run.length === 0) {
|
|
@@ -1844,7 +1954,7 @@ function run(name, args) {
|
|
|
1844
1954
|
(arg) => arg.includes(" ") ? `"${arg}"` : arg
|
|
1845
1955
|
);
|
|
1846
1956
|
const fullCommand = [command, ...quotedArgs].join(" ");
|
|
1847
|
-
const child =
|
|
1957
|
+
const child = spawn3(fullCommand, [], {
|
|
1848
1958
|
stdio: "inherit",
|
|
1849
1959
|
shell: true
|
|
1850
1960
|
});
|
|
@@ -1888,20 +1998,11 @@ function add() {
|
|
|
1888
1998
|
}
|
|
1889
1999
|
|
|
1890
2000
|
// src/commands/statusLine.ts
|
|
1891
|
-
import * as readline from "readline";
|
|
1892
2001
|
function formatNumber(num) {
|
|
1893
2002
|
return num.toLocaleString("en-US");
|
|
1894
2003
|
}
|
|
1895
2004
|
async function statusLine() {
|
|
1896
|
-
const
|
|
1897
|
-
input: process.stdin,
|
|
1898
|
-
output: process.stdout,
|
|
1899
|
-
terminal: false
|
|
1900
|
-
});
|
|
1901
|
-
let inputData = "";
|
|
1902
|
-
for await (const line of rl) {
|
|
1903
|
-
inputData += line;
|
|
1904
|
-
}
|
|
2005
|
+
const inputData = await readStdin();
|
|
1905
2006
|
const data = JSON.parse(inputData);
|
|
1906
2007
|
const model = data.model.display_name;
|
|
1907
2008
|
const totalInput = data.context_window.total_input_tokens;
|
|
@@ -1915,22 +2016,22 @@ async function statusLine() {
|
|
|
1915
2016
|
}
|
|
1916
2017
|
|
|
1917
2018
|
// src/commands/sync.ts
|
|
1918
|
-
import * as
|
|
2019
|
+
import * as fs14 from "fs";
|
|
1919
2020
|
import * as os from "os";
|
|
1920
|
-
import * as
|
|
2021
|
+
import * as path16 from "path";
|
|
1921
2022
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
1922
2023
|
|
|
1923
2024
|
// src/commands/sync/syncSettings.ts
|
|
1924
|
-
import * as
|
|
1925
|
-
import * as
|
|
2025
|
+
import * as fs13 from "fs";
|
|
2026
|
+
import * as path15 from "path";
|
|
1926
2027
|
import chalk28 from "chalk";
|
|
1927
2028
|
async function syncSettings(claudeDir, targetBase) {
|
|
1928
|
-
const source =
|
|
1929
|
-
const target =
|
|
1930
|
-
const sourceContent =
|
|
2029
|
+
const source = path15.join(claudeDir, "settings.json");
|
|
2030
|
+
const target = path15.join(targetBase, "settings.json");
|
|
2031
|
+
const sourceContent = fs13.readFileSync(source, "utf-8");
|
|
1931
2032
|
const normalizedSource = JSON.stringify(JSON.parse(sourceContent), null, 2);
|
|
1932
|
-
if (
|
|
1933
|
-
const targetContent =
|
|
2033
|
+
if (fs13.existsSync(target)) {
|
|
2034
|
+
const targetContent = fs13.readFileSync(target, "utf-8");
|
|
1934
2035
|
const normalizedTarget = JSON.stringify(JSON.parse(targetContent), null, 2);
|
|
1935
2036
|
if (normalizedSource !== normalizedTarget) {
|
|
1936
2037
|
console.log(
|
|
@@ -1948,26 +2049,26 @@ async function syncSettings(claudeDir, targetBase) {
|
|
|
1948
2049
|
}
|
|
1949
2050
|
}
|
|
1950
2051
|
}
|
|
1951
|
-
|
|
2052
|
+
fs13.copyFileSync(source, target);
|
|
1952
2053
|
console.log("Copied settings.json to ~/.claude/settings.json");
|
|
1953
2054
|
}
|
|
1954
2055
|
|
|
1955
2056
|
// src/commands/sync.ts
|
|
1956
2057
|
var __filename2 = fileURLToPath4(import.meta.url);
|
|
1957
|
-
var __dirname5 =
|
|
2058
|
+
var __dirname5 = path16.dirname(__filename2);
|
|
1958
2059
|
async function sync() {
|
|
1959
|
-
const claudeDir =
|
|
1960
|
-
const targetBase =
|
|
2060
|
+
const claudeDir = path16.join(__dirname5, "..", "claude");
|
|
2061
|
+
const targetBase = path16.join(os.homedir(), ".claude");
|
|
1961
2062
|
syncCommands(claudeDir, targetBase);
|
|
1962
2063
|
await syncSettings(claudeDir, targetBase);
|
|
1963
2064
|
}
|
|
1964
2065
|
function syncCommands(claudeDir, targetBase) {
|
|
1965
|
-
const sourceDir =
|
|
1966
|
-
const targetDir =
|
|
1967
|
-
|
|
1968
|
-
const files =
|
|
2066
|
+
const sourceDir = path16.join(claudeDir, "commands");
|
|
2067
|
+
const targetDir = path16.join(targetBase, "commands");
|
|
2068
|
+
fs14.mkdirSync(targetDir, { recursive: true });
|
|
2069
|
+
const files = fs14.readdirSync(sourceDir);
|
|
1969
2070
|
for (const file of files) {
|
|
1970
|
-
|
|
2071
|
+
fs14.copyFileSync(path16.join(sourceDir, file), path16.join(targetDir, file));
|
|
1971
2072
|
console.log(`Copied ${file} to ${targetDir}`);
|
|
1972
2073
|
}
|
|
1973
2074
|
console.log(`Synced ${files.length} command(s) to ~/.claude/commands`);
|
|
@@ -2007,8 +2108,8 @@ Total: ${lines.length} hardcoded color(s)`);
|
|
|
2007
2108
|
}
|
|
2008
2109
|
|
|
2009
2110
|
// src/commands/verify/run.ts
|
|
2010
|
-
import { spawn as
|
|
2011
|
-
import * as
|
|
2111
|
+
import { spawn as spawn4 } from "child_process";
|
|
2112
|
+
import * as path17 from "path";
|
|
2012
2113
|
function formatDuration(ms) {
|
|
2013
2114
|
if (ms < 1e3) {
|
|
2014
2115
|
return `${ms}ms`;
|
|
@@ -2038,7 +2139,7 @@ async function run2(options = {}) {
|
|
|
2038
2139
|
return;
|
|
2039
2140
|
}
|
|
2040
2141
|
const { packageJsonPath, verifyScripts } = result;
|
|
2041
|
-
const packageDir =
|
|
2142
|
+
const packageDir = path17.dirname(packageJsonPath);
|
|
2042
2143
|
console.log(`Running ${verifyScripts.length} verify script(s) in parallel:`);
|
|
2043
2144
|
for (const script of verifyScripts) {
|
|
2044
2145
|
console.log(` - ${script}`);
|
|
@@ -2050,7 +2151,7 @@ async function run2(options = {}) {
|
|
|
2050
2151
|
const results = await Promise.all(
|
|
2051
2152
|
verifyScripts.map(
|
|
2052
2153
|
(script, index) => new Promise((resolve) => {
|
|
2053
|
-
const child =
|
|
2154
|
+
const child = spawn4("npm", ["run", script], {
|
|
2054
2155
|
stdio: "inherit",
|
|
2055
2156
|
shell: true,
|
|
2056
2157
|
cwd: packageDir
|
|
@@ -2124,4 +2225,7 @@ deployCommand.command("init").description("Initialize Netlify project and config
|
|
|
2124
2225
|
deployCommand.command("redirect").description("Add trailing slash redirect script to index.html").action(redirect);
|
|
2125
2226
|
program.command("enable-ralph").description("Enable ralph-wiggum plugin for spacetraders").action(enableRalph);
|
|
2126
2227
|
program.command("status-line").description("Format Claude Code status line from JSON stdin").action(statusLine);
|
|
2228
|
+
program.command("notify").description(
|
|
2229
|
+
"Show notification from Claude Code hook (reads JSON from stdin)"
|
|
2230
|
+
).action(notify);
|
|
2127
2231
|
program.parse();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@staff0rd/assist",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -34,7 +34,9 @@
|
|
|
34
34
|
"commander": "^14.0.2",
|
|
35
35
|
"diff": "^8.0.2",
|
|
36
36
|
"enquirer": "^2.4.1",
|
|
37
|
+
"is-wsl": "^3.1.0",
|
|
37
38
|
"minimatch": "^10.1.1",
|
|
39
|
+
"node-notifier": "^10.0.1",
|
|
38
40
|
"semver": "^7.7.3",
|
|
39
41
|
"yaml": "^2.8.2"
|
|
40
42
|
},
|
|
@@ -43,6 +45,7 @@
|
|
|
43
45
|
"@semantic-release/changelog": "^6.0.3",
|
|
44
46
|
"@semantic-release/git": "^10.0.1",
|
|
45
47
|
"@types/node": "^24.10.1",
|
|
48
|
+
"@types/node-notifier": "^8.0.5",
|
|
46
49
|
"@types/semver": "^7.7.1",
|
|
47
50
|
"jscpd": "^4.0.5",
|
|
48
51
|
"knip": "^5.71.0",
|