@stevezhou/sisu 0.3.13 → 0.3.15
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 +1 -1
- package/dist/tui.js +18 -12
- package/package.json +3 -2
- package/scripts/ensure-cli-path.js +107 -0
- package/scripts/postinstall.js +7 -0
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ sisu login
|
|
|
13
13
|
sisu
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
`npm install -g` is a small JS package.
|
|
16
|
+
Postinstall links `sisu` into `~/.local/bin` (Debian/login PATH) and prints an `export PATH=...` line if this shell still cannot see the command. `npm install -g` is a small JS package. It also fetches the stamped SiSu TUI pager for **this package version** into `~/.sisu/bin` when a prebuilt exists. GitHub Release tags ship `darwin-arm64`, `linux-x64`, and `linux-arm64`. `darwin-x64` is opt-in (`workflow_dispatch` with `platforms` containing `darwin-x64`) and often missing; platforms without a binary, or a missing GitHub Release asset, keep the Node TUI.
|
|
17
17
|
|
|
18
18
|
Requires Node.js 20 or newer. `npx sisu` works without a global install.
|
|
19
19
|
|
package/dist/tui.js
CHANGED
|
@@ -305,7 +305,9 @@ async function runTui(io, deps = {}) {
|
|
|
305
305
|
});
|
|
306
306
|
});
|
|
307
307
|
if (deps.spawnGrokPager || ((0, launch_1.findGrokBuildBinary)() && process.stdout.isTTY)) {
|
|
308
|
-
// Login handoff: pager exits 10 → host web login at most once → respawn
|
|
308
|
+
// Login handoff: pager exits 10 → host web login at most once → respawn
|
|
309
|
+
// grok-pager. Never fall through to the Node TUI while the grok binary ran.
|
|
310
|
+
let retriedWithSession = false;
|
|
309
311
|
while (true) {
|
|
310
312
|
const code = await spawnOnce();
|
|
311
313
|
if (code === null)
|
|
@@ -313,19 +315,23 @@ async function runTui(io, deps = {}) {
|
|
|
313
315
|
if (code !== exports.SISU_LOGIN_EXIT_CODE)
|
|
314
316
|
return code;
|
|
315
317
|
restoreInteractiveTerminal(io);
|
|
316
|
-
if (auth()
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
318
|
+
if (!auth() && !openedBrowserLogin) {
|
|
319
|
+
try {
|
|
320
|
+
const email = await startWebLogin((line) => io.write(`${line}\n`));
|
|
321
|
+
io.write(`logged in as ${email}\n`);
|
|
322
|
+
}
|
|
323
|
+
catch (error) {
|
|
324
|
+
io.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
325
|
+
io.write('login failed — run `sisu login`\n');
|
|
326
|
+
return 1;
|
|
327
|
+
}
|
|
328
|
+
continue;
|
|
323
329
|
}
|
|
324
|
-
|
|
325
|
-
io.write(
|
|
326
|
-
|
|
327
|
-
return 1;
|
|
330
|
+
if (retriedWithSession) {
|
|
331
|
+
io.write('sisu: grok pager still requesting login after a saved session.\n');
|
|
332
|
+
return exports.SISU_LOGIN_EXIT_CODE;
|
|
328
333
|
}
|
|
334
|
+
retriedWithSession = true;
|
|
329
335
|
}
|
|
330
336
|
}
|
|
331
337
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stevezhou/sisu",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.15",
|
|
4
4
|
"description": "SiSu CLI — 思溯 / SiSu · 思有所溯",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"homepage": "https://www.sisu.chat",
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"NOTICE",
|
|
27
27
|
"third_party/grok-build",
|
|
28
28
|
"scripts/postinstall.js",
|
|
29
|
-
"scripts/install-pager.js"
|
|
29
|
+
"scripts/install-pager.js",
|
|
30
|
+
"scripts/ensure-cli-path.js"
|
|
30
31
|
],
|
|
31
32
|
"publishConfig": {
|
|
32
33
|
"access": "public"
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/** After `npm i -g`, put `sisu` on a PATH users actually have.
|
|
3
|
+
* npm's global bin is often missing from Debian/login PATH.
|
|
4
|
+
*/
|
|
5
|
+
const fs = require('fs')
|
|
6
|
+
const os = require('os')
|
|
7
|
+
const path = require('path')
|
|
8
|
+
|
|
9
|
+
function pathDirs(pathEnv = process.env.PATH || '') {
|
|
10
|
+
return pathEnv.split(path.delimiter).filter(Boolean)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function pathContains(dir, pathEnv = process.env.PATH || '') {
|
|
14
|
+
const target = path.resolve(dir)
|
|
15
|
+
return pathDirs(pathEnv).some((entry) => {
|
|
16
|
+
try {
|
|
17
|
+
return path.resolve(entry) === target
|
|
18
|
+
} catch {
|
|
19
|
+
return false
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function globalSisuBin(options = {}) {
|
|
25
|
+
const name = options.platform === 'win32' ? 'sisu.cmd' : 'sisu'
|
|
26
|
+
const prefix = options.prefix || process.env.npm_config_prefix || ''
|
|
27
|
+
const fromPrefix = prefix
|
|
28
|
+
? (options.platform === 'win32' ? path.join(prefix, name) : path.join(prefix, 'bin', name))
|
|
29
|
+
: ''
|
|
30
|
+
const fromLayout = path.resolve(
|
|
31
|
+
options.packageRoot || path.join(__dirname, '..'),
|
|
32
|
+
'..',
|
|
33
|
+
'..',
|
|
34
|
+
options.platform === 'win32' ? name : path.join('bin', name),
|
|
35
|
+
)
|
|
36
|
+
const exists = options.exists || ((file) => fs.existsSync(file))
|
|
37
|
+
for (const candidate of [fromPrefix, fromLayout]) {
|
|
38
|
+
if (candidate && exists(candidate)) return candidate
|
|
39
|
+
}
|
|
40
|
+
return fromPrefix || fromLayout
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function userLocalBin(home = os.homedir()) {
|
|
44
|
+
return path.join(home, '.local', 'bin')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function ensureUserShim(target, options = {}) {
|
|
48
|
+
if ((options.platform || process.platform) === 'win32') return null
|
|
49
|
+
if (!target) return null
|
|
50
|
+
const dir = userLocalBin(options.home || os.homedir())
|
|
51
|
+
const dest = path.join(dir, 'sisu')
|
|
52
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o755 })
|
|
53
|
+
try {
|
|
54
|
+
if (fs.lstatSync(dest)) fs.unlinkSync(dest)
|
|
55
|
+
} catch {
|
|
56
|
+
// missing
|
|
57
|
+
}
|
|
58
|
+
fs.symlinkSync(path.resolve(target), dest)
|
|
59
|
+
try {
|
|
60
|
+
fs.chmodSync(dest, 0o755)
|
|
61
|
+
} catch {
|
|
62
|
+
// symlink mode follows the target on most POSIX
|
|
63
|
+
}
|
|
64
|
+
return dest
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function pathHint(npmBin, localBin, pathEnv = process.env.PATH || '') {
|
|
68
|
+
const dirs = []
|
|
69
|
+
if (localBin && !pathContains(localBin, pathEnv)) dirs.push(localBin)
|
|
70
|
+
if (npmBin && !pathContains(npmBin, pathEnv)) dirs.push(npmBin)
|
|
71
|
+
if (!dirs.length) return ''
|
|
72
|
+
return `export PATH="${dirs.join(':')}:$PATH" && hash -r`
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function installCliPath(options = {}) {
|
|
76
|
+
const writes = options.write || ((text) => process.stdout.write(text))
|
|
77
|
+
const platform = options.platform || process.platform
|
|
78
|
+
const bin = globalSisuBin(options)
|
|
79
|
+
const npmBinDir = bin ? path.dirname(bin) : ''
|
|
80
|
+
let shim = null
|
|
81
|
+
try {
|
|
82
|
+
shim = ensureUserShim(bin, options)
|
|
83
|
+
} catch (error) {
|
|
84
|
+
writes(`sisu: could not link ~/.local/bin/sisu (${error instanceof Error ? error.message : String(error)})\n`)
|
|
85
|
+
}
|
|
86
|
+
const localDir = shim ? path.dirname(shim) : userLocalBin(options.home)
|
|
87
|
+
const hint = pathHint(npmBinDir, localDir, options.pathEnv)
|
|
88
|
+
if (bin) writes(`sisu: command -> ${shim || bin}\n`)
|
|
89
|
+
if (hint) {
|
|
90
|
+
writes('sisu: if `sisu` is not found in this shell, run:\n')
|
|
91
|
+
writes(` ${hint}\n`)
|
|
92
|
+
}
|
|
93
|
+
return { bin, shim, hint }
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
module.exports = {
|
|
97
|
+
ensureUserShim,
|
|
98
|
+
globalSisuBin,
|
|
99
|
+
installCliPath,
|
|
100
|
+
pathContains,
|
|
101
|
+
pathHint,
|
|
102
|
+
userLocalBin,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (require.main === module) {
|
|
106
|
+
installCliPath()
|
|
107
|
+
}
|
package/scripts/postinstall.js
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
* Never fail `npm install` — Node TUI still works without the binary.
|
|
4
4
|
*/
|
|
5
5
|
const { installPager } = require('./install-pager')
|
|
6
|
+
const { installCliPath } = require('./ensure-cli-path')
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
installCliPath()
|
|
10
|
+
} catch (error) {
|
|
11
|
+
process.stdout.write(`sisu: path setup skipped (${error instanceof Error ? error.message : String(error)})\n`)
|
|
12
|
+
}
|
|
6
13
|
|
|
7
14
|
installPager().then(
|
|
8
15
|
(result) => {
|