@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/README.md +29 -0
- package/bin/ascii.js +1 -2
- package/bin/ghosttown.js +5 -842
- package/bin/ght.js +13 -0
- package/bin/gt.js +13 -0
- package/package.json +7 -2
- package/scripts/build-wasm.sh +56 -0
- package/scripts/cli-publish.js +228 -0
- package/scripts/postinstall.js +113 -0
- package/src/cli.js +944 -0
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.
|
|
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();
|