@ghship/cli 1.0.1 → 1.0.4
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 +10 -3
- package/checksums.json +6 -6
- package/package.json +9 -2
- package/run.cjs +42 -10
- 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/README.md
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
# GHShip npm distribution
|
|
2
2
|
|
|
3
|
-
Go CLI and home AI skill plus per-project integration.
|
|
4
|
-
|
|
3
|
+
Go CLI and home AI skill plus per-project integration. npm installs the native
|
|
4
|
+
binary package matching the Node.js operating system and architecture for
|
|
5
|
+
macOS/Linux/Windows × x64/arm64, with no postinstall downloads. Optional
|
|
6
|
+
dependencies must be enabled and the matching package must be available from the
|
|
7
|
+
configured registry. An emulated Node.js runtime selects its own architecture.
|
|
5
8
|
|
|
6
9
|
After publication: `npx @ghship/cli@latest install` installs the home skill, same-version
|
|
7
10
|
persistent CLI, then enters project initialization. `--user-only` stops after user
|
|
@@ -10,12 +13,16 @@ installation. Project workflows need Git and a gh with native Issue relationship
|
|
|
10
13
|
|
|
11
14
|
Update/uninstall via external `npx @ghship/cli@latest update|uninstall`. Project lifecycle:
|
|
12
15
|
`ghship project install|status|update|uninstall`; custom `.ghship/skill.md` is preserved.
|
|
16
|
+
Install and update also update a verified standalone installation in place, keeping its
|
|
17
|
+
channel and paths. To uninstall a standalone installation, use a separate downloaded
|
|
18
|
+
executable with `uninstall --standalone`.
|
|
13
19
|
Users: `ghship user add|update|delete|list`; list validates tokens and reports actual
|
|
14
20
|
expiry when GitHub returns it, otherwise unknown. Tokens never belong in projects.
|
|
15
21
|
|
|
16
22
|
For a downloaded npm tarball, use:
|
|
17
23
|
`npm exec --package /absolute/ghship.tgz -- ghship install --package-source /absolute/ghship.tgz`.
|
|
18
|
-
|
|
24
|
+
The configured registry must provide the same-version platform package. Add
|
|
25
|
+
`--user-only` to install shared tools without initializing a project.
|
|
19
26
|
Registry commands require the selected version to be published.
|
|
20
27
|
|
|
21
28
|
Detailed Chinese tutorial and AI skill: https://github.com/ghship/cli
|
package/checksums.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
2
|
+
"darwin-arm64": "bdce86aa2ebb4bca9ee4e149cce2b29d51557dfeee7f732b2dcd6d1458f125a6",
|
|
3
|
+
"darwin-x64": "c0b71ad5b0d9e338cb9836b8572e9caacbad1a710965df0af88665d68dc100da",
|
|
4
|
+
"linux-arm64": "b3607bc943a8b01a5e8a164a21026766442cd1a7fae14b2703afcfdd1afa97f3",
|
|
5
|
+
"linux-x64": "2ba3458d178f81abc11478fa92128e76fcc61567b9abc4a8d1931fcaa6363f02",
|
|
6
|
+
"win32-arm64": "68a9bb61d9f1ee7147f2bc7eacc2c377fd25f2016b4d911b818db3d8666e2f4c",
|
|
7
|
+
"win32-x64": "dc1d6ebf166634222f919668f1b7803c2bf1c2c6d6df2d460c95b7bb48f2d85d"
|
|
8
8
|
}
|
package/package.json
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ghship/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Go CLI and AI skill for native GitHub delivery pipelines",
|
|
5
5
|
"bin": {
|
|
6
6
|
"ghship": "run.cjs"
|
|
7
7
|
},
|
|
8
8
|
"files": [
|
|
9
9
|
"run.cjs",
|
|
10
|
-
"bin",
|
|
11
10
|
"README.md",
|
|
12
11
|
"checksums.json"
|
|
13
12
|
],
|
|
13
|
+
"optionalDependencies": {
|
|
14
|
+
"@ghship/cli-darwin-x64": "1.0.4",
|
|
15
|
+
"@ghship/cli-darwin-arm64": "1.0.4",
|
|
16
|
+
"@ghship/cli-linux-x64": "1.0.4",
|
|
17
|
+
"@ghship/cli-linux-arm64": "1.0.4",
|
|
18
|
+
"@ghship/cli-win32-x64": "1.0.4",
|
|
19
|
+
"@ghship/cli-win32-arm64": "1.0.4"
|
|
20
|
+
},
|
|
14
21
|
"engines": {
|
|
15
22
|
"node": ">=18"
|
|
16
23
|
},
|
package/run.cjs
CHANGED
|
@@ -4,11 +4,31 @@ const fs = require('node:fs');
|
|
|
4
4
|
const os = require('node:os');
|
|
5
5
|
const crypto = require('node:crypto');
|
|
6
6
|
const { spawn, spawnSync } = require('node:child_process');
|
|
7
|
-
function
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (
|
|
11
|
-
|
|
7
|
+
function singlePack(value,name) {
|
|
8
|
+
let record;
|
|
9
|
+
if(Array.isArray(value)) {if(value.length!==1)throw new Error('Unexpected npm pack result');record=value[0];}
|
|
10
|
+
else if(value&&typeof value==='object'&&Object.keys(value).length===1&&Object.hasOwn(value,name))record=value[name];
|
|
11
|
+
if(!record||typeof record!=='object'||record.name!==name||typeof record.version!=='string')throw new Error('Unexpected npm pack result');
|
|
12
|
+
return record;
|
|
13
|
+
}
|
|
14
|
+
function platformInfo(platform = process.platform, arch = process.arch) {
|
|
15
|
+
if (!['darwin','linux','win32'].includes(platform) || !['x64','arm64'].includes(arch)) throw new Error(`Unsupported platform: ${platform}/${arch}`);
|
|
16
|
+
return {target:`${platform}-${arch}`,name:`@ghship/cli-${platform}-${arch}`,binary:platform==='win32'?'ghship.exe':'ghship'};
|
|
17
|
+
}
|
|
18
|
+
function binaryPath(platform = process.platform, arch = process.arch, root = __dirname) {
|
|
19
|
+
const info=platformInfo(platform,arch);
|
|
20
|
+
const meta=JSON.parse(fs.readFileSync(path.join(root,'package.json'),'utf8'));
|
|
21
|
+
let manifest;try {manifest=require.resolve(`${info.name}/package.json`,{paths:[root]});}
|
|
22
|
+
catch (_) {throw new Error(`Platform package ${info.name}@${meta.version} is missing; enable optional dependencies and reinstall @ghship/cli@${meta.version}`);}
|
|
23
|
+
const allowed=[path.join(root,'node_modules',info.name),path.join(path.dirname(path.dirname(root)),info.name)];
|
|
24
|
+
if(!allowed.some(dir=>path.resolve(path.dirname(manifest))===path.resolve(dir)))throw new Error('Platform package is outside the installation; preserved');
|
|
25
|
+
noLinks(manifest);
|
|
26
|
+
const platformMeta=JSON.parse(fs.readFileSync(manifest,'utf8'));
|
|
27
|
+
if(platformMeta.name!==info.name||platformMeta.version!==meta.version||!platformMeta.os?.includes(platform)||!platformMeta.cpu?.includes(arch))throw new Error('Platform package does not match CLI version or platform; preserved');
|
|
28
|
+
const executable=path.join(path.dirname(manifest),'bin',info.binary);noLinks(executable);
|
|
29
|
+
const checks=JSON.parse(fs.readFileSync(path.join(root,'checksums.json'),'utf8'));
|
|
30
|
+
if(!checks[info.target]||hashFile(executable)!==checks[info.target])throw new Error('Platform binary missing or checksum mismatch; preserved');
|
|
31
|
+
return executable;
|
|
12
32
|
}
|
|
13
33
|
function npmCommand() {
|
|
14
34
|
if (process.env.npm_execpath && fs.existsSync(process.env.npm_execpath)) return [process.execPath, [process.env.npm_execpath]];
|
|
@@ -53,8 +73,10 @@ function observePackage(root,meta,existing,replacingVerifiedReceipt=false) {
|
|
|
53
73
|
const directory=path.join(root,meta.name); noLinks(directory);
|
|
54
74
|
const metadata=JSON.parse(fs.readFileSync(path.join(directory,'package.json'),'utf8'));
|
|
55
75
|
if(metadata.name!==meta.name||metadata.version!==existing.version||metadata.bin?.ghship!=='run.cjs')throw new Error('Unrecognized global package; preserved');
|
|
56
|
-
const
|
|
57
|
-
const
|
|
76
|
+
const info=platformInfo();const legacyOS={darwin:'darwin',linux:'linux',win32:'windows'}[process.platform];const legacyArch={x64:'amd64',arm64:'arm64'}[process.arch];
|
|
77
|
+
const legacy=path.join(directory,'bin',`${legacyOS}-${legacyArch}`,info.binary);
|
|
78
|
+
const installedBinary=fs.existsSync(legacy)?legacy:binaryPath(process.platform,process.arch,directory);noLinks(installedBinary);
|
|
79
|
+
const observed={root,name:meta.name,version:metadata.version,launcher:hashFile(path.join(directory,'run.cjs')),binary:hashFile(installedBinary)};
|
|
58
80
|
const current=observed.version===meta.version&&observed.launcher===hashFile(path.join(__dirname,'run.cjs'))&&observed.binary===hashFile(binaryPath());
|
|
59
81
|
const receipt=packageReceipt(root);noLinks(receipt);
|
|
60
82
|
let recorded=null;try{recorded=JSON.parse(fs.readFileSync(receipt,'utf8'));}catch(error){if(error.code!=='ENOENT')throw new Error('Invalid installation receipt; preserved');}
|
|
@@ -73,7 +95,7 @@ function lifecycle(executable,args) {
|
|
|
73
95
|
const action=args[0], meta=require('./package.json'); let source=`${meta.name}@${meta.version}`;
|
|
74
96
|
const passed=args.slice(1); const sourceIndex=passed.indexOf('--package-source');
|
|
75
97
|
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.
|
|
98
|
+
const packed=singlePack(JSON.parse(npm(['pack',source,'--dry-run','--json'],true)),meta.name);if(packed.version!==meta.version)throw new Error('Local package source must match this exact package and version');
|
|
77
99
|
}
|
|
78
100
|
const lifecycleArgs=[];const initArgs=[];let userOnly=false;
|
|
79
101
|
const initValues=new Set(['--project','--repo','--author','--reviewer','--admin','--acceptance-pr']);
|
|
@@ -87,8 +109,18 @@ function lifecycle(executable,args) {
|
|
|
87
109
|
else throw new Error(`Unknown lifecycle option: ${arg}; use ghship help install`);
|
|
88
110
|
}
|
|
89
111
|
const preflight=go(executable,[action,'--skill-only','--check',...lifecycleArgs,'--json'],true);if(preflight.code!==0)return preflight.code;
|
|
112
|
+
const state=JSON.parse(preflight.stdout);
|
|
90
113
|
const installed=JSON.parse(npm(['list','-g',meta.name,'--depth=0','--json'],true));
|
|
91
114
|
const existing=installed.dependencies && installed.dependencies[meta.name];
|
|
115
|
+
if(state.standalone) {
|
|
116
|
+
if(action==='uninstall')throw new Error('Standalone installation exists; uninstall with a separate downloaded executable and --standalone');
|
|
117
|
+
if(existing)throw new Error('Standalone and npm installations both exist; inspect both before updating');
|
|
118
|
+
const args=[action,'--standalone',...lifecycleArgs,...(userOnly?['--user-only']:[]),...initArgs.filter(arg=>arg!=='--json'),'--json'];
|
|
119
|
+
const result=go(executable,args,true,action==='install'&&!userOnly);
|
|
120
|
+
if(action==='install'&&!userOnly) {if(result.stdout)process.stdout.write(result.stdout);return result.code;}
|
|
121
|
+
if(result.code!==0)return result.code;
|
|
122
|
+
console.log(JSON.stringify({userInstalled:true,version:meta.version,projectInitialized:false}));return 0;
|
|
123
|
+
}
|
|
92
124
|
const root=path.resolve(npm(['root','-g'],true).trim());
|
|
93
125
|
const receipt=packageReceipt(root);noLinks(receipt);
|
|
94
126
|
if(!existing&&action!=='uninstall'&&fs.existsSync(receipt))throw new Error('Installation receipt exists without its package; preserved');
|
|
@@ -105,7 +137,7 @@ function lifecycle(executable,args) {
|
|
|
105
137
|
const verified=JSON.parse(npm(['list','-g',meta.name,'--depth=0','--json'],true));
|
|
106
138
|
if(!verified.dependencies||verified.dependencies[meta.name]?.version!==meta.version)throw new Error('Installed CLI version does not match skill; installation incomplete');
|
|
107
139
|
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
|
|
140
|
+
const runtimeVersion=go(binaryPath(process.platform,process.arch,path.join(root,meta.name)),['version'],true);
|
|
109
141
|
if(runtimeVersion.code!==0||runtimeVersion.stdout.trim()!==meta.version)throw new Error('Persistent CLI cannot run the expected version');
|
|
110
142
|
saveReceipt(root,persisted.observed);
|
|
111
143
|
if(action==='update'||userOnly){console.log(JSON.stringify({userInstalled:true,version:meta.version,projectInitialized:false}));return 0;}
|
|
@@ -113,7 +145,7 @@ function lifecycle(executable,args) {
|
|
|
113
145
|
let result;try{result=JSON.parse(init.stdout);}catch(_){result={ready:false,missing:['Initialization failed before producing a result'],next:['ghship init --json']};}
|
|
114
146
|
result.userInstalled=true;result.version=meta.version;console.log(JSON.stringify(result));return init.code;
|
|
115
147
|
}
|
|
116
|
-
module.exports = {binaryPath};
|
|
148
|
+
module.exports = {binaryPath,platformInfo,singlePack};
|
|
117
149
|
if(require.main===module) {
|
|
118
150
|
try {
|
|
119
151
|
const executable=binaryPath();if(!fs.existsSync(executable))throw new Error('Package missing Go binary; reinstall the package');
|
package/bin/darwin-amd64/ghship
DELETED
|
Binary file
|
package/bin/darwin-arm64/ghship
DELETED
|
Binary file
|
package/bin/linux-amd64/ghship
DELETED
|
Binary file
|
package/bin/linux-arm64/ghship
DELETED
|
Binary file
|
|
Binary file
|
|
Binary file
|