pasika 0.1.6 → 0.2.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.
Files changed (68) hide show
  1. package/README.md +40 -55
  2. package/dist/eslint/pasika/index.d.ts +18 -0
  3. package/dist/eslint/pasika/index.js +18 -3
  4. package/dist/eslint/pasika/rules/enforce-barrel-exports.d.ts +9 -0
  5. package/dist/eslint/pasika/rules/enforce-barrel-exports.js +78 -0
  6. package/dist/eslint/pasika/rules/enforce-cn-merge.d.ts +9 -0
  7. package/dist/eslint/pasika/rules/enforce-cn-merge.js +84 -0
  8. package/dist/eslint/pasika/rules/enforce-cva-variant-props.d.ts +9 -0
  9. package/dist/eslint/pasika/rules/enforce-cva-variant-props.js +76 -0
  10. package/dist/eslint/pasika/rules/filename-case.js +10 -0
  11. package/dist/eslint/pasika/rules/import-boundaries.d.ts +2 -0
  12. package/dist/eslint/pasika/rules/{organization-imports.js → import-boundaries.js} +11 -1
  13. package/dist/eslint/pasika/rules/no-arbitrary-tailwind.d.ts +9 -0
  14. package/dist/eslint/pasika/rules/no-arbitrary-tailwind.js +107 -0
  15. package/dist/eslint/pasika/rules/no-mixed-concerns.d.ts +9 -0
  16. package/dist/eslint/pasika/rules/no-mixed-concerns.js +84 -0
  17. package/package.json +5 -16
  18. package/claude/hooks/.vulyk +0 -3
  19. package/claude/hooks/AGENTS.md +0 -3
  20. package/claude/hooks/CLAUDE.md +0 -1
  21. package/claude/hooks/claude-hooks.md +0 -30
  22. package/claude/hooks/notification.sh +0 -38
  23. package/claude/hooks/protect-files.sh +0 -21
  24. package/claude/hooks/status-line/index.js +0 -57
  25. package/claude/scripts/render-settings.ts +0 -223
  26. package/claude/settings.base.json +0 -38
  27. package/dist/claude/scripts/render-settings.js +0 -145
  28. package/dist/eslint/pasika/rules/organization-imports.d.ts +0 -2
  29. package/dist/eslint.config.js +0 -7
  30. package/dist/scripts/pasika.js +0 -59
  31. package/docs/agent-conventions.md +0 -27
  32. package/docs/claude/hooks.md +0 -30
  33. package/docs/code-organization-guide/code-organization-guide.md +0 -69
  34. package/docs/code-organization-guide/references/application-architecture-reference.md +0 -149
  35. package/docs/code-organization-guide/rules/component-placement-rule.md +0 -119
  36. package/docs/code-organization-guide/rules/configuration-rule.md +0 -42
  37. package/docs/code-organization-guide/rules/constants-rule.md +0 -74
  38. package/docs/code-organization-guide/rules/exports-and-imports-rule.md +0 -84
  39. package/docs/code-organization-guide/rules/folder-nesting-rule.md +0 -82
  40. package/docs/code-organization-guide/rules/hook-extraction-rule.md +0 -141
  41. package/docs/code-organization-guide/rules/interactive-component-rule.md +0 -97
  42. package/docs/code-organization-guide/rules/jsx-hygiene-rule.md +0 -67
  43. package/docs/code-organization-guide/rules/locales-rule.md +0 -53
  44. package/docs/code-organization-guide/rules/nameable-visual-concept-rule.md +0 -66
  45. package/docs/code-organization-guide/rules/no-mixed-concerns-rule.md +0 -63
  46. package/docs/code-organization-guide/rules/repeated-structure-rule.md +0 -93
  47. package/docs/code-organization-guide/rules/smart-vs-dumb-component-rule.md +0 -112
  48. package/docs/code-organization-guide/rules/sole-state-owner-rule.md +0 -101
  49. package/docs/code-organization-guide/rules/types-and-schemas-rule.md +0 -139
  50. package/docs/code-organization-guide/rules/utilities-rule.md +0 -86
  51. package/docs/documentation-guide/_templates/grouped-reference.md +0 -11
  52. package/docs/documentation-guide/_templates/guide.md +0 -19
  53. package/docs/documentation-guide/_templates/rule.md +0 -21
  54. package/docs/documentation-guide/_templates/single-lookup-reference.md +0 -5
  55. package/docs/documentation-guide/documentation-guide.md +0 -13
  56. package/docs/documentation-guide/references/documentation-types-reference.md +0 -9
  57. package/docs/documentation-guide/rules/guide-creation-rule.md +0 -113
  58. package/docs/documentation-guide/rules/reference-creation-rule.md +0 -132
  59. package/docs/documentation-guide/rules/rule-creation-rule.md +0 -81
  60. package/docs/documentation-guide/rules/template-usage-rule.md +0 -49
  61. package/docs/shadcn-theme.md +0 -121
  62. package/docs/styling-guide/rules/arbitrary-value-rule.md +0 -31
  63. package/docs/styling-guide/rules/class-composition-rule.md +0 -52
  64. package/docs/styling-guide/rules/component-ui-state-rule.md +0 -53
  65. package/docs/styling-guide/rules/component-variant-rule.md +0 -125
  66. package/docs/styling-guide/rules/global-stylesheet-rule.md +0 -67
  67. package/docs/styling-guide/rules/theme-and-utility-definition-rule.md +0 -86
  68. package/docs/styling-guide/styling-guide.md +0 -14
