@scheduler-systems/gal-cli 0.1.13-beta.2-alpha.pr72 → 0.1.13
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 +11 -33
- package/dist/index.cjs +265 -50
- package/package.json +8 -2
- package/scripts/postinstall.cjs +77 -3
- package/scripts/preuninstall.cjs +149 -0
package/package.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scheduler-systems/gal-cli",
|
|
3
|
-
"version": "0.1.13
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"description": "GAL CLI - Command-line tool for managing AI agent configurations across your organization",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"private": false,
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"registry": "https://registry.npmjs.org",
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
7
11
|
"type": "module",
|
|
8
12
|
"main": "./dist/index.cjs",
|
|
9
13
|
"bin": {
|
|
@@ -12,11 +16,13 @@
|
|
|
12
16
|
"files": [
|
|
13
17
|
"dist/index.cjs",
|
|
14
18
|
"scripts/postinstall.cjs",
|
|
19
|
+
"scripts/preuninstall.cjs",
|
|
15
20
|
"README.md",
|
|
16
21
|
"LICENSE"
|
|
17
22
|
],
|
|
18
23
|
"scripts": {
|
|
19
24
|
"postinstall": "node scripts/postinstall.cjs",
|
|
25
|
+
"preuninstall": "node scripts/preuninstall.cjs",
|
|
20
26
|
"dev": "tsx watch src/index.ts",
|
|
21
27
|
"build": "rm -rf dist && esbuild src/index.ts --bundle --platform=node --target=node18 --outfile=dist/index.cjs --format=cjs --define:__CLI_VERSION__=\\\"$(node -p \"require('./package.json').version\")\\\" --define:__DEFAULT_API_URL__=\\\"http://localhost:3000\\\" && chmod +x dist/index.cjs",
|
|
22
28
|
"build:publish": "rm -rf dist && esbuild src/index.ts --bundle --platform=node --target=node18 --minify --outfile=dist/index.cjs --format=cjs --define:__CLI_VERSION__=\\\"$(node -p \"require('./package.json').version\")\\\" --define:__DEFAULT_API_URL__=\\\"${DEFAULT_API_URL:-https://gal-api-s3pvf4isfa-uc.a.run.app}\\\" && sed -i '' '1s/^#!.*$//' dist/index.cjs && printf '%s\\n' '#!/usr/bin/env node' | cat - dist/index.cjs > dist/temp.cjs && mv dist/temp.cjs dist/index.cjs && chmod +x dist/index.cjs",
|
|
@@ -74,4 +80,4 @@
|
|
|
74
80
|
"typescript": "^5.7.2",
|
|
75
81
|
"vitest": "^1.0.0"
|
|
76
82
|
}
|
|
77
|
-
}
|
|
83
|
+
}
|
package/scripts/postinstall.cjs
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Automatically installs Claude Code integrations when GAL CLI is installed:
|
|
6
6
|
* 1. SessionStart hook → ~/.claude/hooks/gal-sync-reminder.js
|
|
7
7
|
* 2. Status line script → ~/.claude/status_lines/gal-sync-status.py
|
|
8
|
+
* 3. GAL CLI rules → ~/.claude/rules/gal-cli.md
|
|
8
9
|
*
|
|
9
10
|
* These are CLI-level configs (not org-specific).
|
|
10
11
|
* Org-specific configs are handled by `gal sync --pull`.
|
|
@@ -27,6 +28,31 @@ const CLI_VERSION = cliPackageJson.version;
|
|
|
27
28
|
// Version markers for idempotency
|
|
28
29
|
const HOOK_VERSION = '2.1.0'; // SessionStart version (2.1.0: Added telemetry tracking)
|
|
29
30
|
const STATUS_LINE_VERSION = '1.0.0';
|
|
31
|
+
const RULES_VERSION = '1.0.0';
|
|
32
|
+
|
|
33
|
+
// =============================================================================
|
|
34
|
+
// GAL CLI Rules Content
|
|
35
|
+
// =============================================================================
|
|
36
|
+
// This is injected into ~/.claude/rules/gal-cli.md
|
|
37
|
+
// Provides persistent GAL CLI awareness without running on every prompt
|
|
38
|
+
// =============================================================================
|
|
39
|
+
|
|
40
|
+
const GAL_CLI_RULES_CONTENT = `# GAL CLI
|
|
41
|
+
|
|
42
|
+
<!-- GAL_RULES_VERSION = "${RULES_VERSION}" -->
|
|
43
|
+
|
|
44
|
+
The \`gal\` CLI is available for managing org-approved AI agent configurations.
|
|
45
|
+
|
|
46
|
+
## Available Commands
|
|
47
|
+
- \`gal sync --pull\` - Download latest approved config from your organization
|
|
48
|
+
- \`gal auth login\` - Authenticate with GitHub
|
|
49
|
+
- \`gal --help\` - See all available commands
|
|
50
|
+
|
|
51
|
+
## Behavior Rules
|
|
52
|
+
- **Confirmation Required**: Always ask the user before running any \`gal\` command
|
|
53
|
+
- **Self-Discovery**: If unsure about syntax, run \`gal --help\` or \`gal <command> --help\` first
|
|
54
|
+
- **Sync Notifications**: When you see a GAL sync notification, ask: "Do you want me to sync gal now?"
|
|
55
|
+
`;
|
|
30
56
|
|
|
31
57
|
// =============================================================================
|
|
32
58
|
// SessionStart Hook Content
|
|
@@ -124,11 +150,16 @@ function isGalInstalled() {
|
|
|
124
150
|
|
|
125
151
|
function selfClean() {
|
|
126
152
|
const hookPath = __filename;
|
|
127
|
-
const
|
|
153
|
+
const claudeDir = path.join(os.homedir(), '.claude');
|
|
154
|
+
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
155
|
+
const rulesPath = path.join(claudeDir, 'rules', 'gal-cli.md');
|
|
128
156
|
|
|
129
157
|
// Remove hook file
|
|
130
158
|
try { fs.unlinkSync(hookPath); } catch {}
|
|
131
159
|
|
|
160
|
+
// Remove rules file
|
|
161
|
+
try { fs.unlinkSync(rulesPath); } catch {}
|
|
162
|
+
|
|
132
163
|
// Remove hook entries from settings.json
|
|
133
164
|
try {
|
|
134
165
|
if (fs.existsSync(settingsPath)) {
|
|
@@ -484,6 +515,48 @@ function installHook() {
|
|
|
484
515
|
}
|
|
485
516
|
}
|
|
486
517
|
|
|
518
|
+
/**
|
|
519
|
+
* Install GAL CLI rules to ~/.claude/rules/
|
|
520
|
+
*
|
|
521
|
+
* Key behaviors:
|
|
522
|
+
* - Idempotent: Checks version before writing
|
|
523
|
+
* - Provides persistent GAL CLI awareness
|
|
524
|
+
* - No longer runs on every prompt (unlike hooks)
|
|
525
|
+
*/
|
|
526
|
+
function installRules() {
|
|
527
|
+
const claudeDir = path.join(os.homedir(), '.claude');
|
|
528
|
+
const rulesDir = path.join(claudeDir, 'rules');
|
|
529
|
+
const rulesPath = path.join(rulesDir, 'gal-cli.md');
|
|
530
|
+
|
|
531
|
+
try {
|
|
532
|
+
// Create rules directory if needed
|
|
533
|
+
if (!fs.existsSync(rulesDir)) {
|
|
534
|
+
fs.mkdirSync(rulesDir, { recursive: true });
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// Check if rules file already exists with current version
|
|
538
|
+
let needsUpdate = true;
|
|
539
|
+
if (fs.existsSync(rulesPath)) {
|
|
540
|
+
const existingContent = fs.readFileSync(rulesPath, 'utf-8');
|
|
541
|
+
const versionMatch = existingContent.match(/GAL_RULES_VERSION = "([^"]+)"/);
|
|
542
|
+
if (versionMatch && versionMatch[1] === RULES_VERSION) {
|
|
543
|
+
needsUpdate = false;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// Write the rules file if needed
|
|
548
|
+
if (needsUpdate) {
|
|
549
|
+
fs.writeFileSync(rulesPath, GAL_CLI_RULES_CONTENT, 'utf-8');
|
|
550
|
+
console.log('✓ GAL CLI rules installed');
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
return true;
|
|
554
|
+
} catch (error) {
|
|
555
|
+
// Silent fail - rules are optional enhancement
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
487
560
|
/**
|
|
488
561
|
* Queue a telemetry event for the next CLI run (GAL-114)
|
|
489
562
|
* Since postinstall is CommonJS and telemetry module is ESM,
|
|
@@ -601,14 +674,15 @@ function installStatusLine() {
|
|
|
601
674
|
|
|
602
675
|
function main() {
|
|
603
676
|
const hookInstalled = installHook();
|
|
677
|
+
const rulesInstalled = installRules();
|
|
604
678
|
const statusLineInstalled = installStatusLine();
|
|
605
679
|
|
|
606
680
|
// Queue telemetry event (GAL-114)
|
|
607
681
|
queueTelemetryEvent();
|
|
608
682
|
|
|
609
|
-
if (hookInstalled || statusLineInstalled) {
|
|
683
|
+
if (hookInstalled || rulesInstalled || statusLineInstalled) {
|
|
610
684
|
console.log('');
|
|
611
|
-
console.log('Restart Claude Code for changes to take effect.');
|
|
685
|
+
console.log('Restart Claude Code/Cursor for changes to take effect.');
|
|
612
686
|
console.log('');
|
|
613
687
|
console.log('Next steps:');
|
|
614
688
|
console.log(' 1. gal auth login - Authenticate with GitHub');
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* GAL CLI Preuninstall Script
|
|
4
|
+
* Automatically cleans up GAL files when the CLI is uninstalled via npm
|
|
5
|
+
* This runs before the package is removed
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const os = require('os');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Remove GAL hook entries from settings.json without deleting the file
|
|
14
|
+
*/
|
|
15
|
+
function removeGalHookEntries(settingsPath) {
|
|
16
|
+
try {
|
|
17
|
+
if (!fs.existsSync(settingsPath)) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
22
|
+
|
|
23
|
+
if (!settings.hooks?.UserPromptSubmit) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Filter out GAL hooks
|
|
28
|
+
const originalLength = settings.hooks.UserPromptSubmit.length;
|
|
29
|
+
settings.hooks.UserPromptSubmit = settings.hooks.UserPromptSubmit.filter((entry) => {
|
|
30
|
+
if (!entry.hooks) return true;
|
|
31
|
+
// Keep entry only if it has non-GAL hooks
|
|
32
|
+
entry.hooks = entry.hooks.filter((hook) =>
|
|
33
|
+
!hook.command?.includes('gal-') && !hook.command?.includes('/gal/')
|
|
34
|
+
);
|
|
35
|
+
return entry.hooks.length > 0;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Remove empty hooks array
|
|
39
|
+
if (settings.hooks.UserPromptSubmit.length === 0) {
|
|
40
|
+
delete settings.hooks.UserPromptSubmit;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Remove empty hooks object
|
|
44
|
+
if (Object.keys(settings.hooks).length === 0) {
|
|
45
|
+
delete settings.hooks;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (settings.hooks?.UserPromptSubmit?.length !== originalLength) {
|
|
49
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return false;
|
|
54
|
+
} catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Clean up GAL-installed files from user's home directory
|
|
61
|
+
*/
|
|
62
|
+
function cleanupUserLevel() {
|
|
63
|
+
const claudeDir = path.join(os.homedir(), '.claude');
|
|
64
|
+
const hooksDir = path.join(claudeDir, 'hooks');
|
|
65
|
+
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
66
|
+
|
|
67
|
+
let removed = [];
|
|
68
|
+
|
|
69
|
+
// Remove GAL hook files
|
|
70
|
+
if (fs.existsSync(hooksDir)) {
|
|
71
|
+
try {
|
|
72
|
+
const files = fs.readdirSync(hooksDir);
|
|
73
|
+
for (const file of files) {
|
|
74
|
+
if (file.startsWith('gal-')) {
|
|
75
|
+
const hookPath = path.join(hooksDir, file);
|
|
76
|
+
try {
|
|
77
|
+
fs.unlinkSync(hookPath);
|
|
78
|
+
removed.push(hookPath);
|
|
79
|
+
} catch (err) {
|
|
80
|
+
// Silent fail
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
} catch (err) {
|
|
85
|
+
// Silent fail
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Remove GAL hook entries from settings.json
|
|
90
|
+
if (removeGalHookEntries(settingsPath)) {
|
|
91
|
+
removed.push(`${settingsPath} (GAL hooks removed)`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return removed;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Clean up GAL config from user's home directory
|
|
99
|
+
*/
|
|
100
|
+
function cleanupGalConfig() {
|
|
101
|
+
const galConfigDir = path.join(os.homedir(), '.gal');
|
|
102
|
+
|
|
103
|
+
if (fs.existsSync(galConfigDir)) {
|
|
104
|
+
try {
|
|
105
|
+
fs.rmSync(galConfigDir, { recursive: true, force: true });
|
|
106
|
+
return [galConfigDir];
|
|
107
|
+
} catch (err) {
|
|
108
|
+
// Silent fail
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Main cleanup function
|
|
118
|
+
*/
|
|
119
|
+
function cleanup() {
|
|
120
|
+
console.log('\n═══════════════════════════════════════════════════');
|
|
121
|
+
console.log(' GAL CLI Uninstall Cleanup');
|
|
122
|
+
console.log('═══════════════════════════════════════════════════\n');
|
|
123
|
+
|
|
124
|
+
const userLevelFiles = cleanupUserLevel();
|
|
125
|
+
const galConfigFiles = cleanupGalConfig();
|
|
126
|
+
const allRemoved = [...userLevelFiles, ...galConfigFiles];
|
|
127
|
+
|
|
128
|
+
if (allRemoved.length > 0) {
|
|
129
|
+
console.log('✓ Cleaned up GAL files:');
|
|
130
|
+
for (const file of allRemoved) {
|
|
131
|
+
console.log(` - ${file}`);
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
console.log('No GAL files found to clean up.');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
console.log('\n═══════════════════════════════════════════════════');
|
|
138
|
+
console.log(' GAL CLI has been uninstalled');
|
|
139
|
+
console.log('═══════════════════════════════════════════════════\n');
|
|
140
|
+
console.log('To reinstall: npm install -g @scheduler-systems/gal-cli\n');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Run cleanup
|
|
144
|
+
try {
|
|
145
|
+
cleanup();
|
|
146
|
+
} catch (error) {
|
|
147
|
+
// Silent fail - don't prevent uninstall
|
|
148
|
+
console.error('GAL cleanup encountered an error, but uninstall will proceed.');
|
|
149
|
+
}
|