@seflless/ghosttown 1.3.0 โ†’ 1.3.1

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/bin/ght.js ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * ght - Alternative alias for ghosttown CLI
5
+ *
6
+ * This is a thin wrapper that delegates to the shared CLI implementation.
7
+ * Primary command: ghosttown
8
+ * Short alias: gt
9
+ */
10
+
11
+ import { run } from '../src/cli.js';
12
+
13
+ run(process.argv);
package/bin/gt.js ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * gt - Short alias for ghosttown CLI
5
+ *
6
+ * This is a thin wrapper that delegates to the shared CLI implementation.
7
+ * Primary command: ghosttown
8
+ * Alternative alias: ght
9
+ */
10
+
11
+ import { run } from '../src/cli.js';
12
+
13
+ run(process.argv);
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@seflless/ghosttown",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "Web-based terminal emulator using Ghostty's VT100 parser via WebAssembly",
5
5
  "type": "module",
6
6
  "main": "./dist/ghostty-web.umd.cjs",
7
7
  "module": "./dist/ghostty-web.js",
8
8
  "types": "./dist/index.d.ts",
9
9
  "bin": {
10
- "ghosttown": "./bin/ghosttown.js"
10
+ "ghosttown": "./bin/ghosttown.js",
11
+ "gt": "./bin/gt.js",
12
+ "ght": "./bin/ght.js"
11
13
  },
