gsd-pi 2.3.9 → 2.3.10
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gsd-pi",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.10",
|
|
4
4
|
"description": "GSD — Get Shit Done coding agent",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -44,7 +44,9 @@
|
|
|
44
44
|
"prepublishOnly": "npm run sync-pkg-version && npm run build"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
+
"@clack/prompts": "^1.1.0",
|
|
47
48
|
"@mariozechner/pi-coding-agent": "^0.57.1",
|
|
49
|
+
"picocolors": "^1.1.1",
|
|
48
50
|
"playwright": "^1.58.2"
|
|
49
51
|
},
|
|
50
52
|
"devDependencies": {
|
package/scripts/postinstall.js
CHANGED
|
@@ -1,18 +1,38 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
import { exec as execCb } from 'child_process'
|
|
3
4
|
import { createRequire } from 'module'
|
|
4
5
|
import os from 'os'
|
|
5
|
-
import { fileURLToPath } from 'url'
|
|
6
6
|
import { dirname, resolve } from 'path'
|
|
7
|
+
import { fileURLToPath } from 'url'
|
|
7
8
|
|
|
8
9
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
9
10
|
const require = createRequire(import.meta.url)
|
|
10
11
|
const pkg = require(resolve(__dirname, '..', 'package.json'))
|
|
12
|
+
const cwd = resolve(__dirname, '..')
|
|
13
|
+
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Async exec helper — captures stdout+stderr, never inherits to terminal
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
function run(cmd, options = {}) {
|
|
18
|
+
return new Promise((resolve) => {
|
|
19
|
+
execCb(cmd, { cwd, ...options }, (error, stdout, stderr) => {
|
|
20
|
+
resolve({ ok: !error, stdout, stderr, error })
|
|
21
|
+
})
|
|
22
|
+
})
|
|
23
|
+
}
|
|
11
24
|
|
|
12
|
-
//
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Redirect stdout → stderr so npm always shows postinstall output.
|
|
27
|
+
// npm ≥7 suppresses stdout from lifecycle scripts by default; stderr is
|
|
28
|
+
// always forwarded. Clack writes to process.stdout, so we reroute it.
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
process.stdout.write = process.stderr.write.bind(process.stderr)
|
|
31
|
+
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// ASCII banner — printed before clack UI for brand recognition
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
13
35
|
const cyan = '\x1b[36m'
|
|
14
|
-
const green = '\x1b[32m'
|
|
15
|
-
const yellow = '\x1b[33m'
|
|
16
36
|
const dim = '\x1b[2m'
|
|
17
37
|
const reset = '\x1b[0m'
|
|
18
38
|
|
|
@@ -27,58 +47,81 @@ const banner =
|
|
|
27
47
|
' ╚═════╝ ╚══════╝╚═════╝ ' +
|
|
28
48
|
reset + '\n' +
|
|
29
49
|
'\n' +
|
|
30
|
-
` Get Shit Done ${dim}v${pkg.version}${reset}\n`
|
|
31
|
-
` A standalone coding agent that plans, executes, and ships.\n` +
|
|
32
|
-
'\n' +
|
|
33
|
-
` ${green}✓${reset} Installed successfully\n` +
|
|
34
|
-
` ${dim}Run ${reset}${cyan}gsd${reset}${dim} to get started.${reset}\n`
|
|
35
|
-
|
|
36
|
-
function run(command, options = {}) {
|
|
37
|
-
return execSync(command, {
|
|
38
|
-
cwd: resolve(__dirname, '..'),
|
|
39
|
-
encoding: 'utf8',
|
|
40
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
41
|
-
...options,
|
|
42
|
-
})
|
|
43
|
-
}
|
|
50
|
+
` Get Shit Done ${dim}v${pkg.version}${reset}\n`
|
|
44
51
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Main — wrapped in async IIFE, with graceful fallback if clack fails
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
;(async () => {
|
|
56
|
+
process.stderr.write(banner)
|
|
48
57
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// Apply patches to upstream dependencies (non-fatal)
|
|
52
|
-
try {
|
|
53
|
-
const output = run('npx patch-package')
|
|
54
|
-
printCaptured(output)
|
|
55
|
-
process.stderr.write(`\n ${green}✓${reset} Patches applied\n`)
|
|
56
|
-
} catch (error) {
|
|
57
|
-
printCaptured(error.stdout)
|
|
58
|
-
printCaptured(error.stderr)
|
|
59
|
-
process.stderr.write(`\n ${yellow}⚠${reset} Failed to apply patches — run ${cyan}npx patch-package${reset} manually\n`)
|
|
60
|
-
}
|
|
58
|
+
let p, pc
|
|
61
59
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
60
|
+
try {
|
|
61
|
+
p = await import('@clack/prompts')
|
|
62
|
+
pc = (await import('picocolors')).default
|
|
63
|
+
} catch {
|
|
64
|
+
// Clack or picocolors unavailable — fall back to minimal output
|
|
65
|
+
process.stderr.write(` Run gsd to get started.\n\n`)
|
|
66
|
+
await run('npx patch-package')
|
|
67
|
+
await run('npx playwright install chromium')
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// --- Branded intro -------------------------------------------------------
|
|
72
|
+
p.intro('Setup')
|
|
73
|
+
|
|
74
|
+
const results = []
|
|
75
|
+
const s = p.spinner()
|
|
76
|
+
|
|
77
|
+
// --- Step 1: Apply patches -----------------------------------------------
|
|
78
|
+
s.start('Applying patches…')
|
|
79
|
+
const patchResult = await run('npx patch-package')
|
|
80
|
+
if (patchResult.ok) {
|
|
81
|
+
s.stop('Patches applied')
|
|
82
|
+
results.push({ label: 'Patches applied', ok: true })
|
|
79
83
|
} else {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
84
|
+
s.stop(pc.yellow('Patches — skipped (non-fatal)'))
|
|
85
|
+
results.push({
|
|
86
|
+
label: 'Patches skipped — run ' + pc.cyan('npx patch-package') + ' manually',
|
|
87
|
+
ok: false,
|
|
88
|
+
})
|
|
83
89
|
}
|
|
84
|
-
|
|
90
|
+
|
|
91
|
+
// --- Step 2: Playwright browser ------------------------------------------
|
|
92
|
+
// Avoid --with-deps: install scripts should not block on interactive sudo
|
|
93
|
+
// prompts. If Linux libs are missing, suggest the explicit follow-up.
|
|
94
|
+
s.start('Setting up browser tools…')
|
|
95
|
+
const pwResult = await run('npx playwright install chromium')
|
|
96
|
+
if (pwResult.ok) {
|
|
97
|
+
s.stop('Browser tools ready')
|
|
98
|
+
results.push({ label: 'Browser tools ready', ok: true })
|
|
99
|
+
} else {
|
|
100
|
+
const output = `${pwResult.stdout ?? ''}${pwResult.stderr ?? ''}`
|
|
101
|
+
if (os.platform() === 'linux' && output.includes('Host system is missing dependencies to run browsers.')) {
|
|
102
|
+
s.stop(pc.yellow('Browser downloaded, missing Linux deps'))
|
|
103
|
+
results.push({
|
|
104
|
+
label: 'Run ' + pc.cyan('sudo npx playwright install-deps chromium') + ' to finish setup',
|
|
105
|
+
ok: false,
|
|
106
|
+
})
|
|
107
|
+
} else {
|
|
108
|
+
s.stop(pc.yellow('Browser tools — skipped (non-fatal)'))
|
|
109
|
+
results.push({
|
|
110
|
+
label: 'Browser tools unavailable — run ' + pc.cyan('npx playwright install chromium'),
|
|
111
|
+
ok: false,
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// --- Summary note --------------------------------------------------------
|
|
117
|
+
const lines = results.map(
|
|
118
|
+
(r) => (r.ok ? pc.green('✓') : pc.yellow('⚠')) + ' ' + r.label
|
|
119
|
+
)
|
|
120
|
+
lines.push('')
|
|
121
|
+
lines.push('Run ' + pc.cyan('gsd') + ' to get started.')
|
|
122
|
+
|
|
123
|
+
p.note(lines.join('\n'), 'Installed')
|
|
124
|
+
|
|
125
|
+
// --- Outro ---------------------------------------------------------------
|
|
126
|
+
p.outro(pc.green('Done!'))
|
|
127
|
+
})()
|
|
@@ -48,6 +48,7 @@ import { createConnection } from "node:net";
|
|
|
48
48
|
import { randomUUID } from "node:crypto";
|
|
49
49
|
import { writeFileSync, readFileSync, existsSync, mkdirSync } from "node:fs";
|
|
50
50
|
import { join } from "node:path";
|
|
51
|
+
import { shortcutDesc } from "../shared/terminal.js";
|
|
51
52
|
import { createRequire } from "node:module";
|
|
52
53
|
|
|
53
54
|
// ── Windows VT Input Restoration ────────────────────────────────────────────
|
|
@@ -2356,7 +2357,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
2356
2357
|
// ── Ctrl+Alt+B shortcut ──────────────────────────────────────────────
|
|
2357
2358
|
|
|
2358
2359
|
pi.registerShortcut(Key.ctrlAlt("b"), {
|
|
2359
|
-
description: "Open background process manager",
|
|
2360
|
+
description: shortcutDesc("Open background process manager", "/bg"),
|
|
2360
2361
|
handler: async (ctx) => {
|
|
2361
2362
|
latestCtx = ctx;
|
|
2362
2363
|
await ctx.ui.custom<void>(
|
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
import { Key } from "@mariozechner/pi-tui";
|
|
48
48
|
import { join } from "node:path";
|
|
49
49
|
import { existsSync } from "node:fs";
|
|
50
|
+
import { shortcutDesc } from "../shared/terminal.js";
|
|
50
51
|
import { Text } from "@mariozechner/pi-tui";
|
|
51
52
|
|
|
52
53
|
// ── ASCII logo ────────────────────────────────────────────────────────────
|
|
@@ -184,10 +185,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
184
185
|
});
|
|
185
186
|
|
|
186
187
|
// ── Ctrl+Alt+G shortcut — GSD dashboard overlay ────────────────────────
|
|
187
|
-
// Requires Kitty keyboard protocol or modifyOtherKeys support.
|
|
188
|
-
// Terminals without support (macOS Terminal.app, JetBrains): use /gsd status instead.
|
|
189
188
|
pi.registerShortcut(Key.ctrlAlt("g"), {
|
|
190
|
-
description: "Open GSD dashboard
|
|
189
|
+
description: shortcutDesc("Open GSD dashboard", "/gsd status"),
|
|
191
190
|
handler: async (ctx) => {
|
|
192
191
|
// Only show if .gsd/ exists
|
|
193
192
|
if (!existsSync(join(process.cwd(), ".gsd"))) {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal capability detection for keyboard shortcut support.
|
|
3
|
+
*
|
|
4
|
+
* Ctrl+Alt shortcuts require the Kitty keyboard protocol or modifyOtherKeys.
|
|
5
|
+
* Terminals that lack this support silently swallow the key combos.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const UNSUPPORTED_TERMS = ["apple_terminal"];
|
|
9
|
+
|
|
10
|
+
export function supportsCtrlAltShortcuts(): boolean {
|
|
11
|
+
const term = (process.env.TERM_PROGRAM || "").toLowerCase();
|
|
12
|
+
const jetbrains = (process.env.TERMINAL_EMULATOR || "").toLowerCase().includes("jetbrains");
|
|
13
|
+
return !UNSUPPORTED_TERMS.some((t) => term.includes(t)) && !jetbrains;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Returns a shortcut description that includes a slash-command fallback hint
|
|
18
|
+
* when the current terminal likely can't fire Ctrl+Alt combos.
|
|
19
|
+
*/
|
|
20
|
+
export function shortcutDesc(base: string, fallbackCmd: string): string {
|
|
21
|
+
if (supportsCtrlAltShortcuts()) return base;
|
|
22
|
+
return `${base} — shortcut may not work in this terminal, use ${fallbackCmd}`;
|
|
23
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
import { shortcutDesc } from "../shared/terminal.js";
|
|
2
3
|
import type { AssistantMessage } from "@mariozechner/pi-ai";
|
|
3
4
|
import { isKeyRelease, Key, matchesKey, truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
|
|
4
5
|
import { spawn, execSync, type ChildProcess } from "node:child_process";
|
|
@@ -131,7 +132,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
131
132
|
});
|
|
132
133
|
|
|
133
134
|
pi.registerShortcut("ctrl+alt+v", {
|
|
134
|
-
description: "Toggle voice mode",
|
|
135
|
+
description: shortcutDesc("Toggle voice mode", "/voice"),
|
|
135
136
|
handler: async (ctx) => toggleVoice(ctx),
|
|
136
137
|
});
|
|
137
138
|
|