@@ -0,0 +1,84 @@
1
+ /**
2
+ * ESLint rule: pasika/no-mixed-concerns
3
+ *
4
+ * Enforces the "No Mixed Concerns Rule" — one React component per .tsx file.
5
+ *
6
+ * @see docs/code-organization-guide/rules/no-mixed-concerns-rule.md
7
+ */
8
+ /**
9
+ * Return the name of an export node so we can report it clearly.
10
+ * Handles:
11
+ * export function Foo() { }
12
+ * export const Foo = () => { }
13
+ * export const Foo = function () { }
14
+ * export default function Foo() { }
15
+ * export default () => { }
16
+ */
17
+ // biome-ignore lint/suspicious/noExplicitAny: AST node type from ESLint with dynamic property access
18
+ function getExportName(declaration) {
19
+ if (declaration.type === "FunctionDeclaration" && declaration.id) {
20
+ return declaration.id.name;
21
+ }
22
+ if (declaration.type === "VariableDeclaration") {
23
+ const declarator = declaration.declarations[0];
24
+ if (declarator?.id.type === "Identifier" &&
25
+ (declarator.init?.type === "ArrowFunctionExpression" || declarator.init?.type === "FunctionExpression")) {
26
+ return declarator.id.name;
27
+ }
28
+ }
29
+ if (declaration.type === "ArrowFunctionExpression") {
30
+ return "default";
31
+ }
32
+ if (declaration.type === "FunctionExpression" && declaration.id) {
33
+ return declaration.id.name;
34
+ }
35
+ return null;
36
+ }
37
+ export const noMixedConcernsRule = {
38
+ meta: {
39
+ schema: [],
40
+ type: "problem",
41
+ docs: {
42
+ description: "Enforce one exported React component per .tsx file.",
43
+ },
44
+ },
45
+ create(context) {
46
+ if (!context.filename.endsWith(".tsx"))
47
+ return {};
48
+ let exportedComponentCount = 0;
49
+ const extraExports = [];
50
+ function registerExport(name) {
51
+ exportedComponentCount++;
52
+ if (exportedComponentCount > 1) {
53
+ extraExports.push({ name });
54
+ }
55
+ }
56
+ return {
57
+ ExportNamedDeclaration(node) {
58
+ if (!node.declaration)
59
+ return;
60
+ const name = getExportName(node.declaration);
61
+ if (name)
62
+ registerExport(name);
63
+ },
64
+ ExportDefaultDeclaration(node) {
65
+ const name = getExportName(node.declaration);
66
+ if (name)
67
+ registerExport(name);
68
+ },
69
+ "Program:exit"() {
70
+ if (exportedComponentCount > 1) {
71
+ for (const extra of extraExports) {
72
+ context.report({
73
+ loc: { line: 1, column: 0 },
74
+ message: `File exports multiple components. "${extra.name}" is an extra component export. ` +
75
+ "Move it to its own file. Each .tsx file MUST contain exactly one component. " +
76
+ "See docs/code-organization-guide/rules/no-mixed-concerns-rule.md",
77
+ });
78
+ }
79
+ }
80
+ },
81
+ };
82
+ },
83
+ };
84
+ /* eslint-enable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-explicit-any -- re-enable after AST node access block */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pasika",
3
- "version": "0.1.6",
3
+ "version": "0.2.0",
4
4
  "description": "Reusable agent setup package",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,33 +14,22 @@