12
14
  "exports": {
13
15
  ".": {
@@ -20,6 +22,8 @@
20
22
  "files": [
21
23
  "bin",
22
24
  "dist",
25
+ "scripts",
26
+ "src",
23
27
  "ghostty-vt.wasm",
24
28
  "README.md"
25
29
  ],
@@ -47,6 +51,7 @@
47
51
  "access": "public"
48
52
  },
49
53
  "scripts": {
54
+ "postinstall": "node ./scripts/postinstall.js",
50
55
  "dev": "vite --port 8000",
51
56
  "demo": "node demo/bin/demo.js",
52
57
  "demo:dev": "node demo/bin/demo.js --dev",
@@ -0,0 +1,56 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ echo "๐Ÿ”จ Building ghostty-vt.wasm..."
5
+
6
+ # Check for Zig
7
+ if ! command -v zig &> /dev/null; then
8
+ echo "โŒ Error: Zig not found"
9
+ echo ""
10
+ echo "Install Zig 0.15.2+:"
11
+ echo " macOS: brew install zig"
12
+ echo " Linux: https://ziglang.org/download/"
13
+ echo ""
14
+ exit 1
15
+ fi
16
+
17
+ ZIG_VERSION=$(zig version)
18
+ echo "โœ“ Found Zig $ZIG_VERSION"
19
+
20
+ # Initialize/update submodule
21
+ if [ ! -d "ghostty/.git" ]; then
22
+ echo "๐Ÿ“ฆ Initializing Ghostty submodule..."
23
+ git submodule update --init --recursive
24
+ else
25
+ echo "๐Ÿ“ฆ Ghostty submodule already initialized"
26
+ fi
27
+
28
+ # Apply patch
29
+ echo "๐Ÿ”ง Applying WASM API patch..."
30
+ cd ghostty
31
+ git apply --check ../patches/ghostty-wasm-api.patch || {
32
+ echo "โŒ Patch doesn't apply cleanly"
33
+ echo "Ghostty may have changed. Check patches/ghostty-wasm-api.patch"
34
+ exit 1
35
+ }
36
+ git apply ../patches/ghostty-wasm-api.patch
37
+
38
+ # Build WASM
39
+ echo "โš™๏ธ Building WASM (takes ~20 seconds)..."
40
+ zig build lib-vt -Dtarget=wasm32-freestanding -Doptimize=ReleaseSmall
41
+
42
+ # Copy to project root
43
+ cd ..
44
+ cp ghostty/zig-out/bin/ghostty-vt.wasm ./
45
+
46
+ # Revert patch to keep submodule clean
47
+ echo "๐Ÿงน Cleaning up..."
48
+ cd ghostty
49
+ git apply -R ../patches/ghostty-wasm-api.patch
50
+ # Remove new files created by the patch
51
+ rm -f include/ghostty/vt/terminal.h
52
+ rm -f src/terminal/c/terminal.zig
53
+ cd ..
54
+
55
+ SIZE=$(du -h ghostty-vt.wasm | cut -f1)
56
+ echo "โœ… Built ghostty-vt.wasm ($SIZE)"
@@ -0,0 +1,228 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * CLI Publish Script
5
+ *
6
+ * Full release workflow:
7
+ * 1. Build the project
8
+ * 2. Bump version (patch|minor|major)
9
+ * 3. Create branch francois/version-bump-<version>
10
+ * 4. Commit package.json version change
11
+ * 5. Publish to npm with --access public
12
+ * 6. Tag with v<version>
13
+ * 7. Push branch and tags
14
+ * 8. Create GitHub release (latest)
15
+ * 9. Create Draft PR
16
+ *
17
+ * Usage: bun cli:publish [patch|minor|major]
18
+ */
19
+
20
+ import { execSync } from 'child_process';
21
+ import fs from 'fs';
22
+ import path from 'path';
23
+ import { fileURLToPath } from 'url';
24
+
25
+ const __filename = fileURLToPath(import.meta.url);
26
+ const __dirname = path.dirname(__filename);
27
+ const rootDir = path.join(__dirname, '..');
28
+
29
+ function run(cmd, options = {}) {
30
+ console.log(`\n$ ${cmd}`);
31
+ try {
32
+ const result = execSync(cmd, {
33
+ cwd: rootDir,
34
+ stdio: options.silent ? 'pipe' : 'inherit',
35
+ encoding: 'utf-8',
36
+ ...options,
37
+ });
38
+ return result;
39
+ } catch (error) {
40
+ if (options.ignoreError) {
41
+ return null;
42
+ }
43
+ console.error(`\nCommand failed: ${cmd}`);
44
+ process.exit(1);
45
+ }
46
+ }
47
+
48
+ function getPackageJson() {
49
+ const packagePath = path.join(rootDir, 'package.json');
50
+ return JSON.parse(fs.readFileSync(packagePath, 'utf-8'));
51
+ }
52
+
53
+ function setPackageVersion(version) {
54
+ const packagePath = path.join(rootDir, 'package.json');
55
+ const pkg = getPackageJson();
56
+ pkg.version = version;
57
+ fs.writeFileSync(packagePath, JSON.stringify(pkg, null, 2) + '\n');
58
+ }
59
+
60
+ function bumpVersion(currentVersion, type) {
61
+ const [major, minor, patch] = currentVersion.split('.').map(Number);
62
+
63
+ switch (type) {
64
+ case 'major':
65
+ return `${major + 1}.0.0`;
66
+ case 'minor':
67
+ return `${major}.${minor + 1}.0`;
68
+ case 'patch':
69
+ return `${major}.${minor}.${patch + 1}`;
70
+ default:
71
+ console.error(`Invalid version type: ${type}. Use patch, minor, or major.`);
72
+ process.exit(1);
73
+ }
74
+ }
75
+
76
+ async function main() {
77
+ const versionType = process.argv[2] || 'patch';
78
+
79
+ if (!['patch', 'minor', 'major'].includes(versionType)) {
80
+ console.error('Usage: bun cli:publish [patch|minor|major]');
81
+ console.error(' patch - Bug fixes (1.0.0 -> 1.0.1)');
82
+ console.error(' minor - New features (1.0.0 -> 1.1.0)');
83
+ console.error(' major - Breaking changes (1.0.0 -> 2.0.0)');
84
+ process.exit(1);
85
+ }
86
+
87
+ // Check for uncommitted changes
88
+ const status = run('git status --porcelain', { silent: true });
89
+ if (status && status.trim()) {
90
+ console.error('\nError: You have uncommitted changes. Please commit or stash them first.');
91
+ process.exit(1);
92
+ }
93
+
94
+ // Check we're on main branch
95
+ const currentBranch = run('git branch --show-current', { silent: true }).trim();
96
+ if (currentBranch !== 'main') {
97
+ console.error(
98
+ `\nError: You must be on the main branch to publish. Currently on: ${currentBranch}`
99
+ );
100
+ process.exit(1);
101
+ }
102
+
103
+ // Pull latest
104
+ console.log('\n๐Ÿ“ฅ Pulling latest changes...');
105
+ run('git pull origin main');
106
+
107
+ // Get current version and calculate new version
108
+ const pkg = getPackageJson();
109
+ const currentVersion = pkg.version;
110
+ const newVersion = bumpVersion(currentVersion, versionType);
111
+ const branchName = `francois/version-bump-${newVersion}`;
112
+ const tagName = `v${newVersion}`;
113
+
114
+ console.log('\n๐Ÿ“‹ Release Plan:');
115
+ console.log(` Package: ${pkg.name}`);
116
+ console.log(` Current version: ${currentVersion}`);
117
+ console.log(` New version: ${newVersion} (${versionType})`);
118
+ console.log(` Branch: ${branchName}`);
119
+ console.log(` Tag: ${tagName}`);
120
+
121
+ // Step 1: Build
122
+ console.log('\n๐Ÿ”จ Building project...');
123
+ run('bun run build');
124
+
125
+ // Step 2: Bump version
126
+ console.log(`\n๐Ÿ“ Bumping version to ${newVersion}...`);
127
+ setPackageVersion(newVersion);
128
+
129
+ // Step 3: Create branch
130
+ console.log(`\n๐ŸŒฟ Creating branch ${branchName}...`);
131
+ run(`git checkout -b ${branchName}`);
132
+
133
+ // Step 4: Commit
134
+ console.log('\n๐Ÿ’พ Committing version bump...');
135
+ run('git add package.json');
136
+ run(`git commit -m "chore: bump version to ${newVersion}"`);
137
+
138
+ // Step 5: Publish to npm
139
+ console.log('\n๐Ÿ“ฆ Publishing to npm...');
140
+ run('npm publish --access public');
141
+
142
+ // Step 6: Tag
143
+ console.log(`\n๐Ÿท๏ธ Creating tag ${tagName}...`);
144
+ run(`git tag -a ${tagName} -m "Release ${tagName}"`);
145
+
146
+ // Step 7: Push branch and tags
147
+ console.log('\n๐Ÿš€ Pushing branch and tags...');
148
+ run(`git push -u origin ${branchName}`);
149
+ run('git push --tags');
150
+
151
+ // Step 8: Create GitHub release
152
+ console.log('\n๐Ÿ“ข Creating GitHub release...');
153
+ const releaseNotes = `## ${pkg.name} ${tagName}
154
+
155
+ ### Installation
156
+
157
+ \`\`\`bash
158
+ # Install globally
159
+ npm install -g ${pkg.name}
160
+
161
+ # Or use npx
162
+ npx ${pkg.name}
163
+ \`\`\`
164
+
165
+ ### Run
166
+
167
+ \`\`\`bash
168
+ ghosttown
169
+ \`\`\`
170
+
171
+ Opens http://localhost:8080 with a web-based terminal.
172
+ `;
173
+
174
+ // Write release notes to temp file to avoid shell escaping issues
175
+ const tempFile = path.join(rootDir, '.release-notes-temp.md');
176
+ fs.writeFileSync(tempFile, releaseNotes);
177
+
178
+ run(`gh release create ${tagName} --title "${tagName}" --notes-file "${tempFile}" --latest`);
179
+
180
+ // Clean up temp file
181
+ fs.unlinkSync(tempFile);
182
+
183
+ // Step 9: Create Draft PR
184
+ console.log('\n๐Ÿ“ Creating Draft PR...');
185
+ const prBody = `## Summary
186
+ - Bumps version from ${currentVersion} to ${newVersion}
187
+
188
+ ## Checklist
189
+ - [x] Built successfully
190
+ - [x] Published to npm
191
+ - [x] Tagged ${tagName}
192
+ - [x] GitHub release created
193
+
194
+ ## npm
195
+ https://www.npmjs.com/package/${pkg.name}
196
+ `;
197
+
198
+ const tempPrFile = path.join(rootDir, '.pr-body-temp.md');
199
+ fs.writeFileSync(tempPrFile, prBody);
200
+
201
+ const prUrl = run(
202
+ `gh pr create --draft --title "chore: bump version to ${newVersion}" --body-file "${tempPrFile}"`,
203
+ { silent: true }
204
+ );
205
+
206
+ // Clean up temp file
207
+ fs.unlinkSync(tempPrFile);
208
+
209
+ // Done!
210
+ console.log('\n' + 'โ•'.repeat(50));
211
+ console.log(' โœ… Release complete!');
212
+ console.log('โ•'.repeat(50));
213
+ console.log(`\n ๐Ÿ“ฆ npm: https://www.npmjs.com/package/${pkg.name}`);
214
+ console.log(` ๐Ÿท๏ธ Tag: ${tagName}`);
215
+ console.log(` ๐ŸŒฟ Branch: ${branchName}`);
216
+ if (prUrl) {
217
+ console.log(` ๐Ÿ“ PR: ${prUrl.trim()}`);
218
+ }
219
+ console.log('\n Next steps:');
220
+ console.log(' 1. Review and merge the PR');
221
+ console.log(' 2. Switch back to main: git checkout main && git pull');
222
+ console.log('');
223
+ }
224
+
225
+ main().catch((error) => {
226
+ console.error('Unexpected error:', error);
227
+ process.exit(1);
228
+ });
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * postinstall script for ghosttown
5
+ *
6
+ * Detects if an existing 'gt' command exists on PATH and prints a warning
7
+ * if it appears to belong to a different package.
8
+ *
9
+ * This script is non-blocking and will never fail the install.
10
+ * macOS/Linux only.
11
+ */
12
+
13
+ import { execSync } from 'child_process';
14
+
15
+ /**
16
+ * Check if we're on a supported platform (macOS or Linux)
17
+ */
18
+ function isSupportedPlatform() {
19
+ return process.platform === 'darwin' || process.platform === 'linux';
20
+ }
21
+
22
+ /**
23
+ * Resolve the path of a command using 'command -v'
24
+ * Returns null if the command is not found
25
+ */
26
+ function resolveCommand(cmd) {
27
+ try {
28
+ const result = execSync(`command -v ${cmd}`, {
29
+ encoding: 'utf8',
30
+ stdio: ['pipe', 'pipe', 'pipe'],
31
+ });
32
+ return result.trim();
33
+ } catch (err) {
34
+ // Command not found
35
+ return null;
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Check if a resolved path likely belongs to this package
41
+ */
42
+ function isOurCommand(resolvedPath) {
43
+ if (!resolvedPath) return false;
44
+
45
+ // Check if the path contains indicators that it's from our package
46
+ const indicators = [
47
+ 'node_modules/ghosttown',
48
+ 'node_modules/@seflless/ghosttown',
49
+ '/ghosttown/bin/gt',
50
+ ];
51
+
52
+ const normalizedPath = resolvedPath.toLowerCase();
53
+ return indicators.some((indicator) => normalizedPath.includes(indicator.toLowerCase()));
54
+ }
55
+
56
+ /**
57
+ * Print the conflict warning message
58
+ */
59
+ function printWarning(resolvedPath) {
60
+ const YELLOW = '\x1b[33m';
61
+ const CYAN = '\x1b[36m';
62
+ const DIM = '\x1b[2m';
63
+ const RESET = '\x1b[0m';
64
+
65
+ console.log('');
66
+ console.log(`${YELLOW}\u26a0\ufe0f ghosttown: 'gt' command conflict detected${RESET}`);
67
+ console.log('');
68
+ console.log(`An existing 'gt' command was found on your PATH:`);
69
+ console.log(` ${DIM}${resolvedPath}${RESET}`);
70
+ console.log('');
71
+ console.log(`ghosttown also provides a 'gt' alias. Depending on PATH order,`);
72
+ console.log(`one may shadow the other.`);
73
+ console.log('');
74
+ console.log(`${CYAN}Primary command:${RESET} ghosttown`);
75
+ console.log(`${CYAN}Alternative alias:${RESET} ght`);
76
+ console.log('');
77
+ console.log(`${DIM}Manual alias (optional):${RESET}`);
78
+ console.log(` ${DIM}alias gt=ghosttown${RESET}`);
79
+ console.log('');
80
+ }
81
+
82
+ /**
83
+ * Main function - detect gt conflicts
84
+ */
85
+ function main() {
86
+ try {
87
+ // Skip on unsupported platforms
88
+ if (!isSupportedPlatform()) {
89
+ return;
90
+ }
91
+
92
+ // Check if gt command exists
93
+ const gtPath = resolveCommand('gt');
94
+
95
+ // If gt doesn't exist, nothing to warn about
96
+ if (!gtPath) {
97
+ return;
98
+ }
99
+
100
+ // If it appears to be ours, no warning needed
101
+ if (isOurCommand(gtPath)) {
102
+ return;
103
+ }
104
+
105
+ // Print the warning
106
+ printWarning(gtPath);
107
+ } catch (err) {
108
+ // Swallow all errors - postinstall must never fail
109
+ // This is a best-effort warning only
110
+ }
111
+ }
112
+
113
+ main();