riciplay 1.9.0 → 1.9.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 +13 -1
- package/package.json +3 -3
- package/scripts/postinstall.js +84 -23
package/README.md
CHANGED
|
@@ -29,6 +29,18 @@ riciplay chat # start an agent session
|
|
|
29
29
|
|
|
30
30
|
## The npm wrapper
|
|
31
31
|
|
|
32
|
-
`bin/riciplay`
|
|
32
|
+
`bin/riciplay` resolves the pip-installed console script via `PATH` and falls back to invoking `riciplay_cli.main:app` through `python3`. It explicitly excludes its own path as a candidate, so an npm global install (which symlinks this wrapper onto `PATH`) can never re-exec itself.
|
|
33
|
+
|
|
34
|
+
`scripts/postinstall.js` pip-installs `riciplay-cli` **pinned to this launcher's exact version** (`riciplay-cli==<package.json version>`), and compares the *installed* version rather than merely checking that the module imports — so an out-of-date install is upgraded instead of being silently kept. It degrades to a printed manual command when it can't (no network, `--ignore-scripts`, managed Python).
|
|
35
|
+
|
|
36
|
+
### The two versions are locked together
|
|
37
|
+
|
|
38
|
+
The launcher and the Python package must be released at the same version, because postinstall pins the pair. That used to be an unenforced convention and it drifted (npm `1.8.95` against PyPI `1.8.96`). Three things now enforce it:
|
|
39
|
+
|
|
40
|
+
- `npm test` / `npm publish` run `scripts/check-version-sync.js` — `prepublishOnly` **refuses to publish** a mismatched pair
|
|
41
|
+
- `pytest tests/test_version_sync.py` fails the suite on drift, catching it at PR time
|
|
42
|
+
- `python scripts/bump_version.py <version>` moves both files together, so the correct action is also the easy one (`--check` to verify, `--show` to inspect)
|
|
43
|
+
|
|
44
|
+
Release order: **PyPI first, then npm** — the pinned postinstall needs the matching version to already exist on PyPI.
|
|
33
45
|
|
|
34
46
|
Repository: [Zaidux/Riciplay](https://github.com/Zaidux/Riciplay)
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "riciplay",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.1",
|
|
4
4
|
"description": "AI-powered bug bounty reconnaissance and penetration testing agent \u2014 browser, proxy interception, recon, and exploit workflows",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"riciplay": "./bin/riciplay"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"test": "
|
|
11
|
-
"prepublishOnly": "
|
|
10
|
+
"test": "node scripts/check-version-sync.js",
|
|
11
|
+
"prepublishOnly": "node scripts/check-version-sync.js || (echo 'Refusing to publish: npm and PyPI versions disagree.' && exit 1)",
|
|
12
12
|
"postinstall": "node scripts/postinstall.js"
|
|
13
13
|
},
|
|
14
14
|
"repository": {
|
package/scripts/postinstall.js
CHANGED
|
@@ -1,40 +1,101 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// Riciplay npm postinstall — installs the Python package from PyPI.
|
|
2
|
+
// Riciplay npm postinstall — installs the matching Python package from PyPI.
|
|
3
3
|
//
|
|
4
|
-
// This npm package is a launcher; the implementation is the Python
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
4
|
+
// This npm package is a launcher; the implementation is the Python package
|
|
5
|
+
// `riciplay-cli` (PyPI). The two versions are meant to be identical, and this
|
|
6
|
+
// script enforces that:
|
|
7
|
+
//
|
|
8
|
+
// * it installs the EXACT version matching this npm release
|
|
9
|
+
// (`riciplay-cli==<package.json version>`), never just "latest", so a
|
|
10
|
+
// launcher can never end up driving a different implementation than the
|
|
11
|
+
// one it was released with;
|
|
12
|
+
// * it compares the INSTALLED version, not merely whether the module
|
|
13
|
+
// imports. The previous check was `python -c "import riciplay_cli"`, which
|
|
14
|
+
// passed for any old version already present — so a fresh npm install
|
|
15
|
+
// silently kept a stale CLI and reported "already importable".
|
|
16
|
+
//
|
|
17
|
+
// Failures are warnings, not errors: the user may be installing with
|
|
18
|
+
// --ignore-scripts, without network, or managing Python manually — print the
|
|
19
|
+
// manual command instead of failing the install.
|
|
9
20
|
|
|
10
21
|
const { execSync, spawnSync } = require('child_process');
|
|
11
22
|
const os = require('os');
|
|
23
|
+
const path = require('path');
|
|
12
24
|
|
|
13
|
-
|
|
25
|
+
const npmVersion = require(path.join(__dirname, '..', 'package.json')).version;
|
|
14
26
|
|
|
15
27
|
const isWin = os.platform() === 'win32';
|
|
16
28
|
const python = isWin ? 'python' : 'python3';
|
|
17
29
|
const pip = isWin ? 'pip' : 'pip3';
|
|
18
30
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
31
|
+
/**
|
|
32
|
+
* The version of `riciplay_cli` importable right now, or null if it is not
|
|
33
|
+
* installed / not importable.
|
|
34
|
+
*
|
|
35
|
+
* Read via `riciplay_cli.__version__`, which falls back to parsing
|
|
36
|
+
* pyproject.toml when dist metadata is unavailable, so this works for both a
|
|
37
|
+
* pip install and a source checkout.
|
|
38
|
+
*/
|
|
39
|
+
function installedVersion(py = python, run = spawnSync) {
|
|
40
|
+
const r = run(py, ['-c', 'import riciplay_cli; print(riciplay_cli.__version__)'], {
|
|
41
|
+
encoding: 'utf8',
|
|
42
|
+
});
|
|
43
|
+
if (r.status !== 0 || !r.stdout) return null;
|
|
44
|
+
const v = String(r.stdout).trim();
|
|
45
|
+
return v && v !== '0.0.0' ? v : null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** True when the installed CLI is not the version this launcher ships with. */
|
|
49
|
+
function needsInstall(installed, target = npmVersion) {
|
|
50
|
+
return installed !== target;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The exact pip requirement pinning the Python package to this npm release. */
|
|
54
|
+
function pipSpec(target = npmVersion) {
|
|
55
|
+
return `riciplay-cli==${target}`;
|
|
22
56
|
}
|
|
23
57
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
58
|
+
function main() {
|
|
59
|
+
console.log('\n🕷️ Installing Riciplay (bug bounty AI agent)...\n');
|
|
60
|
+
|
|
61
|
+
let current = null;
|
|
62
|
+
try {
|
|
63
|
+
current = installedVersion();
|
|
64
|
+
} catch {
|
|
65
|
+
current = null; // treated as "not installed" below
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!needsInstall(current)) {
|
|
69
|
+
console.log(`✓ riciplay-cli ${npmVersion} already installed.`);
|
|
27
70
|
} else {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
71
|
+
if (current) {
|
|
72
|
+
console.log(
|
|
73
|
+
`Updating riciplay-cli ${current} → ${npmVersion} ` +
|
|
74
|
+
'(the launcher and the Python package are version-locked)...'
|
|
75
|
+
);
|
|
76
|
+
} else {
|
|
77
|
+
console.log(
|
|
78
|
+
`Installing riciplay-cli ${npmVersion} from PyPI ` +
|
|
79
|
+
'(this also pulls Chrome/mitmproxy deps)...'
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
execSync(`${pip} install --upgrade ${pipSpec()}`, { stdio: 'inherit' });
|
|
84
|
+
console.log(`✓ Installed riciplay-cli ${npmVersion}.`);
|
|
85
|
+
} catch (err) {
|
|
86
|
+
console.warn(
|
|
87
|
+
`\n⚠ Could not install the Python package automatically (${err.message}).\n` +
|
|
88
|
+
' Riciplay needs Python 3.10+. Install the matching version manually with:\n' +
|
|
89
|
+
` pip install ${pipSpec()}\n`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
31
92
|
}
|
|
32
|
-
|
|
33
|
-
console.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
);
|
|
93
|
+
|
|
94
|
+
console.log('\nUsage: riciplay chat # start an agent session\n');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (require.main === module) {
|
|
98
|
+
main();
|
|
38
99
|
}
|
|
39
100
|
|
|
40
|
-
|
|
101
|
+
module.exports = { npmVersion, installedVersion, needsInstall, pipSpec, main };
|