14
14
  "import": "./dist/eslint/pasika/index.js"
15
15
  }
16
16
  },
17
- "bin": {
18
- "pasika": "dist/scripts/pasika.js"
19
- },
20
17
  "files": [
21
- "claude",
22
- "docs",
23
- "dist",
24
- "AGENTS.md",
25
- "CLAUDE.md",
26
- "README.md"
18
+ "dist/eslint"
27
19
  ],
28
20
  "scripts": {
29
- "build": "rm -rf dist && tsc -p tsconfig.json && tsc -p tsconfig.eslint.json",
30
- "check": "npm run lint && npm run typecheck",
31
- "docs:generate": "rm -f AGENTS.md CLAUDE.md && npx vulyk docs",
21
+ "build": "rm -rf dist && tsc -p tsconfig.build.json",
32
22
  "fix": "eslint . --fix",
33
23
  "lint": "eslint .",
34
24
  "prepack": "npm run build",
35
- "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.eslint.json --noEmit"
25
+ "typecheck": "tsc --noEmit"
36
26
  },
37
27
  "devDependencies": {
38
28
  "@types/node": "^24.12.2",
39
29
  "eslint": "^9.39.4",
40
30
  "prettier": "^3.8.1",
41
31
  "typescript": "^5.9.2",
42
- "vulyk": "github:Bredansky/vulyk#829cac4a244add961304070474db3e978db01d2a",
43
- "zirka": "^0.0.28"
32
+ "zirka": "^0.0.35"
44
33
  },
