@staff0rd/assist 0.10.1 → 0.13.3
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/README.md +45 -44
- package/dist/commands/deploy/build.yml +25 -25
- package/dist/commands/deploy/init.ts +29 -9
- package/dist/commands/enable-ralph/index.ts +2 -7
- package/dist/commands/lint/init.ts +5 -7
- package/dist/index.js +266 -172
- package/package.json +53 -49
package/README.md
CHANGED
|
@@ -1,44 +1,45 @@
|
|
|
1
|
-
# assist
|
|
2
|
-
|
|
3
|
-
A CLI tool for enforcing determinism in LLM development workflow automation.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
# Clone the repository
|
|
9
|
-
git clone git@github.com:staff0rd/assist.git
|
|
10
|
-
cd assist
|
|
11
|
-
|
|
12
|
-
# Install dependencies
|
|
13
|
-
npm install
|
|
14
|
-
|
|
15
|
-
# Build the project
|
|
16
|
-
npm run build
|
|
17
|
-
|
|
18
|
-
# Install globally
|
|
19
|
-
npm install -g .
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
After installation, the `assist` command will be available globally.
|
|
23
|
-
|
|
24
|
-
## Commands
|
|
25
|
-
|
|
26
|
-
- `assist init` - Initialize project with VS Code and verify configurations
|
|
27
|
-
- `assist new` - Initialize a new Vite React TypeScript project
|
|
28
|
-
- `assist sync` - Copy command files to `~/.claude/commands`
|
|
29
|
-
- `assist commit <message>` - Create a git commit with validation
|
|
30
|
-
- `assist update` - Update claude-code to the latest version
|
|
31
|
-
- `assist verify` - Run all verify:* scripts from package.json in parallel
|
|
32
|
-
- `assist verify init` - Add verify scripts to a project
|
|
33
|
-
- `assist verify hardcoded-colors` - Check for hardcoded hex colors in src/
|
|
34
|
-
- `assist lint` - Run lint checks for conventions not enforced by biomejs
|
|
35
|
-
- `assist lint init` - Initialize Biome with standard linter config
|
|
36
|
-
- `assist refactor check [pattern]` - Check for files that exceed the maximum line count
|
|
37
|
-
- `assist refactor ignore <file>` - Add a file to the refactor ignore list
|
|
38
|
-
- `assist devlog list` - Group git commits by date
|
|
39
|
-
- `assist devlog next` - Show commits for the day after the last versioned entry
|
|
40
|
-
- `assist devlog skip <date>` - Add a date to the skip list
|
|
41
|
-
- `assist devlog version` - Show current repo name and version info
|
|
42
|
-
- `assist vscode init` - Add VS Code configuration files
|
|
43
|
-
- `assist deploy init` - Initialize Netlify project and configure deployment
|
|
44
|
-
|
|
1
|
+
# assist
|
|
2
|
+
|
|
3
|
+
A CLI tool for enforcing determinism in LLM development workflow automation.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Clone the repository
|
|
9
|
+
git clone git@github.com:staff0rd/assist.git
|
|
10
|
+
cd assist
|
|
11
|
+
|
|
12
|
+
# Install dependencies
|
|
13
|
+
npm install
|
|
14
|
+
|
|
15
|
+
# Build the project
|
|
16
|
+
npm run build
|
|
17
|
+
|
|
18
|
+
# Install globally
|
|
19
|
+
npm install -g .
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
After installation, the `assist` command will be available globally.
|
|
23
|
+
|
|
24
|
+
## Commands
|
|
25
|
+
|
|
26
|
+
- `assist init` - Initialize project with VS Code and verify configurations
|
|
27
|
+
- `assist new` - Initialize a new Vite React TypeScript project
|
|
28
|
+
- `assist sync` - Copy command files to `~/.claude/commands`
|
|
29
|
+
- `assist commit <message>` - Create a git commit with validation
|
|
30
|
+
- `assist update` - Update claude-code to the latest version
|
|
31
|
+
- `assist verify` - Run all verify:* scripts from package.json in parallel
|
|
32
|
+
- `assist verify init` - Add verify scripts to a project
|
|
33
|
+
- `assist verify hardcoded-colors` - Check for hardcoded hex colors in src/
|
|
34
|
+
- `assist lint` - Run lint checks for conventions not enforced by biomejs
|
|
35
|
+
- `assist lint init` - Initialize Biome with standard linter config
|
|
36
|
+
- `assist refactor check [pattern]` - Check for files that exceed the maximum line count
|
|
37
|
+
- `assist refactor ignore <file>` - Add a file to the refactor ignore list
|
|
38
|
+
- `assist devlog list` - Group git commits by date
|
|
39
|
+
- `assist devlog next` - Show commits for the day after the last versioned entry
|
|
40
|
+
- `assist devlog skip <date>` - Add a date to the skip list
|
|
41
|
+
- `assist devlog version` - Show current repo name and version info
|
|
42
|
+
- `assist vscode init` - Add VS Code configuration files
|
|
43
|
+
- `assist deploy init` - Initialize Netlify project and configure deployment
|
|
44
|
+
- `assist status-line` - Format Claude Code status line from JSON stdin
|
|
45
|
+
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
name: Build and Deploy to Netlify
|
|
2
|
-
on:
|
|
3
|
-
push:
|
|
4
|
-
branches:
|
|
5
|
-
- main
|
|
6
|
-
jobs:
|
|
7
|
-
build_and_deploy:
|
|
8
|
-
runs-on: ubuntu-latest
|
|
9
|
-
steps:
|
|
10
|
-
- uses: actions/checkout@v3
|
|
11
|
-
name: Checkout
|
|
12
|
-
|
|
13
|
-
- uses: actions/setup-node@v4
|
|
14
|
-
name: Setup Node.js
|
|
15
|
-
with:
|
|
16
|
-
node-version: "22"
|
|
17
|
-
|
|
18
|
-
- run: npm ci
|
|
19
|
-
name: Install dependencies
|
|
20
|
-
|
|
21
|
-
- run: npm run build
|
|
22
|
-
name: Build project
|
|
23
|
-
|
|
24
|
-
- run: npx netlify-cli deploy --no-build --dir=dist --prod -s {{NETLIFY_SITE_ID}} --auth ${{ secrets.NETLIFY_AUTH_TOKEN }} --message "Deployed commit ${{ github.sha }}"
|
|
25
|
-
name: Deploy to Netlify
|
|
1
|
+
name: Build and Deploy to Netlify
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- main
|
|
6
|
+
jobs:
|
|
7
|
+
build_and_deploy:
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
steps:
|
|
10
|
+
- uses: actions/checkout@v3
|
|
11
|
+
name: Checkout
|
|
12
|
+
|
|
13
|
+
- uses: actions/setup-node@v4
|
|
14
|
+
name: Setup Node.js
|
|
15
|
+
with:
|
|
16
|
+
node-version: "22"
|
|
17
|
+
|
|
18
|
+
- run: npm ci
|
|
19
|
+
name: Install dependencies
|
|
20
|
+
|
|
21
|
+
- run: npm run build
|
|
22
|
+
name: Build project
|
|
23
|
+
|
|
24
|
+
- run: npx netlify-cli deploy --no-build --dir=dist --prod -s {{NETLIFY_SITE_ID}} --auth ${{ secrets.NETLIFY_AUTH_TOKEN }} --message "Deployed commit ${{ github.sha }}"
|
|
25
|
+
name: Deploy to Netlify
|
|
@@ -4,6 +4,7 @@ import { dirname, join } from "node:path";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import chalk from "chalk";
|
|
6
6
|
import enquirer from "enquirer";
|
|
7
|
+
import { promptConfirm } from "../../shared/promptConfirm";
|
|
7
8
|
import { printDiff } from "../../utils/printDiff";
|
|
8
9
|
|
|
9
10
|
const WORKFLOW_PATH = ".github/workflows/build.yml";
|
|
@@ -44,12 +45,7 @@ async function updateWorkflow(siteId: string): Promise<void> {
|
|
|
44
45
|
console.log();
|
|
45
46
|
printDiff(oldContent, newContent);
|
|
46
47
|
|
|
47
|
-
const
|
|
48
|
-
type: "confirm",
|
|
49
|
-
name: "confirm",
|
|
50
|
-
message: chalk.red("Update build.yml?"),
|
|
51
|
-
initial: true,
|
|
52
|
-
});
|
|
48
|
+
const confirm = await promptConfirm(chalk.red("Update build.yml?"));
|
|
53
49
|
|
|
54
50
|
if (!confirm) {
|
|
55
51
|
console.log("Skipped build.yml update");
|
|
@@ -73,9 +69,33 @@ export async function init(): Promise<void> {
|
|
|
73
69
|
}
|
|
74
70
|
|
|
75
71
|
console.log("Creating Netlify site...\n");
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
72
|
+
try {
|
|
73
|
+
execSync("netlify sites:create --disable-linking", {
|
|
74
|
+
stdio: "inherit",
|
|
75
|
+
});
|
|
76
|
+
} catch (error) {
|
|
77
|
+
if (error instanceof Error && error.message.includes("command not found")) {
|
|
78
|
+
console.error(chalk.red("\nNetlify CLI is not installed.\n"));
|
|
79
|
+
const install = await promptConfirm("Would you like to install it now?");
|
|
80
|
+
if (install) {
|
|
81
|
+
console.log(chalk.dim("\nInstalling netlify-cli...\n"));
|
|
82
|
+
execSync("npm install -g netlify-cli", { stdio: "inherit" });
|
|
83
|
+
console.log();
|
|
84
|
+
execSync("netlify sites:create --disable-linking", {
|
|
85
|
+
stdio: "inherit",
|
|
86
|
+
});
|
|
87
|
+
} else {
|
|
88
|
+
console.log(
|
|
89
|
+
chalk.yellow(
|
|
90
|
+
"\nInstall it manually with: npm install -g netlify-cli\n",
|
|
91
|
+
),
|
|
92
|
+
);
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
79
99
|
|
|
80
100
|
const { siteId } = await enquirer.prompt<{ siteId: string }>({
|
|
81
101
|
type: "input",
|
|
@@ -2,7 +2,7 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import chalk from "chalk";
|
|
5
|
-
import
|
|
5
|
+
import { promptConfirm } from "../../shared/promptConfirm";
|
|
6
6
|
import { printDiff } from "../../utils/printDiff";
|
|
7
7
|
|
|
8
8
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -66,12 +66,7 @@ export async function enableRalph(): Promise<void> {
|
|
|
66
66
|
console.log();
|
|
67
67
|
printDiff(targetContent, mergedContent);
|
|
68
68
|
|
|
69
|
-
const
|
|
70
|
-
type: "confirm",
|
|
71
|
-
name: "confirm",
|
|
72
|
-
message: "Apply these changes?",
|
|
73
|
-
initial: true,
|
|
74
|
-
});
|
|
69
|
+
const confirm = await promptConfirm("Apply these changes?");
|
|
75
70
|
|
|
76
71
|
if (!confirm) {
|
|
77
72
|
console.log("Skipped");
|
|
@@ -3,12 +3,15 @@ import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import chalk from "chalk";
|
|
6
|
-
import
|
|
6
|
+
import { promptConfirm } from "../../shared/promptConfirm";
|
|
7
|
+
import { removeEslint } from "../../shared/removeEslint";
|
|
7
8
|
import { printDiff } from "../../utils/printDiff";
|
|
8
9
|
|
|
9
10
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
11
|
|
|
11
12
|
export async function init(): Promise<void> {
|
|
13
|
+
removeEslint();
|
|
14
|
+
|
|
12
15
|
const biomeConfigPath = "biome.json";
|
|
13
16
|
|
|
14
17
|
if (!existsSync(biomeConfigPath)) {
|
|
@@ -41,12 +44,7 @@ export async function init(): Promise<void> {
|
|
|
41
44
|
console.log();
|
|
42
45
|
printDiff(oldContent, newContent);
|
|
43
46
|
|
|
44
|
-
const
|
|
45
|
-
type: "confirm",
|
|
46
|
-
name: "confirm",
|
|
47
|
-
message: chalk.red("Update biome.json?"),
|
|
48
|
-
initial: true,
|
|
49
|
-
});
|
|
47
|
+
const confirm = await promptConfirm(chalk.red("Update biome.json?"));
|
|
50
48
|
|
|
51
49
|
if (!confirm) {
|
|
52
50
|
console.log("Skipped biome.json update");
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,73 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { execSync as
|
|
4
|
+
import { execSync as execSync13 } from "child_process";
|
|
5
5
|
import { Command } from "commander";
|
|
6
6
|
|
|
7
7
|
// src/commands/commit.ts
|
|
8
8
|
import { execSync } from "child_process";
|
|
9
|
+
|
|
10
|
+
// src/shared/loadConfig.ts
|
|
11
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
12
|
+
import { basename, join } from "path";
|
|
13
|
+
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
14
|
+
function getConfigPath() {
|
|
15
|
+
const claudeConfigPath = join(process.cwd(), ".claude", "assist.yml");
|
|
16
|
+
if (existsSync(claudeConfigPath)) {
|
|
17
|
+
return claudeConfigPath;
|
|
18
|
+
}
|
|
19
|
+
return join(process.cwd(), "assist.yml");
|
|
20
|
+
}
|
|
21
|
+
function loadConfig() {
|
|
22
|
+
const configPath = getConfigPath();
|
|
23
|
+
if (!existsSync(configPath)) {
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const content = readFileSync(configPath, "utf-8");
|
|
28
|
+
return parseYaml(content) || {};
|
|
29
|
+
} catch {
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function saveConfig(config) {
|
|
34
|
+
const configPath = getConfigPath();
|
|
35
|
+
writeFileSync(configPath, stringifyYaml(config, { lineWidth: 0 }));
|
|
36
|
+
}
|
|
37
|
+
function getRepoName() {
|
|
38
|
+
const config = loadConfig();
|
|
39
|
+
if (config.devlog?.name) {
|
|
40
|
+
return config.devlog.name;
|
|
41
|
+
}
|
|
42
|
+
const packageJsonPath = join(process.cwd(), "package.json");
|
|
43
|
+
if (existsSync(packageJsonPath)) {
|
|
44
|
+
try {
|
|
45
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
46
|
+
const pkg = JSON.parse(content);
|
|
47
|
+
if (pkg.name) {
|
|
48
|
+
return pkg.name;
|
|
49
|
+
}
|
|
50
|
+
} catch {
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return basename(process.cwd());
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// src/commands/commit.ts
|
|
9
57
|
var MAX_MESSAGE_LENGTH = 50;
|
|
58
|
+
var CONVENTIONAL_COMMIT_REGEX = /^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(!)?(\(.+\))?!?: .+$/;
|
|
10
59
|
function commit(message) {
|
|
60
|
+
const config = loadConfig();
|
|
11
61
|
if (message.toLowerCase().includes("claude")) {
|
|
12
62
|
console.error("Error: Commit message must not reference Claude");
|
|
13
63
|
process.exit(1);
|
|
14
64
|
}
|
|
65
|
+
if (config.commit?.conventional && !CONVENTIONAL_COMMIT_REGEX.test(message)) {
|
|
66
|
+
console.error(
|
|
67
|
+
"Error: Commit message must follow conventional commit format (e.g., 'feat: add feature', 'fix(scope): fix bug')"
|
|
68
|
+
);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
15
71
|
if (message.length > MAX_MESSAGE_LENGTH) {
|
|
16
72
|
console.error(
|
|
17
73
|
`Error: Commit message must be ${MAX_MESSAGE_LENGTH} characters or less (current: ${message.length})`
|
|
@@ -19,9 +75,16 @@ function commit(message) {
|
|
|
19
75
|
process.exit(1);
|
|
20
76
|
}
|
|
21
77
|
try {
|
|
78
|
+
if (config.commit?.pull) {
|
|
79
|
+
execSync("git pull", { stdio: "inherit" });
|
|
80
|
+
}
|
|
22
81
|
execSync(`git commit -m "${message.replace(/"/g, '\\"')}"`, {
|
|
23
82
|
stdio: "inherit"
|
|
24
83
|
});
|
|
84
|
+
if (config.commit?.push) {
|
|
85
|
+
execSync("git push", { stdio: "inherit" });
|
|
86
|
+
console.log("Pushed to remote");
|
|
87
|
+
}
|
|
25
88
|
process.exit(0);
|
|
26
89
|
} catch (_error) {
|
|
27
90
|
process.exit(1);
|
|
@@ -30,11 +93,28 @@ function commit(message) {
|
|
|
30
93
|
|
|
31
94
|
// src/commands/deploy/init.ts
|
|
32
95
|
import { execSync as execSync2 } from "child_process";
|
|
33
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
34
|
-
import { dirname, join } from "path";
|
|
96
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
97
|
+
import { dirname, join as join2 } from "path";
|
|
35
98
|
import { fileURLToPath } from "url";
|
|
36
99
|
import chalk2 from "chalk";
|
|
100
|
+
import enquirer2 from "enquirer";
|
|
101
|
+
|
|
102
|
+
// src/shared/promptConfirm.ts
|
|
37
103
|
import enquirer from "enquirer";
|
|
104
|
+
async function promptConfirm(message, initial = true) {
|
|
105
|
+
const { confirmed } = await enquirer.prompt({
|
|
106
|
+
type: "confirm",
|
|
107
|
+
name: "confirmed",
|
|
108
|
+
message,
|
|
109
|
+
initial,
|
|
110
|
+
// @ts-expect-error - enquirer types don't include symbols but it's supported
|
|
111
|
+
symbols: {
|
|
112
|
+
on: "[x]",
|
|
113
|
+
off: "[ ]"
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
return confirmed;
|
|
117
|
+
}
|
|
38
118
|
|
|
39
119
|
// src/utils/printDiff.ts
|
|
40
120
|
import chalk from "chalk";
|
|
@@ -69,26 +149,26 @@ function printDiff(oldContent, newContent) {
|
|
|
69
149
|
var WORKFLOW_PATH = ".github/workflows/build.yml";
|
|
70
150
|
var __dirname2 = dirname(fileURLToPath(import.meta.url));
|
|
71
151
|
function getExistingSiteId() {
|
|
72
|
-
if (!
|
|
152
|
+
if (!existsSync2(WORKFLOW_PATH)) {
|
|
73
153
|
return null;
|
|
74
154
|
}
|
|
75
|
-
const content =
|
|
155
|
+
const content = readFileSync2(WORKFLOW_PATH, "utf-8");
|
|
76
156
|
const match = content.match(/-s\s+([a-f0-9-]{36})/);
|
|
77
157
|
return match ? match[1] : null;
|
|
78
158
|
}
|
|
79
159
|
function getTemplateContent(siteId) {
|
|
80
|
-
const templatePath =
|
|
81
|
-
const template =
|
|
160
|
+
const templatePath = join2(__dirname2, "commands/deploy/build.yml");
|
|
161
|
+
const template = readFileSync2(templatePath, "utf-8");
|
|
82
162
|
return template.replace("{{NETLIFY_SITE_ID}}", siteId);
|
|
83
163
|
}
|
|
84
164
|
async function updateWorkflow(siteId) {
|
|
85
165
|
const newContent = getTemplateContent(siteId);
|
|
86
166
|
const workflowDir = ".github/workflows";
|
|
87
|
-
if (!
|
|
167
|
+
if (!existsSync2(workflowDir)) {
|
|
88
168
|
mkdirSync(workflowDir, { recursive: true });
|
|
89
169
|
}
|
|
90
|
-
if (
|
|
91
|
-
const oldContent =
|
|
170
|
+
if (existsSync2(WORKFLOW_PATH)) {
|
|
171
|
+
const oldContent = readFileSync2(WORKFLOW_PATH, "utf-8");
|
|
92
172
|
if (oldContent === newContent) {
|
|
93
173
|
console.log(chalk2.green("build.yml is already up to date"));
|
|
94
174
|
return;
|
|
@@ -96,18 +176,13 @@ async function updateWorkflow(siteId) {
|
|
|
96
176
|
console.log(chalk2.yellow("\nbuild.yml will be updated:"));
|
|
97
177
|
console.log();
|
|
98
178
|
printDiff(oldContent, newContent);
|
|
99
|
-
const
|
|
100
|
-
type: "confirm",
|
|
101
|
-
name: "confirm",
|
|
102
|
-
message: chalk2.red("Update build.yml?"),
|
|
103
|
-
initial: true
|
|
104
|
-
});
|
|
179
|
+
const confirm = await promptConfirm(chalk2.red("Update build.yml?"));
|
|
105
180
|
if (!confirm) {
|
|
106
181
|
console.log("Skipped build.yml update");
|
|
107
182
|
return;
|
|
108
183
|
}
|
|
109
184
|
}
|
|
110
|
-
|
|
185
|
+
writeFileSync2(WORKFLOW_PATH, newContent);
|
|
111
186
|
console.log(chalk2.green(`
|
|
112
187
|
Created ${WORKFLOW_PATH}`));
|
|
113
188
|
}
|
|
@@ -121,10 +196,34 @@ async function init() {
|
|
|
121
196
|
return;
|
|
122
197
|
}
|
|
123
198
|
console.log("Creating Netlify site...\n");
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
199
|
+
try {
|
|
200
|
+
execSync2("netlify sites:create --disable-linking", {
|
|
201
|
+
stdio: "inherit"
|
|
202
|
+
});
|
|
203
|
+
} catch (error) {
|
|
204
|
+
if (error instanceof Error && error.message.includes("command not found")) {
|
|
205
|
+
console.error(chalk2.red("\nNetlify CLI is not installed.\n"));
|
|
206
|
+
const install = await promptConfirm("Would you like to install it now?");
|
|
207
|
+
if (install) {
|
|
208
|
+
console.log(chalk2.dim("\nInstalling netlify-cli...\n"));
|
|
209
|
+
execSync2("npm install -g netlify-cli", { stdio: "inherit" });
|
|
210
|
+
console.log();
|
|
211
|
+
execSync2("netlify sites:create --disable-linking", {
|
|
212
|
+
stdio: "inherit"
|
|
213
|
+
});
|
|
214
|
+
} else {
|
|
215
|
+
console.log(
|
|
216
|
+
chalk2.yellow(
|
|
217
|
+
"\nInstall it manually with: npm install -g netlify-cli\n"
|
|
218
|
+
)
|
|
219
|
+
);
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
222
|
+
} else {
|
|
223
|
+
throw error;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
const { siteId } = await enquirer2.prompt({
|
|
128
227
|
type: "input",
|
|
129
228
|
name: "siteId",
|
|
130
229
|
message: "Enter the Site ID from above:",
|
|
@@ -156,52 +255,6 @@ import chalk4 from "chalk";
|
|
|
156
255
|
import { execSync as execSync3 } from "child_process";
|
|
157
256
|
import chalk3 from "chalk";
|
|
158
257
|
|
|
159
|
-
// src/shared/loadConfig.ts
|
|
160
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
161
|
-
import { basename, join as join2 } from "path";
|
|
162
|
-
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
163
|
-
function getConfigPath() {
|
|
164
|
-
const claudeConfigPath = join2(process.cwd(), ".claude", "assist.yml");
|
|
165
|
-
if (existsSync2(claudeConfigPath)) {
|
|
166
|
-
return claudeConfigPath;
|
|
167
|
-
}
|
|
168
|
-
return join2(process.cwd(), "assist.yml");
|
|
169
|
-
}
|
|
170
|
-
function loadConfig() {
|
|
171
|
-
const configPath = getConfigPath();
|
|
172
|
-
if (!existsSync2(configPath)) {
|
|
173
|
-
return {};
|
|
174
|
-
}
|
|
175
|
-
try {
|
|
176
|
-
const content = readFileSync2(configPath, "utf-8");
|
|
177
|
-
return parseYaml(content) || {};
|
|
178
|
-
} catch {
|
|
179
|
-
return {};
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
function saveConfig(config) {
|
|
183
|
-
const configPath = getConfigPath();
|
|
184
|
-
writeFileSync2(configPath, stringifyYaml(config, { lineWidth: 0 }));
|
|
185
|
-
}
|
|
186
|
-
function getRepoName() {
|
|
187
|
-
const config = loadConfig();
|
|
188
|
-
if (config.devlog?.name) {
|
|
189
|
-
return config.devlog.name;
|
|
190
|
-
}
|
|
191
|
-
const packageJsonPath = join2(process.cwd(), "package.json");
|
|
192
|
-
if (existsSync2(packageJsonPath)) {
|
|
193
|
-
try {
|
|
194
|
-
const content = readFileSync2(packageJsonPath, "utf-8");
|
|
195
|
-
const pkg = JSON.parse(content);
|
|
196
|
-
if (pkg.name) {
|
|
197
|
-
return pkg.name;
|
|
198
|
-
}
|
|
199
|
-
} catch {
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
return basename(process.cwd());
|
|
203
|
-
}
|
|
204
|
-
|
|
205
258
|
// src/commands/devlog/loadDevlogEntries.ts
|
|
206
259
|
import { readdirSync, readFileSync as readFileSync3 } from "fs";
|
|
207
260
|
import { homedir } from "os";
|
|
@@ -498,7 +551,6 @@ import * as fs from "fs";
|
|
|
498
551
|
import * as path from "path";
|
|
499
552
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
500
553
|
import chalk8 from "chalk";
|
|
501
|
-
import enquirer2 from "enquirer";
|
|
502
554
|
var __dirname3 = path.dirname(fileURLToPath2(import.meta.url));
|
|
503
555
|
function deepMerge(target, source) {
|
|
504
556
|
const result = { ...target };
|
|
@@ -542,12 +594,7 @@ async function enableRalph() {
|
|
|
542
594
|
console.log(chalk8.yellow("\nChanges to settings.local.json:"));
|
|
543
595
|
console.log();
|
|
544
596
|
printDiff(targetContent, mergedContent);
|
|
545
|
-
const
|
|
546
|
-
type: "confirm",
|
|
547
|
-
name: "confirm",
|
|
548
|
-
message: "Apply these changes?",
|
|
549
|
-
initial: true
|
|
550
|
-
});
|
|
597
|
+
const confirm = await promptConfirm("Apply these changes?");
|
|
551
598
|
if (!confirm) {
|
|
552
599
|
console.log("Skipped");
|
|
553
600
|
return;
|
|
@@ -570,7 +617,14 @@ async function promptMultiselect(message, options) {
|
|
|
570
617
|
choices: options.map((opt) => ({
|
|
571
618
|
name: opt.value,
|
|
572
619
|
message: `${opt.name} - ${chalk9.dim(opt.description)}`
|
|
573
|
-
}))
|
|
620
|
+
})),
|
|
621
|
+
// @ts-expect-error - enquirer types don't include symbols but it's supported
|
|
622
|
+
symbols: {
|
|
623
|
+
indicator: {
|
|
624
|
+
on: "[x]",
|
|
625
|
+
off: "[ ]"
|
|
626
|
+
}
|
|
627
|
+
}
|
|
574
628
|
});
|
|
575
629
|
return selected;
|
|
576
630
|
}
|
|
@@ -763,26 +817,104 @@ import * as path7 from "path";
|
|
|
763
817
|
import chalk17 from "chalk";
|
|
764
818
|
|
|
765
819
|
// src/commands/lint/init.ts
|
|
766
|
-
import { execSync as
|
|
767
|
-
import { existsSync as
|
|
820
|
+
import { execSync as execSync8 } from "child_process";
|
|
821
|
+
import { existsSync as existsSync7, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "fs";
|
|
768
822
|
import { dirname as dirname7, join as join8 } from "path";
|
|
769
823
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
770
824
|
import chalk16 from "chalk";
|
|
771
|
-
|
|
825
|
+
|
|
826
|
+
// src/shared/removeEslint.ts
|
|
827
|
+
import { execSync as execSync7 } from "child_process";
|
|
828
|
+
import { existsSync as existsSync6, readFileSync as readFileSync8, unlinkSync, writeFileSync as writeFileSync5 } from "fs";
|
|
829
|
+
function removeEslint(options = {}) {
|
|
830
|
+
const removedFromPackageJson = removeEslintFromPackageJson(options);
|
|
831
|
+
const removedConfigFiles = removeEslintConfigFiles();
|
|
832
|
+
if (removedFromPackageJson || removedConfigFiles) {
|
|
833
|
+
console.log("Running npm install...");
|
|
834
|
+
execSync7("npm install", { stdio: "inherit" });
|
|
835
|
+
return true;
|
|
836
|
+
}
|
|
837
|
+
return false;
|
|
838
|
+
}
|
|
839
|
+
function removeEslintFromPackageJson(options) {
|
|
840
|
+
const packageJsonPath = "package.json";
|
|
841
|
+
if (!existsSync6(packageJsonPath)) {
|
|
842
|
+
return false;
|
|
843
|
+
}
|
|
844
|
+
const packageJson = JSON.parse(readFileSync8(packageJsonPath, "utf-8"));
|
|
845
|
+
let modified = false;
|
|
846
|
+
if (packageJson.dependencies) {
|
|
847
|
+
for (const key of Object.keys(packageJson.dependencies)) {
|
|
848
|
+
if (key.includes("eslint")) {
|
|
849
|
+
delete packageJson.dependencies[key];
|
|
850
|
+
modified = true;
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
if (packageJson.devDependencies) {
|
|
855
|
+
for (const key of Object.keys(packageJson.devDependencies)) {
|
|
856
|
+
if (key.includes("eslint")) {
|
|
857
|
+
delete packageJson.devDependencies[key];
|
|
858
|
+
modified = true;
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
if (packageJson.scripts) {
|
|
863
|
+
for (const key of Object.keys(packageJson.scripts)) {
|
|
864
|
+
const isEslintScript = key.includes("eslint") || packageJson.scripts[key].includes("eslint") || options.removeLintScripts && key.includes("lint");
|
|
865
|
+
if (isEslintScript) {
|
|
866
|
+
delete packageJson.scripts[key];
|
|
867
|
+
modified = true;
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
if (modified) {
|
|
872
|
+
writeFileSync5(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
|
|
873
|
+
`);
|
|
874
|
+
console.log("Removed eslint references from package.json");
|
|
875
|
+
}
|
|
876
|
+
return modified;
|
|
877
|
+
}
|
|
878
|
+
function removeEslintConfigFiles() {
|
|
879
|
+
const eslintConfigFiles = [
|
|
880
|
+
"eslint.config.js",
|
|
881
|
+
"eslint.config.mjs",
|
|
882
|
+
"eslint.config.cjs",
|
|
883
|
+
".eslintrc",
|
|
884
|
+
".eslintrc.js",
|
|
885
|
+
".eslintrc.cjs",
|
|
886
|
+
".eslintrc.json",
|
|
887
|
+
".eslintrc.yaml",
|
|
888
|
+
".eslintrc.yml",
|
|
889
|
+
".eslintignore"
|
|
890
|
+
];
|
|
891
|
+
let removed = false;
|
|
892
|
+
for (const configFile of eslintConfigFiles) {
|
|
893
|
+
if (existsSync6(configFile)) {
|
|
894
|
+
unlinkSync(configFile);
|
|
895
|
+
console.log(`Removed ${configFile}`);
|
|
896
|
+
removed = true;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
return removed;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
// src/commands/lint/init.ts
|
|
772
903
|
var __dirname4 = dirname7(fileURLToPath3(import.meta.url));
|
|
773
904
|
async function init2() {
|
|
905
|
+
removeEslint();
|
|
774
906
|
const biomeConfigPath = "biome.json";
|
|
775
|
-
if (!
|
|
907
|
+
if (!existsSync7(biomeConfigPath)) {
|
|
776
908
|
console.log("Initializing Biome...");
|
|
777
|
-
|
|
909
|
+
execSync8("npx @biomejs/biome init", { stdio: "inherit" });
|
|
778
910
|
}
|
|
779
|
-
if (!
|
|
911
|
+
if (!existsSync7(biomeConfigPath)) {
|
|
780
912
|
console.log("No biome.json found, skipping linter config");
|
|
781
913
|
return;
|
|
782
914
|
}
|
|
783
915
|
const linterConfigPath = join8(__dirname4, "commands/lint/biome.linter.json");
|
|
784
|
-
const linterConfig = JSON.parse(
|
|
785
|
-
const biomeConfig = JSON.parse(
|
|
916
|
+
const linterConfig = JSON.parse(readFileSync9(linterConfigPath, "utf-8"));
|
|
917
|
+
const biomeConfig = JSON.parse(readFileSync9(biomeConfigPath, "utf-8"));
|
|
786
918
|
const oldContent = `${JSON.stringify(biomeConfig, null, 2)}
|
|
787
919
|
`;
|
|
788
920
|
biomeConfig.linter = linterConfig.linter;
|
|
@@ -798,17 +930,12 @@ async function init2() {
|
|
|
798
930
|
console.log(chalk16.yellow("\n\u26A0\uFE0F biome.json will be updated:"));
|
|
799
931
|
console.log();
|
|
800
932
|
printDiff(oldContent, newContent);
|
|
801
|
-
const
|
|
802
|
-
type: "confirm",
|
|
803
|
-
name: "confirm",
|
|
804
|
-
message: chalk16.red("Update biome.json?"),
|
|
805
|
-
initial: true
|
|
806
|
-
});
|
|
933
|
+
const confirm = await promptConfirm(chalk16.red("Update biome.json?"));
|
|
807
934
|
if (!confirm) {
|
|
808
935
|
console.log("Skipped biome.json update");
|
|
809
936
|
return;
|
|
810
937
|
}
|
|
811
|
-
|
|
938
|
+
writeFileSync6(biomeConfigPath, newContent);
|
|
812
939
|
console.log("Updated biome.json with linter config");
|
|
813
940
|
}
|
|
814
941
|
|
|
@@ -1306,64 +1433,25 @@ function lint() {
|
|
|
1306
1433
|
}
|
|
1307
1434
|
|
|
1308
1435
|
// src/commands/new/newProject.ts
|
|
1309
|
-
import { execSync as
|
|
1310
|
-
import { existsSync as
|
|
1436
|
+
import { execSync as execSync9 } from "child_process";
|
|
1437
|
+
import { existsSync as existsSync10, readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "fs";
|
|
1311
1438
|
async function newProject() {
|
|
1312
1439
|
console.log("Initializing Vite with react-ts template...");
|
|
1313
|
-
|
|
1440
|
+
execSync9("npm create vite@latest . -- --template react-ts", {
|
|
1314
1441
|
stdio: "inherit"
|
|
1315
1442
|
});
|
|
1316
|
-
|
|
1317
|
-
removeEslintConfigFile();
|
|
1443
|
+
removeEslint({ removeLintScripts: true });
|
|
1318
1444
|
addViteBaseConfig();
|
|
1319
1445
|
await init5();
|
|
1320
1446
|
await init();
|
|
1321
1447
|
}
|
|
1322
|
-
function removeEslintFromPackageJson() {
|
|
1323
|
-
const packageJsonPath = "package.json";
|
|
1324
|
-
if (!existsSync9(packageJsonPath)) {
|
|
1325
|
-
console.log("No package.json found, skipping eslint removal");
|
|
1326
|
-
return;
|
|
1327
|
-
}
|
|
1328
|
-
const packageJson = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
|
|
1329
|
-
let modified = false;
|
|
1330
|
-
if (packageJson.dependencies) {
|
|
1331
|
-
for (const key of Object.keys(packageJson.dependencies)) {
|
|
1332
|
-
if (key.includes("eslint")) {
|
|
1333
|
-
delete packageJson.dependencies[key];
|
|
1334
|
-
modified = true;
|
|
1335
|
-
}
|
|
1336
|
-
}
|
|
1337
|
-
}
|
|
1338
|
-
if (packageJson.devDependencies) {
|
|
1339
|
-
for (const key of Object.keys(packageJson.devDependencies)) {
|
|
1340
|
-
if (key.includes("eslint")) {
|
|
1341
|
-
delete packageJson.devDependencies[key];
|
|
1342
|
-
modified = true;
|
|
1343
|
-
}
|
|
1344
|
-
}
|
|
1345
|
-
}
|
|
1346
|
-
if (packageJson.scripts) {
|
|
1347
|
-
for (const key of Object.keys(packageJson.scripts)) {
|
|
1348
|
-
if (key.includes("eslint") || key.includes("lint") || packageJson.scripts[key].includes("eslint")) {
|
|
1349
|
-
delete packageJson.scripts[key];
|
|
1350
|
-
modified = true;
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
1353
|
-
}
|
|
1354
|
-
if (modified) {
|
|
1355
|
-
writeFileSync7(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
|
|
1356
|
-
`);
|
|
1357
|
-
console.log("Removed eslint references from package.json");
|
|
1358
|
-
}
|
|
1359
|
-
}
|
|
1360
1448
|
function addViteBaseConfig() {
|
|
1361
1449
|
const viteConfigPath = "vite.config.ts";
|
|
1362
|
-
if (!
|
|
1450
|
+
if (!existsSync10(viteConfigPath)) {
|
|
1363
1451
|
console.log("No vite.config.ts found, skipping base config");
|
|
1364
1452
|
return;
|
|
1365
1453
|
}
|
|
1366
|
-
const content =
|
|
1454
|
+
const content = readFileSync11(viteConfigPath, "utf-8");
|
|
1367
1455
|
if (content.includes("base:")) {
|
|
1368
1456
|
console.log("vite.config.ts already has base config");
|
|
1369
1457
|
return;
|
|
@@ -1373,39 +1461,20 @@ function addViteBaseConfig() {
|
|
|
1373
1461
|
'defineConfig({\n base: "./",'
|
|
1374
1462
|
);
|
|
1375
1463
|
if (updated !== content) {
|
|
1376
|
-
|
|
1464
|
+
writeFileSync8(viteConfigPath, updated);
|
|
1377
1465
|
console.log('Added base: "./" to vite.config.ts');
|
|
1378
1466
|
}
|
|
1379
1467
|
}
|
|
1380
|
-
function removeEslintConfigFile() {
|
|
1381
|
-
const eslintConfigFiles = [
|
|
1382
|
-
"eslint.config.js",
|
|
1383
|
-
"eslint.config.mjs",
|
|
1384
|
-
"eslint.config.cjs",
|
|
1385
|
-
".eslintrc",
|
|
1386
|
-
".eslintrc.js",
|
|
1387
|
-
".eslintrc.cjs",
|
|
1388
|
-
".eslintrc.json",
|
|
1389
|
-
".eslintrc.yaml",
|
|
1390
|
-
".eslintrc.yml"
|
|
1391
|
-
];
|
|
1392
|
-
for (const configFile of eslintConfigFiles) {
|
|
1393
|
-
if (existsSync9(configFile)) {
|
|
1394
|
-
unlinkSync(configFile);
|
|
1395
|
-
console.log(`Removed ${configFile}`);
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
1468
|
|
|
1400
1469
|
// src/commands/prs.ts
|
|
1401
|
-
import { execSync as
|
|
1470
|
+
import { execSync as execSync10 } from "child_process";
|
|
1402
1471
|
import chalk24 from "chalk";
|
|
1403
|
-
import
|
|
1472
|
+
import enquirer4 from "enquirer";
|
|
1404
1473
|
var PAGE_SIZE = 10;
|
|
1405
1474
|
async function prs(options) {
|
|
1406
1475
|
const state = options.open ? "open" : options.closed ? "closed" : "all";
|
|
1407
1476
|
try {
|
|
1408
|
-
const result =
|
|
1477
|
+
const result = execSync10(
|
|
1409
1478
|
`gh pr list --state ${state} --json number,title,url,author,createdAt,mergedAt,closedAt,state,changedFiles --limit 100`,
|
|
1410
1479
|
{ encoding: "utf-8" }
|
|
1411
1480
|
);
|
|
@@ -1472,7 +1541,7 @@ Page ${page + 1} of ${totalPages} (${pullRequests.length} total)
|
|
|
1472
1541
|
if (hasNext) choices.push({ name: "Next page", value: "next" });
|
|
1473
1542
|
if (hasPrev) choices.push({ name: "Previous page", value: "prev" });
|
|
1474
1543
|
choices.push({ name: "Quit", value: "quit" });
|
|
1475
|
-
const { action } = await
|
|
1544
|
+
const { action } = await enquirer4.prompt({
|
|
1476
1545
|
type: "select",
|
|
1477
1546
|
name: "action",
|
|
1478
1547
|
message: "Navigate",
|
|
@@ -1495,7 +1564,7 @@ import { spawn } from "child_process";
|
|
|
1495
1564
|
import * as path13 from "path";
|
|
1496
1565
|
|
|
1497
1566
|
// src/commands/refactor/getViolations.ts
|
|
1498
|
-
import { execSync as
|
|
1567
|
+
import { execSync as execSync11 } from "child_process";
|
|
1499
1568
|
import fs10 from "fs";
|
|
1500
1569
|
import { minimatch } from "minimatch";
|
|
1501
1570
|
|
|
@@ -1600,7 +1669,7 @@ function getGitFiles(options) {
|
|
|
1600
1669
|
}
|
|
1601
1670
|
const files = /* @__PURE__ */ new Set();
|
|
1602
1671
|
if (options.staged || options.modified) {
|
|
1603
|
-
const staged =
|
|
1672
|
+
const staged = execSync11("git diff --cached --name-only", {
|
|
1604
1673
|
encoding: "utf-8"
|
|
1605
1674
|
});
|
|
1606
1675
|
for (const file of staged.trim().split("\n").filter(Boolean)) {
|
|
@@ -1608,7 +1677,7 @@ function getGitFiles(options) {
|
|
|
1608
1677
|
}
|
|
1609
1678
|
}
|
|
1610
1679
|
if (options.unstaged || options.modified) {
|
|
1611
|
-
const unstaged =
|
|
1680
|
+
const unstaged = execSync11("git diff --name-only", { encoding: "utf-8" });
|
|
1612
1681
|
for (const file of unstaged.trim().split("\n").filter(Boolean)) {
|
|
1613
1682
|
files.add(file);
|
|
1614
1683
|
}
|
|
@@ -1789,6 +1858,33 @@ function add() {
|
|
|
1789
1858
|
console.log(`Added run configuration: ${name} -> ${display}`);
|
|
1790
1859
|
}
|
|
1791
1860
|
|
|
1861
|
+
// src/commands/statusLine.ts
|
|
1862
|
+
import * as readline from "readline";
|
|
1863
|
+
function formatNumber(num) {
|
|
1864
|
+
return num.toLocaleString("en-US");
|
|
1865
|
+
}
|
|
1866
|
+
async function statusLine() {
|
|
1867
|
+
const rl = readline.createInterface({
|
|
1868
|
+
input: process.stdin,
|
|
1869
|
+
output: process.stdout,
|
|
1870
|
+
terminal: false
|
|
1871
|
+
});
|
|
1872
|
+
let inputData = "";
|
|
1873
|
+
for await (const line of rl) {
|
|
1874
|
+
inputData += line;
|
|
1875
|
+
}
|
|
1876
|
+
const data = JSON.parse(inputData);
|
|
1877
|
+
const model = data.model.display_name;
|
|
1878
|
+
const totalInput = data.context_window.total_input_tokens;
|
|
1879
|
+
const totalOutput = data.context_window.total_output_tokens;
|
|
1880
|
+
const usedPct = data.context_window.used_percentage ?? 0;
|
|
1881
|
+
const formattedInput = formatNumber(totalInput);
|
|
1882
|
+
const formattedOutput = formatNumber(totalOutput);
|
|
1883
|
+
console.log(
|
|
1884
|
+
`${model} | Tokens - ${formattedOutput} \u2191 : ${formattedInput} \u2193 | Context - ${usedPct}%`
|
|
1885
|
+
);
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1792
1888
|
// src/commands/sync.ts
|
|
1793
1889
|
import * as fs13 from "fs";
|
|
1794
1890
|
import * as os from "os";
|
|
@@ -1799,7 +1895,6 @@ import { fileURLToPath as fileURLToPath4 } from "url";
|
|
|
1799
1895
|
import * as fs12 from "fs";
|
|
1800
1896
|
import * as path14 from "path";
|
|
1801
1897
|
import chalk27 from "chalk";
|
|
1802
|
-
import enquirer6 from "enquirer";
|
|
1803
1898
|
async function syncSettings(claudeDir, targetBase) {
|
|
1804
1899
|
const source = path14.join(claudeDir, "settings.json");
|
|
1805
1900
|
const target = path14.join(targetBase, "settings.json");
|
|
@@ -1814,12 +1909,10 @@ async function syncSettings(claudeDir, targetBase) {
|
|
|
1814
1909
|
);
|
|
1815
1910
|
console.log();
|
|
1816
1911
|
printDiff(targetContent, sourceContent);
|
|
1817
|
-
const
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
initial: false
|
|
1822
|
-
});
|
|
1912
|
+
const confirm = await promptConfirm(
|
|
1913
|
+
chalk27.red("Overwrite existing settings.json?"),
|
|
1914
|
+
false
|
|
1915
|
+
);
|
|
1823
1916
|
if (!confirm) {
|
|
1824
1917
|
console.log("Skipped settings.json");
|
|
1825
1918
|
return;
|
|
@@ -1852,11 +1945,11 @@ function syncCommands(claudeDir, targetBase) {
|
|
|
1852
1945
|
}
|
|
1853
1946
|
|
|
1854
1947
|
// src/commands/verify/hardcodedColors.ts
|
|
1855
|
-
import { execSync as
|
|
1948
|
+
import { execSync as execSync12 } from "child_process";
|
|
1856
1949
|
var pattern = "0x[0-9a-fA-F]{6}|#[0-9a-fA-F]{3,6}";
|
|
1857
1950
|
function hardcodedColors() {
|
|
1858
1951
|
try {
|
|
1859
|
-
const output =
|
|
1952
|
+
const output = execSync12(`grep -rEnH '${pattern}' src/`, {
|
|
1860
1953
|
encoding: "utf-8"
|
|
1861
1954
|
});
|
|
1862
1955
|
const lines = output.trim().split("\n");
|
|
@@ -1966,7 +2059,7 @@ program.command("init").description("Initialize VS Code and verify configuration
|
|
|
1966
2059
|
program.command("commit <message>").description("Create a git commit with validation").action(commit);
|
|
1967
2060
|
program.command("update").description("Update claude-code to the latest version").action(() => {
|
|
1968
2061
|
console.log("Updating claude-code...");
|
|
1969
|
-
|
|
2062
|
+
execSync13("npm install -g @anthropic-ai/claude-code", { stdio: "inherit" });
|
|
1970
2063
|
});
|
|
1971
2064
|
program.command("prs").description("List pull requests for the current repository").option("--open", "List only open pull requests").option("--closed", "List only closed pull requests").action(prs);
|
|
1972
2065
|
var runCommand = program.command("run").description("Run a configured command from assist.yml").argument("<name>", "Name of the configured command").argument("[args...]", "Arguments to pass to the command").allowUnknownOption().action((name, args) => {
|
|
@@ -2000,4 +2093,5 @@ vscodeCommand.command("init").description("Add VS Code configuration files").act
|
|
|
2000
2093
|
var deployCommand = program.command("deploy").description("Netlify deployment utilities");
|
|
2001
2094
|
deployCommand.command("init").description("Initialize Netlify project and configure deployment").action(init);
|
|
2002
2095
|
program.command("enable-ralph").description("Enable ralph-wiggum plugin for spacetraders").action(enableRalph);
|
|
2096
|
+
program.command("status-line").description("Format Claude Code status line from JSON stdin").action(statusLine);
|
|
2003
2097
|
program.parse();
|
package/package.json
CHANGED
|
@@ -1,49 +1,53 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@staff0rd/assist",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"type": "module",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"bin": {
|
|
7
|
-
"assist": "./dist/index.js"
|
|
8
|
-
},
|
|
9
|
-
"files": [
|
|
10
|
-
"dist"
|
|
11
|
-
],
|
|
12
|
-
"publishConfig": {
|
|
13
|
-
"access": "public"
|
|
14
|
-
},
|
|
15
|
-
"scripts": {
|
|
16
|
-
"build": "tsup",
|
|
17
|
-
"start": "node dist/index.js",
|
|
18
|
-
"verify:lint": "biome check --write .",
|
|
19
|
-
"verify:build": "tsup",
|
|
20
|
-
"verify:types": "tsc --noEmit",
|
|
21
|
-
"verify:knip": "knip --no-progress",
|
|
22
|
-
"verify:duplicate-code": "jscpd --format 'typescript,tsx' --exitCode 1 --ignore '**/*.test.*' -r consoleFull src"
|
|
23
|
-
},
|
|
24
|
-
"keywords": [],
|
|
25
|
-
"author": "",
|
|
26
|
-
"license": "ISC",
|
|
27
|
-
"description": "",
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"@
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@staff0rd/assist",
|
|
3
|
+
"version": "0.13.3",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"assist": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsup",
|
|
17
|
+
"start": "node dist/index.js",
|
|
18
|
+
"verify:lint": "biome check --write .",
|
|
19
|
+
"verify:build": "tsup",
|
|
20
|
+
"verify:types": "tsc --noEmit",
|
|
21
|
+
"verify:knip": "knip --no-progress",
|
|
22
|
+
"verify:duplicate-code": "jscpd --format 'typescript,tsx' --exitCode 1 --ignore '**/*.test.*' -r consoleFull src"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [],
|
|
25
|
+
"author": "",
|
|
26
|
+
"license": "ISC",
|
|
27
|
+
"description": "",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/staff0rd/assist"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"chalk": "^5.6.2",
|
|
34
|
+
"commander": "^14.0.2",
|
|
35
|
+
"diff": "^8.0.2",
|
|
36
|
+
"enquirer": "^2.4.1",
|
|
37
|
+
"minimatch": "^10.1.1",
|
|
38
|
+
"semver": "^7.7.3",
|
|
39
|
+
"yaml": "^2.8.2"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@biomejs/biome": "^2.3.8",
|
|
43
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
44
|
+
"@semantic-release/git": "^10.0.1",
|
|
45
|
+
"@types/node": "^24.10.1",
|
|
46
|
+
"@types/semver": "^7.7.1",
|
|
47
|
+
"jscpd": "^4.0.5",
|
|
48
|
+
"knip": "^5.71.0",
|
|
49
|
+
"semantic-release": "^25.0.2",
|
|
50
|
+
"tsup": "^8.5.1",
|
|
51
|
+
"typescript": "^5.9.3"
|
|
52
|
+
}
|
|
53
|
+
}
|