@qialike/cli 0.8.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 +44 -0
- package/bin/qialike.js +169 -0
- package/package.json +27 -0
package/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# @qialike/cli
|
|
2
|
+
|
|
3
|
+
Terminal client for **DeepSeek Harness** — a full-screen TUI over an agent session.
|
|
4
|
+
|
|
5
|
+
> **This npm channel ships the Windows binaries only.** Linux and macOS install with the shell
|
|
6
|
+
> installer, because a `curl … | bash` line is what those platforms already have:
|
|
7
|
+
>
|
|
8
|
+
> ```sh
|
|
9
|
+
> curl -fsSL https://qialike.com/install | bash
|
|
10
|
+
> ```
|
|
11
|
+
>
|
|
12
|
+
> Windows has no `bash`, which is why this package exists: it turns the manual
|
|
13
|
+
> "download a zip, unpack it into `%USERPROFILE%\.dsh\bin\`, edit your PATH, reopen the terminal"
|
|
14
|
+
> sequence into one command.
|
|
15
|
+
|
|
16
|
+
## Install (Windows)
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
npm i -g @qialike/cli
|
|
20
|
+
qialike --version
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**You do not choose an architecture.** The package declares one optional dependency per Windows
|
|
24
|
+
target — `@qialike/cli-win32-x64` and `@qialike/cli-win32-arm64` — each restricted with `os`/`cpu`,
|
|
25
|
+
so npm downloads only the payload that matches your machine (x64 or arm64), never both.
|
|
26
|
+
|
|
27
|
+
## When optional dependencies are skipped
|
|
28
|
+
|
|
29
|
+
`--omit=optional`, pnpm's defaults (which skip them), a mirror that dropped the platform package or
|
|
30
|
+
an interrupted install all leave the launcher without a binary. It then prints the exact command to
|
|
31
|
+
install the package for your architecture, for example:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
npm i -g @qialike/cli-win32-arm64@0.8.1
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Alternative installers
|
|
38
|
+
|
|
39
|
+
- Shell installer (Linux, macOS): `curl -fsSL https://qialike.com/install | bash`
|
|
40
|
+
- Release archives: <https://github.com/qialike/qialike/releases>
|
|
41
|
+
|
|
42
|
+
## License
|
|
43
|
+
|
|
44
|
+
MIT
|
package/bin/qialike.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* The `qialike` npm entry point: locate the Windows binary for this machine's
|
|
4
|
+
* architecture and hand over.
|
|
5
|
+
*
|
|
6
|
+
* WHY THIS FILE EXISTS. qialike is a compiled single-file executable, not a Node
|
|
7
|
+
* program, but npm is how Windows users install command-line tools — that
|
|
8
|
+
* platform has no `bash`, so the documented `curl … | bash` installer cannot run
|
|
9
|
+
* there and the README would have to walk people through downloading a zip,
|
|
10
|
+
* unpacking it by hand and editing their PATH. This wrapper is what turns that
|
|
11
|
+
* into `npm i -g @qialike/cli`.
|
|
12
|
+
*
|
|
13
|
+
* HOW THE ARCHITECTURE IS CHOSEN. The parent package declares one
|
|
14
|
+
* `optionalDependencies` entry per Windows architecture, and each of those
|
|
15
|
+
* packages declares the `os`/`cpu` pair it can run on. npm installs only the
|
|
16
|
+
* matching one, so an x64 machine downloads `@qialike/cli-win32-x64` and an
|
|
17
|
+
* arm64 machine downloads `@qialike/cli-win32-arm64` — no prompt, no detection
|
|
18
|
+
* code of our own, and never both payloads. That mechanism is load-bearing:
|
|
19
|
+
* this file is the part that reports when it breaks.
|
|
20
|
+
*
|
|
21
|
+
* WHY A WRAPPER AT ALL, rather than pointing `bin` straight at `qialike.exe`:
|
|
22
|
+
* npm's `cmd-shim` does support a shebang-less target ("assume it's something
|
|
23
|
+
* that'll be compiled … just call it directly"), but no widely used package
|
|
24
|
+
* relies on that path — esbuild, Biome, SWC and sharp all ship a small script
|
|
25
|
+
* in front of the binary, and the reason is the failure mode below: an
|
|
26
|
+
* `optionalDependency` can go missing (a mirrored registry that dropped it,
|
|
27
|
+
* `--omit=optional`, pnpm's defaults, a partial install), and only a wrapper can
|
|
28
|
+
* say so in words. A bare exec would fail with whatever the shell prints for a
|
|
29
|
+
* missing file.
|
|
30
|
+
*
|
|
31
|
+
* @module @qialike/cli/bin
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
'use strict'
|
|
35
|
+
|
|
36
|
+
const { spawnSync } = require('node:child_process')
|
|
37
|
+
const { existsSync, readFileSync } = require('node:fs')
|
|
38
|
+
const { dirname, join } = require('node:path')
|
|
39
|
+
|
|
40
|
+
/** The installer this npm channel stands in for, quoted in every message. */
|
|
41
|
+
const SHELL_INSTALLER = 'curl -fsSL https://qialike.com/install | bash'
|
|
42
|
+
const RELEASES = 'https://github.com/qialike/qialike/releases'
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Supported targets, and the binary name inside each platform package. The keys
|
|
46
|
+
* are `<process.platform>-<process.arch>`; the payload keeps its `.exe` because
|
|
47
|
+
* that is the file the build produces.
|
|
48
|
+
* @type {Record<string, string>}
|
|
49
|
+
*/
|
|
50
|
+
const TARGETS = {
|
|
51
|
+
'win32-x64': 'qialike.exe',
|
|
52
|
+
'win32-arm64': 'qialike.exe',
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const key = `${process.platform}-${process.arch}`
|
|
56
|
+
const binaryName = TARGETS[key]
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The version of the parent package, read from its own `package.json`. Used
|
|
60
|
+
* only to write an exact reinstall command: a bare `npm i -g <name>` could
|
|
61
|
+
* fetch a platform package that does not match the parent that resolved it.
|
|
62
|
+
* @returns {string} the semver string, or `latest` when it cannot be read.
|
|
63
|
+
*/
|
|
64
|
+
function ownVersion() {
|
|
65
|
+
try {
|
|
66
|
+
const manifest = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'))
|
|
67
|
+
return typeof manifest.version === 'string' && manifest.version.length > 0 ? manifest.version : 'latest'
|
|
68
|
+
} catch {
|
|
69
|
+
return 'latest'
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Report a fatal setup problem and stop, without pretending the binary ran.
|
|
75
|
+
* The exit code is always 1, never the binary's own — a wrapper failure is not
|
|
76
|
+
* a model turn failing.
|
|
77
|
+
* @param {string} message - the full, already-wrapped diagnostic.
|
|
78
|
+
* @returns {never} always exits.
|
|
79
|
+
*/
|
|
80
|
+
function fail(message) {
|
|
81
|
+
process.stderr.write(`${message}\n`)
|
|
82
|
+
process.exit(1)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// This channel carries Windows binaries only. Refuse loudly and name the route
|
|
86
|
+
// that does work for the platform we are on: silently doing nothing, or dying
|
|
87
|
+
// with a spawn error, would both be worse than one actionable sentence.
|
|
88
|
+
if (process.platform !== 'win32') {
|
|
89
|
+
fail(
|
|
90
|
+
`qialike: the npm channel ships Windows binaries only (this is ${key}).\n`
|
|
91
|
+
+ '\n'
|
|
92
|
+
+ ' Install it with the shell installer instead:\n'
|
|
93
|
+
+ ` ${SHELL_INSTALLER}\n`
|
|
94
|
+
+ '\n'
|
|
95
|
+
+ ' That is what Linux and macOS use; "npm i -g @qialike/cli" exists because\n'
|
|
96
|
+
+ ' Windows has no bash to run the installer with.\n',
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// x64 and arm64 are the only Windows targets the release publishes, and npm
|
|
101
|
+
// picks between them with `cpu`. Anything else (ia32, or a future arch) has no
|
|
102
|
+
// package to resolve.
|
|
103
|
+
if (!binaryName) {
|
|
104
|
+
fail(
|
|
105
|
+
`qialike: no npm build for ${key}.\n`
|
|
106
|
+
+ '\n'
|
|
107
|
+
+ ` Published Windows targets: ${Object.keys(TARGETS).join(', ')}\n`
|
|
108
|
+
+ '\n'
|
|
109
|
+
+ ' For anything else, build from source or fetch a release archive:\n'
|
|
110
|
+
+ ` ${RELEASES}\n`,
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const name = `@qialike/cli-${key}`
|
|
115
|
+
|
|
116
|
+
// Resolve the platform package through Node itself, so the same relative layout
|
|
117
|
+
// works for a global install (%APPDATA%\npm\node_modules\…), a local install and
|
|
118
|
+
// a workspace. `package.json` is used purely as a landmark: it keeps resolving
|
|
119
|
+
// even for a package that declares `exports`.
|
|
120
|
+
let manifestPath
|
|
121
|
+
try {
|
|
122
|
+
manifestPath = require.resolve(`${name}/package.json`)
|
|
123
|
+
} catch (error) {
|
|
124
|
+
const reason = error instanceof Error ? error.message : String(error)
|
|
125
|
+
const skipped = process.env.npm_config_optional === 'false'
|
|
126
|
+
fail(
|
|
127
|
+
`qialike: the ${name} package is missing, so there is no binary to run.\n`
|
|
128
|
+
+ '\n'
|
|
129
|
+
+ ' This is expected when npm was told to skip optional dependencies\n'
|
|
130
|
+
+ ` (${skipped ? 'npm_config_optional=false is set right now' : '--omit=optional / --no-optional'}),\n`
|
|
131
|
+
+ ' and possible with pnpm (which skips them by default), when a mirror\n'
|
|
132
|
+
+ ' dropped the package, or when the install was interrupted.\n'
|
|
133
|
+
+ '\n'
|
|
134
|
+
+ ' Install it explicitly:\n'
|
|
135
|
+
+ ` npm i -g ${name}@${ownVersion()}\n`
|
|
136
|
+
+ '\n'
|
|
137
|
+
+ ` (resolution error: ${reason})\n`,
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const exe = join(dirname(manifestPath), binaryName)
|
|
142
|
+
if (!existsSync(exe)) {
|
|
143
|
+
fail(
|
|
144
|
+
`qialike: ${name} is installed but carries no ${binaryName}.\n`
|
|
145
|
+
+ '\n'
|
|
146
|
+
+ ` Expected at: ${exe}\n`
|
|
147
|
+
+ ` Reinstall: npm i -g ${name}@${ownVersion()}\n`,
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Hand the terminal over: stdio is inherited, because the TUI owns raw mode,
|
|
152
|
+
// colour and resize. The child's exit code is what the caller sees.
|
|
153
|
+
const result = spawnSync(exe, process.argv.slice(2), { stdio: 'inherit' })
|
|
154
|
+
|
|
155
|
+
if (result.error) {
|
|
156
|
+
const reason = result.error instanceof Error ? result.error.message : String(result.error)
|
|
157
|
+
fail(
|
|
158
|
+
`qialike: failed to launch ${exe}\n`
|
|
159
|
+
+ '\n'
|
|
160
|
+
+ ` ${reason}\n`
|
|
161
|
+
+ '\n'
|
|
162
|
+
+ ' If the file exists and this persists the download may be incomplete —\n'
|
|
163
|
+
+ ` reinstall: npm i -g ${name}@${ownVersion()}\n`,
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// A signal-terminated child has `status === null`; count that as a failure
|
|
168
|
+
// rather than as success, because the turn did not complete.
|
|
169
|
+
process.exit(result.status === null ? 1 : result.status)
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@qialike/cli",
|
|
3
|
+
"version": "0.8.1",
|
|
4
|
+
"description": "Terminal client for DeepSeek Harness. Installs the Windows binary for your architecture (x64 or arm64) automatically.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/qialike/qialike.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://qialike.com",
|
|
11
|
+
"bin": {
|
|
12
|
+
"qialike": "bin/qialike.js"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"bin/qialike.js"
|
|
16
|
+
],
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=18"
|
|
19
|
+
},
|
|
20
|
+
"optionalDependencies": {
|
|
21
|
+
"@qialike/cli-win32-x64": "0.8.1",
|
|
22
|
+
"@qialike/cli-win32-arm64": "0.8.1"
|
|
23
|
+
},
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
}
|
|
27
|
+
}
|