45
34
  "engines": {
46
35
  "node": ">=22"
@@ -1,3 +0,0 @@
1
- 🍯 AGENTS.md
2
- 🍯 CLAUDE.md
3
- 🍯 claude-hooks.md
@@ -1,3 +0,0 @@
1
- # Claude Hooks
2
- Shared Claude hooks shipped by pasika.
3
- Full documentation: docs/claude/hooks.md
@@ -1 +0,0 @@
1
- @AGENTS.md
@@ -1,30 +0,0 @@
1
- # Claude Hooks
2
-
3
- `pasika` ships the reusable shared Claude hooks.
4
-
5
- ## `status-line/index.js`
6
-
7
- Displays a two-line status view with:
8
-
9
- - model name
10
- - current folder
11
- - git branch when available
12
- - used context percentage as a 10-segment bar
13
- - session cost
14
- - session duration
15
-
16
- ## `notification.sh`
17
-
18
- Sends a desktop notification when Claude needs attention.
19
-
20
- - macOS: `terminal-notifier` with click-to-focus VS Code behavior, falls back to `osascript`
21
- - Linux: `notify-send`
22
- - Windows: PowerShell message box
23
-
24
- ## `protect-files.sh`
25
-
26
- Blocks edits to:
27
-
28
- - `.env` files
29
- - `package-lock.json`
30
- - files inside `.git/`
@@ -1,38 +0,0 @@
1
- #!/bin/bash
2
- # notification.sh - Cross-platform notification
3
-
4
- OS="$(uname -s)"
5
-
6
- case "$OS" in
7
- Darwin*)
8
- if command -v terminal-notifier &> /dev/null; then
9
- PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
10
- TEMP_SCRIPT=$(mktemp)
11
-
12
- cat > "$TEMP_SCRIPT" <<SCRIPTEND
13
- #!/bin/bash
14
- /usr/local/bin/code -r "$PROJECT_DIR"
15
- sleep 0.5
16
- osascript -e 'tell application "Visual Studio Code" to activate'
17
- SCRIPTEND
18
-
19
- chmod +x "$TEMP_SCRIPT"
20
-
21
- terminal-notifier \
22
- -message "Claude Code needs your attention - Click to focus terminal" \
23
- -title "Claude Code" \
24
- -sound Ping \
25
- -execute "$TEMP_SCRIPT"
26
-
27
- (sleep 60; rm -f "$TEMP_SCRIPT") &
28
- else
29
- osascript -e 'display notification "Claude Code needs your attention" with title "Claude Code"'
30
- fi
31
- ;;
32
- Linux*)
33
- notify-send 'Claude Code' 'Claude Code needs your attention'
34
- ;;
35
- MINGW*|MSYS*|CYGWIN*)
36
- powershell.exe -Command "[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Claude Code needs your attention', 'Claude Code')"
37
- ;;
38
- esac
@@ -1,21 +0,0 @@
1
- #!/bin/bash
2
- # protect-files.sh - Block edits to sensitive files
3
-
4
- INPUT=$(cat)
5
- FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
6
-
7
- PROTECTED_PATTERNS=(
8
- "/\.env$|^\.env$"
9
- "package-lock\.json$"
10
- "/\.git/|^\.git/"
11
- )
12
-
13
- for pattern in "${PROTECTED_PATTERNS[@]}"; do
14
- if echo "$FILE_PATH" | grep -qE "$pattern"; then
15
- echo "Blocked: Cannot edit protected file '$FILE_PATH'" >&2
16
- echo "Reason: This is a sensitive/generated file that should not be manually edited" >&2
17
- exit 2
18
- fi
19
- done
20
-
21
- exit 0
@@ -1,57 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { execSync } from "node:child_process";
4
- import path from "node:path";
5
-
6
- let input = "";
7
-
8
- process.stdin.on("data", (chunk) => {
9
- input += chunk;
10
- });
11
-
12
- process.stdin.on("end", () => {
13
- try {
14
- const data = JSON.parse(input || "{}");
15
- const model = data.model?.display_name || data.model?.name || "Claude";
16
- const dir = path.basename(data.workspace?.current_dir || process.cwd());
17
- const cost = Number(data.cost?.total_cost_usd || 0);
18
- const pct = Math.floor(Number(data.context_window?.used_percentage || 0));
19
- const durationMs = Number(data.cost?.total_duration_ms || 0);
20
-
21
- const CYAN = "\x1b[36m";
22
- const GREEN = "\x1b[32m";
23
- const YELLOW = "\x1b[33m";
24
- const RED = "\x1b[31m";
25
- const RESET = "\x1b[0m";
26
-
27
- let barColor = GREEN;
28
- if (pct >= 90) {
29
- barColor = RED;
30
- } else if (pct >= 70) {
31
- barColor = YELLOW;
32
- }
33
-
34
- const filled = Math.max(0, Math.min(10, Math.floor(pct / 10)));
35
- const bar = "█".repeat(filled) + "░".repeat(10 - filled);
36
- const mins = Math.floor(durationMs / 60000);
37
- const secs = Math.floor((durationMs % 60000) / 1000);
38
-
39
- let branch = "";
40
- try {
41
- branch = execSync("git branch --show-current", {
42
- encoding: "utf8",
43
- stdio: ["pipe", "pipe", "ignore"],
44
- }).trim();
45
- branch = branch ? ` | 🌿 ${branch}` : "";
46
- } catch {
47
- branch = "";
48
- }
49
-
50
- process.stdout.write(`${CYAN}[${model}]${RESET} 📁 ${dir}${branch}\n`);
51
- process.stdout.write(
52
- `${barColor}${bar}${RESET} ${pct}% | ${YELLOW}$${cost.toFixed(2)}${RESET} | ⏱️ ${mins}m ${secs}s\n`,
53
- );
54
- } catch {
55
- process.stdout.write("Claude\n");
56
- }
57
- });
@@ -1,223 +0,0 @@
1
- import { access, copyFile, mkdir, readFile, writeFile } from "node:fs/promises";
2
- import path from "node:path";
3
- import { constants } from "node:fs";
4
- import { fileURLToPath } from "node:url";
5
-
6
- const __filename = fileURLToPath(import.meta.url);
7
- const __dirname = path.dirname(__filename);
8
-
9
- interface ClaudeSettings {
10
- $schema?: string;
11
- attribution?: Record<string, unknown>;
12
- permissions?: {
13
- ask?: string[];
14
- deny?: string[];
15
- };
16
- hooks: {
17
- Notification?: HookMatcherEntry[];
18
- PreToolUse?: HookMatcherEntry[];
19
- [key: string]: unknown;
20
- };
21
- statusLine: {
22
- type?: string;
23
- command: string;
24
- };
25
- [key: string]: unknown;
26
- }
27
-
28
- interface CommandHook {
29
- type?: string;
30
- command: string;
31
- [key: string]: unknown;
32
- }
33
-
34
- interface HookMatcherEntry {
35
- matcher?: string;
36
- hooks: CommandHook[];
37
- [key: string]: unknown;
38
- }
39
-
40
- const isRecord = (value: unknown): value is Record<string, unknown> => typeof value === "object" && value !== null;
41
-
42
- const fileExists = async (filePath: string): Promise<boolean> => {
43
- try {
44
- await access(filePath, constants.F_OK);
45
- return true;
46
- } catch {
47
- return false;
48
- }
49
- };
50
-
51
- const isClaudeSettings = (value: unknown): value is ClaudeSettings => {
52
- if (!isRecord(value)) {
53
- return false;
54
- }
55
-
56
- const hooks = value.hooks;
57
- const statusLine = value.statusLine;
58
-
59
- if (!isRecord(hooks) || !isRecord(statusLine) || typeof statusLine.command !== "string") {
60
- return false;
61
- }
62
-
63
- const notification = hooks.Notification;
64
- if (notification !== undefined && !Array.isArray(notification)) {
65
- return false;
66
- }
67
-
68
- const preToolUse = hooks.PreToolUse;
69
- return preToolUse === undefined || Array.isArray(preToolUse);
70
- };
71
-
72
- const readClaudeSettings = async (templatePath: string): Promise<ClaudeSettings> => {
73
- const templateRaw = await readFile(templatePath, "utf8");
74
- const parsed: unknown = JSON.parse(templateRaw);
75
-
76
- if (!isClaudeSettings(parsed)) {
77
- throw new Error("Claude settings template has an invalid shape.");
78
- }
79
-
80
- return parsed;
81
- };
82
-
83
- const mergeStringArrays = (left: string[] = [], right: string[] = []): string[] =>
84
- Array.from(new Set([...left, ...right]));
85
-
86
- const upsertHookMatcherEntry = (
87
- entries: HookMatcherEntry[] | undefined,
88
- matcher: string,
89
- command: string,
90
- ): HookMatcherEntry[] => {
91
- const nextEntries = [...(entries ?? [])];
92
- const existingIndex = nextEntries.findIndex((entry) => (entry.matcher ?? "") === matcher);
93
- const hook: CommandHook = { type: "command", command };
94
-
95
- if (existingIndex === -1) {
96
- nextEntries.push({ matcher, hooks: [hook] });
97
- return nextEntries;
98
- }
99
-
100
- const existingEntry = nextEntries[existingIndex];
101
- nextEntries[existingIndex] = { ...existingEntry, hooks: [hook] };
102
- return nextEntries;
103
- };
104
-
105
- const mergeClaudeSettings = (
106
- existingSettings: ClaudeSettings,
107
- baseSettings: ClaudeSettings,
108
- packagePath: string,
109
- ): ClaudeSettings => {
110
- const notificationCommand = `${packagePath}/hooks/notification.sh`;
111
- const protectFilesCommand = `${packagePath}/hooks/protect-files.sh`;
112
- const statusLineCommand = `node ${packagePath}/hooks/status-line/index.js`;
113
-
114
- return {
115
- ...existingSettings,
116
- $schema: baseSettings.$schema ?? existingSettings.$schema,
117
- attribution: { ...(baseSettings.attribution ?? {}), ...(existingSettings.attribution ?? {}) },
118
- permissions: {
119
- ...(existingSettings.permissions ?? {}),
120
- ...(baseSettings.permissions ?? {}),
121
- ask: mergeStringArrays(baseSettings.permissions?.ask, existingSettings.permissions?.ask),
122
- deny: mergeStringArrays(baseSettings.permissions?.deny, existingSettings.permissions?.deny),
123
- },
124
- hooks: {
125
- ...existingSettings.hooks,
126
- Notification: upsertHookMatcherEntry(existingSettings.hooks.Notification, "", notificationCommand),
127
- PreToolUse: upsertHookMatcherEntry(existingSettings.hooks.PreToolUse, "Edit|Write", protectFilesCommand),
128
- },
129
- statusLine: {
130
- ...existingSettings.statusLine,
131
- ...baseSettings.statusLine,
132
- type: "command",
133
- command: statusLineCommand,
134
- },
135
- };
136
- };
137
-
138
- export const renderClaude = async (targetDir: string, force: boolean, packageRoot: string): Promise<string[]> => {
139
- const templatePath = path.join(packageRoot, "claude/settings.base.json");
140
- const baseSettings = await readClaudeSettings(templatePath);
141
- const packagePath = "./node_modules/pasika/claude";
142
- const notificationEntries = upsertHookMatcherEntry(
143
- baseSettings.hooks.Notification,
144
- "",
145
- `${packagePath}/hooks/notification.sh`,
146
- );
147
- const preToolUseEntries = upsertHookMatcherEntry(
148
- baseSettings.hooks.PreToolUse,
149
- "Edit|Write",
150
- `${packagePath}/hooks/protect-files.sh`,
151
- );
152
- const settings: ClaudeSettings = {
153
- ...baseSettings,
154
- hooks: {
155
- ...baseSettings.hooks,
156
- Notification: notificationEntries,
157
- PreToolUse: preToolUseEntries,
158
- },
159
- statusLine: {
160
- ...baseSettings.statusLine,
161
- type: "command",
162
- command: `node ${packagePath}/hooks/status-line/index.js`,
163
- },
164
- };
165
-
166
- const outputDir = path.join(targetDir, ".claude");
167
- const outputPath = path.join(outputDir, "settings.json");
168
- const hooksOutputDir = path.join(outputDir, "hooks");
169
-
170
- await mkdir(outputDir, { recursive: true });
171
- await mkdir(hooksOutputDir, { recursive: true });
172
-
173
- const finalSettings =
174
- !force && (await fileExists(outputPath))
175
- ? mergeClaudeSettings(await readClaudeSettings(outputPath), settings, packagePath)
176
- : settings;
177
-
178
- await writeFile(outputPath, `${JSON.stringify(finalSettings, null, 2)}\n`, "utf8");
179
-
180
- const outputs = [outputPath];
181
- const hookDocFiles = ["AGENTS.md", "CLAUDE.md"] as const;
182
-
183
- for (const fileName of hookDocFiles) {
184
- const sourcePath = path.join(packageRoot, "claude/hooks", fileName);
185
- if (!(await fileExists(sourcePath))) {
186
- continue;
187
- }
188
-
189
- const destinationPath = path.join(hooksOutputDir, fileName);
190
- await copyFile(sourcePath, destinationPath);
191
- outputs.push(destinationPath);
192
- }
193
-
194
- return outputs;
195
- };
196
-
197
- const isDirectRun = process.argv[1] ? path.resolve(process.argv[1]) === __filename : false;
198
-
199
- if (isDirectRun) {
200
- const args = process.argv.slice(2);
201
- const getArgValue = (flag: string): string | undefined => {
202
- const index = args.indexOf(flag);
203
- if (index === -1) {
204
- return undefined;
205
- }
206
-
207
- return args[index + 1];
208
- };
209
-
210
- const targetDir = path.resolve(process.cwd(), getArgValue("--target-dir") ?? ".");
211
- const force = args.includes("--force");
212
- const packageRoot = path.resolve(__dirname, "../..");
213
-
214
- try {
215
- const outputs = await renderClaude(targetDir, force, packageRoot);
216
- for (const output of outputs) {
217
- process.stdout.write(`Wrote ${output}\n`);
218
- }
219
- } catch (error) {
220
- process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
221
- process.exit(1);
222
- }
223
- }
@@ -1,38 +0,0 @@
1
- {
2
- "$schema": "https://json.schemastore.org/claude-code-settings.json",
3
- "attribution": {
4
- "commit": "",
5
- "pr": ""
6
- },
7
- "permissions": {
8
- "ask": ["Bash(git commit:*)", "Bash(git push:*)"]
9
- },
10
- "hooks": {
11
- "Notification": [
12
- {
13
- "matcher": "",
14
- "hooks": [
15
- {
16
- "type": "command",
17
- "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/notification.sh"
18
- }
19
- ]
20
- }
21
- ],
22
- "PreToolUse": [
23
- {
24
- "matcher": "Edit|Write",
25
- "hooks": [
26
- {
27
- "type": "command",
28
- "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/protect-files.sh"
29
- }
30
- ]
31
- }
32
- ]
33
- },
34
- "statusLine": {
35
- "type": "command",
36
- "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/status-line/index.js"
37
- }
38
- }