@ghship/cli 0.0.0-stage → 1.0.0
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 +108 -2
- package/bin/darwin-amd64/ghship +0 -0
- package/bin/darwin-arm64/ghship +0 -0
- package/bin/linux-amd64/ghship +0 -0
- package/bin/linux-arm64/ghship +0 -0
- package/bin/windows-amd64/ghship.exe +0 -0
- package/bin/windows-arm64/ghship.exe +0 -0
- package/checksums.json +8 -0
- package/package.json +23 -4
- package/run.cjs +128 -0
package/README.md
CHANGED
|
@@ -1,3 +1,109 @@
|
|
|
1
|
-
#
|
|
1
|
+
# GHShip npm distribution
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Go CLI and home AI skill plus per-project integration. Package includes native
|
|
4
|
+
binaries for macOS/Linux/Windows × amd64/arm64, with no postinstall downloads.
|
|
5
|
+
|
|
6
|
+
After publication: `npx @ghship/cli@latest install` installs the home skill, same-version
|
|
7
|
+
persistent CLI, then enters project initialization. `--user-only` stops after user
|
|
8
|
+
installation. Project workflows need Git and a gh with native Issue relationships.
|
|
9
|
+
`ghship doctor` provides official tool installation links when missing.
|
|
10
|
+
|
|
11
|
+
Update/uninstall via external `npx @ghship/cli@latest update|uninstall`. Project lifecycle:
|
|
12
|
+
`ghship project install|status|update|uninstall`; custom `.ghship/skill.md` is preserved.
|
|
13
|
+
Users: `ghship user add|update|delete|list`; list validates tokens and reports actual
|
|
14
|
+
expiry when GitHub returns it, otherwise unknown. Tokens never belong in projects.
|
|
15
|
+
|
|
16
|
+
For a downloaded npm tarball, use:
|
|
17
|
+
`npm exec --package /absolute/ghship.tgz -- ghship install --package-source /absolute/ghship.tgz`.
|
|
18
|
+
Add `--user-only` to install shared tools without initializing a project.
|
|
19
|
+
Registry commands require the selected version to be published.
|
|
20
|
+
|
|
21
|
+
Detailed Chinese tutorial and AI skill: https://github.com/ghship/cli
|
|
22
|
+
|
|
23
|
+
## License notices
|
|
24
|
+
|
|
25
|
+
GHShip is distributed under the MIT License.
|
|
26
|
+
|
|
27
|
+
MIT License
|
|
28
|
+
|
|
29
|
+
Copyright (c) 2026 GHShip contributors
|
|
30
|
+
|
|
31
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
32
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
33
|
+
in the Software without restriction, including without limitation the rights
|
|
34
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
35
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
36
|
+
furnished to do so, subject to the following conditions:
|
|
37
|
+
|
|
38
|
+
The above copyright notice and this permission notice shall be included in all
|
|
39
|
+
copies or substantial portions of the Software.
|
|
40
|
+
|
|
41
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
42
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
43
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
44
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
45
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
46
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
47
|
+
SOFTWARE.
|
|
48
|
+
|
|
49
|
+
The bundled Go binary includes golang.org/x/sys and golang.org/x/term,
|
|
50
|
+
which share the following BSD 3-Clause license:
|
|
51
|
+
|
|
52
|
+
Copyright 2009 The Go Authors.
|
|
53
|
+
|
|
54
|
+
Redistribution and use in source and binary forms, with or without
|
|
55
|
+
modification, are permitted provided that the following conditions are
|
|
56
|
+
met:
|
|
57
|
+
|
|
58
|
+
* Redistributions of source code must retain the above copyright
|
|
59
|
+
notice, this list of conditions and the following disclaimer.
|
|
60
|
+
* Redistributions in binary form must reproduce the above
|
|
61
|
+
copyright notice, this list of conditions and the following disclaimer
|
|
62
|
+
in the documentation and/or other materials provided with the
|
|
63
|
+
distribution.
|
|
64
|
+
* Neither the name of Google LLC nor the names of its
|
|
65
|
+
contributors may be used to endorse or promote products derived from
|
|
66
|
+
this software without specific prior written permission.
|
|
67
|
+
|
|
68
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
69
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
70
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
71
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
72
|
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
73
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
74
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
75
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
76
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
77
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
78
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
79
|
+
|
|
80
|
+
The bundled binaries include the Go runtime and standard library,
|
|
81
|
+
distributed under the following BSD 3-Clause license:
|
|
82
|
+
|
|
83
|
+
Copyright (c) 2009 The Go Authors. All rights reserved.
|
|
84
|
+
|
|
85
|
+
Redistribution and use in source and binary forms, with or without
|
|
86
|
+
modification, are permitted provided that the following conditions are
|
|
87
|
+
met:
|
|
88
|
+
|
|
89
|
+
* Redistributions of source code must retain the above copyright
|
|
90
|
+
notice, this list of conditions and the following disclaimer.
|
|
91
|
+
* Redistributions in binary form must reproduce the above
|
|
92
|
+
copyright notice, this list of conditions and the following disclaimer
|
|
93
|
+
in the documentation and/or other materials provided with the
|
|
94
|
+
distribution.
|
|
95
|
+
* Neither the name of Google Inc. nor the names of its
|
|
96
|
+
contributors may be used to endorse or promote products derived from
|
|
97
|
+
this software without specific prior written permission.
|
|
98
|
+
|
|
99
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
100
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
101
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
102
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
103
|
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
104
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
105
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
106
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
107
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
108
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
109
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/checksums.json
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bin/darwin-amd64/ghship": "f6c0f2c362d2a8631a4797976b775b918e14e4073414442abe7a6130adf125c5",
|
|
3
|
+
"bin/darwin-arm64/ghship": "6dd13e6d4b114308945119919728b50e2d97340f08d1405b9ddc58306d4fbfbb",
|
|
4
|
+
"bin/linux-amd64/ghship": "738329d127602e603562aada7daa270e5114f4e1715d14d5f7281f2ab79d03ea",
|
|
5
|
+
"bin/linux-arm64/ghship": "082b7c6945e6cfd9242a894d7ffb93771cd74fceddd6699a895889e747d5fff6",
|
|
6
|
+
"bin/windows-amd64/ghship.exe": "81c84b93a067b756de38bb2670d9b128801bdbf5ec081f296ea74de147f16621",
|
|
7
|
+
"bin/windows-arm64/ghship.exe": "7ddcae142e6d00e8706b5b29e447c6f83d0cb2bd650d99811ba01456f1776bc7"
|
|
8
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ghship/cli",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Go CLI and AI skill for native GitHub delivery pipelines",
|
|
5
|
+
"bin": {
|
|
6
|
+
"ghship": "run.cjs"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"run.cjs",
|
|
10
|
+
"bin",
|
|
11
|
+
"README.md",
|
|
12
|
+
"checksums.json"
|
|
13
|
+
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/ghship/cli.git"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"test": "node --test test.cjs"
|
|
23
|
+
},
|
|
24
|
+
"license": "MIT"
|
|
25
|
+
}
|
package/run.cjs
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const path = require('node:path');
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const os = require('node:os');
|
|
5
|
+
const crypto = require('node:crypto');
|
|
6
|
+
const { spawn, spawnSync } = require('node:child_process');
|
|
7
|
+
function binaryPath(platform = process.platform, arch = process.arch) {
|
|
8
|
+
const os = {darwin:'darwin', linux:'linux', win32:'windows'}[platform];
|
|
9
|
+
const cpu = {x64:'amd64', arm64:'arm64'}[arch];
|
|
10
|
+
if (!os || !cpu) throw new Error(`Unsupported platform: ${platform}/${arch}`);
|
|
11
|
+
return path.join(__dirname, 'bin', `${os}-${cpu}`, os === 'windows' ? 'ghship.exe' : 'ghship');
|
|
12
|
+
}
|
|
13
|
+
function npmCommand() {
|
|
14
|
+
if (process.env.npm_execpath && fs.existsSync(process.env.npm_execpath)) return [process.execPath, [process.env.npm_execpath]];
|
|
15
|
+
const suffixes = process.platform === 'win32' ? ['npm.cmd'] : ['npm'];
|
|
16
|
+
for (const dir of (process.env.PATH || '').split(path.delimiter)) for (const name of suffixes) {
|
|
17
|
+
const candidate = path.join(dir, name); if (!fs.existsSync(candidate)) continue;
|
|
18
|
+
const real = fs.realpathSync(candidate);
|
|
19
|
+
if (process.platform !== 'win32') return [process.execPath, [real]];
|
|
20
|
+
const cli = path.join(dir, 'node_modules', 'npm', 'bin', 'npm-cli.js');
|
|
21
|
+
if (fs.existsSync(cli)) return [process.execPath, [cli]];
|
|
22
|
+
}
|
|
23
|
+
throw new Error('npm is unavailable. Install Node/npm: https://nodejs.org/en/download');
|
|
24
|
+
}
|
|
25
|
+
function npm(args, capture = false) {
|
|
26
|
+
const [command, base] = npmCommand();
|
|
27
|
+
const result = spawnSync(command, [...base, ...args], {stdio:capture ? ['ignore','pipe','pipe'] : 'inherit', encoding:'utf8'});
|
|
28
|
+
const absentList = args[0] === 'list' && result.status !== 0 && (() => {
|
|
29
|
+
try { const value=JSON.parse(result.stdout); return value.error?.code === 'ENOENT' || (result.status === 1 && !value.error); } catch (_) { return false; }
|
|
30
|
+
})();
|
|
31
|
+
if (result.error || (result.status !== 0 && !absentList)) throw new Error(`npm ${args[0]} failed; retry the same fixed-version command`);
|
|
32
|
+
return capture ? (absentList ? '{"dependencies":{}}' : result.stdout) : '';
|
|
33
|
+
}
|
|
34
|
+
function go(executable,args,capture=false,interactive=false) {
|
|
35
|
+
const result=spawnSync(executable,args,{stdio:capture?[interactive?'inherit':'ignore','pipe',interactive?'inherit':'pipe']:'inherit',encoding:'utf8'});
|
|
36
|
+
if(result.error) throw new Error('Cannot start the packaged Go CLI');
|
|
37
|
+
if (capture && result.status !== 0 && result.stderr) process.stderr.write(result.stderr);
|
|
38
|
+
return {code:result.status===null?1:result.status,stdout:result.stdout};
|
|
39
|
+
}
|
|
40
|
+
function hashFile(file) { return crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex'); }
|
|
41
|
+
function noLinks(file) {
|
|
42
|
+
for(let current=file;;current=path.dirname(current)) {
|
|
43
|
+
try {if(fs.lstatSync(current).isSymbolicLink())throw new Error('Installation path contains a symlink; preserved');}
|
|
44
|
+
catch(error){if(error.code!=='ENOENT')throw error;}
|
|
45
|
+
if(path.dirname(current)===current)break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function packageReceipt(root) {
|
|
49
|
+
const base=process.platform==='win32' ? path.join(process.env.APPDATA||path.join(os.homedir(),'AppData','Roaming'),'ghship') : path.join(os.homedir(),'.config','ghship');
|
|
50
|
+
return path.join(base,`npm-${crypto.createHash('sha256').update(root).digest('hex')}.json`);
|
|
51
|
+
}
|
|
52
|
+
function observePackage(root,meta,existing,replacingVerifiedReceipt=false) {
|
|
53
|
+
const directory=path.join(root,meta.name); noLinks(directory);
|
|
54
|
+
const metadata=JSON.parse(fs.readFileSync(path.join(directory,'package.json'),'utf8'));
|
|
55
|
+
if(metadata.name!==meta.name||metadata.version!==existing.version||metadata.bin?.ghship!=='run.cjs')throw new Error('Unrecognized global package; preserved');
|
|
56
|
+
const relative=path.relative(__dirname,binaryPath());
|
|
57
|
+
const observed={root,name:meta.name,version:metadata.version,launcher:hashFile(path.join(directory,'run.cjs')),binary:hashFile(path.join(directory,relative))};
|
|
58
|
+
const current=observed.version===meta.version&&observed.launcher===hashFile(path.join(__dirname,'run.cjs'))&&observed.binary===hashFile(binaryPath());
|
|
59
|
+
const receipt=packageReceipt(root);noLinks(receipt);
|
|
60
|
+
let recorded=null;try{recorded=JSON.parse(fs.readFileSync(receipt,'utf8'));}catch(error){if(error.code!=='ENOENT')throw new Error('Invalid installation receipt; preserved');}
|
|
61
|
+
if(recorded&&!replacingVerifiedReceipt&&!Object.keys(observed).every(key=>recorded[key]===observed[key]))throw new Error('Installation receipt does not match the package; preserved');
|
|
62
|
+
const managed=current||(recorded&&Object.keys(observed).every(key=>recorded[key]===observed[key]));
|
|
63
|
+
if(!managed)throw new Error('Global package ownership/content is unverified; preserved. Inspect npm list -g @ghship/cli before changing it');
|
|
64
|
+
return {observed,current};
|
|
65
|
+
}
|
|
66
|
+
function saveReceipt(root,observed) {
|
|
67
|
+
const file=packageReceipt(root);noLinks(file);fs.mkdirSync(path.dirname(file),{recursive:true,mode:0o700});
|
|
68
|
+
const stage=`${file}.${process.pid}.tmp`;const descriptor=fs.openSync(stage,'wx',0o600);
|
|
69
|
+
try{fs.writeFileSync(descriptor,JSON.stringify(observed));fs.fsyncSync(descriptor);}finally{fs.closeSync(descriptor);}
|
|
70
|
+
try{fs.renameSync(stage,file);}finally{if(fs.existsSync(stage))fs.unlinkSync(stage);}
|
|
71
|
+
}
|
|
72
|
+
function lifecycle(executable,args) {
|
|
73
|
+
const action=args[0], meta=require('./package.json'); let source=`${meta.name}@${meta.version}`;
|
|
74
|
+
const passed=args.slice(1); const sourceIndex=passed.indexOf('--package-source');
|
|
75
|
+
if(sourceIndex>=0) {if(!passed[sourceIndex+1])throw new Error('--package-source requires a local tarball');source=path.resolve(passed[sourceIndex+1]);passed.splice(sourceIndex,2);
|
|
76
|
+
const packed=JSON.parse(npm(['pack',source,'--dry-run','--json'],true));if(packed.length!==1||packed[0].name!==meta.name||packed[0].version!==meta.version)throw new Error('Local package source must match this exact package and version');
|
|
77
|
+
}
|
|
78
|
+
const lifecycleArgs=[];const initArgs=[];let userOnly=false;
|
|
79
|
+
const initValues=new Set(['--project','--repo','--author','--reviewer','--admin','--acceptance-pr']);
|
|
80
|
+
const initSwitches=new Set(['--configure','--non-interactive','--confirm-auto-close']);
|
|
81
|
+
for(let i=0;i<passed.length;i++){
|
|
82
|
+
const arg=passed[i];
|
|
83
|
+
if(arg==='--user-only'){userOnly=true;continue;}
|
|
84
|
+
if(arg==='--dir'){if(!passed[i+1])throw new Error('--dir requires a path');lifecycleArgs.push(arg,passed[++i]);}
|
|
85
|
+
else if(arg==='--json'||initSwitches.has(arg)){initArgs.push(arg);}
|
|
86
|
+
else if(initValues.has(arg)){if(!passed[i+1])throw new Error(`${arg} requires a value`);initArgs.push(arg,passed[++i]);}
|
|
87
|
+
else throw new Error(`Unknown lifecycle option: ${arg}; use ghship help install`);
|
|
88
|
+
}
|
|
89
|
+
const preflight=go(executable,[action,'--skill-only','--check',...lifecycleArgs,'--json'],true);if(preflight.code!==0)return preflight.code;
|
|
90
|
+
const installed=JSON.parse(npm(['list','-g',meta.name,'--depth=0','--json'],true));
|
|
91
|
+
const existing=installed.dependencies && installed.dependencies[meta.name];
|
|
92
|
+
const root=path.resolve(npm(['root','-g'],true).trim());
|
|
93
|
+
const receipt=packageReceipt(root);noLinks(receipt);
|
|
94
|
+
if(!existing&&action!=='uninstall'&&fs.existsSync(receipt))throw new Error('Installation receipt exists without its package; preserved');
|
|
95
|
+
if(existing && (existing.invalid||existing.extraneous))throw new Error('Global package ownership is inconsistent; inspect npm list -g @ghship/cli');
|
|
96
|
+
const observation=existing ? observePackage(root,meta,existing) : null;
|
|
97
|
+
if(action==='uninstall') {
|
|
98
|
+
const removal=go(executable,['uninstall','--skill-only',...lifecycleArgs,'--json'],true);if(removal.code!==0)return removal.code;
|
|
99
|
+
if(existing)npm(['uninstall','-g',meta.name],true);
|
|
100
|
+
const receipt=packageReceipt(root);noLinks(receipt);if(existing&&fs.existsSync(receipt))fs.unlinkSync(receipt);
|
|
101
|
+
console.log(JSON.stringify({userInstalled:false,projectConfigurationsPreserved:true,credentialsPreserved:true}));return 0;
|
|
102
|
+
}
|
|
103
|
+
const skill=go(executable,['install','--skill-only',...lifecycleArgs,'--json'],true);if(skill.code!==0)return skill.code;
|
|
104
|
+
try{if(!observation||!observation.current)npm(['install','-g',source],true);}catch(error){console.error(`Skill is ${meta.version}; CLI installation incomplete. Retry npx ${meta.name}@${meta.version} ${action}`);throw error;}
|
|
105
|
+
const verified=JSON.parse(npm(['list','-g',meta.name,'--depth=0','--json'],true));
|
|
106
|
+
if(!verified.dependencies||verified.dependencies[meta.name]?.version!==meta.version)throw new Error('Installed CLI version does not match skill; installation incomplete');
|
|
107
|
+
const persisted=observePackage(root,meta,verified.dependencies[meta.name],!!observation);if(!persisted.current)throw new Error('Persistent CLI content does not match this package');
|
|
108
|
+
const runtimeVersion=go(path.join(root,meta.name,path.relative(__dirname,executable)),['version'],true);
|
|
109
|
+
if(runtimeVersion.code!==0||runtimeVersion.stdout.trim()!==meta.version)throw new Error('Persistent CLI cannot run the expected version');
|
|
110
|
+
saveReceipt(root,persisted.observed);
|
|
111
|
+
if(action==='update'||userOnly){console.log(JSON.stringify({userInstalled:true,version:meta.version,projectInitialized:false}));return 0;}
|
|
112
|
+
const init=go(executable,['init',...initArgs,'--json'],true,true);
|
|
113
|
+
let result;try{result=JSON.parse(init.stdout);}catch(_){result={ready:false,missing:['Initialization failed before producing a result'],next:['ghship init --json']};}
|
|
114
|
+
result.userInstalled=true;result.version=meta.version;console.log(JSON.stringify(result));return init.code;
|
|
115
|
+
}
|
|
116
|
+
module.exports = {binaryPath};
|
|
117
|
+
if(require.main===module) {
|
|
118
|
+
try {
|
|
119
|
+
const executable=binaryPath();if(!fs.existsSync(executable))throw new Error('Package missing Go binary; reinstall the package');
|
|
120
|
+
const args=process.argv.slice(2);const action=args[0];
|
|
121
|
+
if(['install','update','uninstall'].includes(action)&&!args.includes('--standalone')&&!args.includes('--skill-only')&&!args.includes('--help')){
|
|
122
|
+
if(action!=='install'&&process.env.npm_command!=='exec') {console.error(`Run npx @ghship/cli@latest ${action} from an external npm entry`);process.exitCode=4;}
|
|
123
|
+
else process.exitCode=lifecycle(executable,args);
|
|
124
|
+
} else {
|
|
125
|
+
const child=spawn(executable,args,{stdio:'inherit'});child.on('error',()=>{console.error('Cannot start Go CLI');process.exitCode=1});child.on('exit',(code,signal)=>{if(signal)process.kill(process.pid,signal);else process.exitCode=code===null?1:code});
|
|
126
|
+
}
|
|
127
|
+
}catch(error){console.error(error.message);process.exitCode=1;}
|
|
128
|
+
}
|