memento-mori-jester 0.1.3
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/LICENSE +21 -0
- package/README.md +313 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +789 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +33 -0
- package/dist/config.js +295 -0
- package/dist/config.js.map +1 -0
- package/dist/core.d.ts +7 -0
- package/dist/core.js +489 -0
- package/dist/core.js.map +1 -0
- package/dist/format.d.ts +2 -0
- package/dist/format.js +25 -0
- package/dist/format.js.map +1 -0
- package/dist/hooks.d.ts +26 -0
- package/dist/hooks.js +133 -0
- package/dist/hooks.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +87 -0
- package/dist/server.js.map +1 -0
- package/dist/types.d.ts +61 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/docs/AGENTS.md +145 -0
- package/docs/GITHUB_ACTIONS.md +116 -0
- package/docs/RELEASE.md +119 -0
- package/examples/github-action.yml +21 -0
- package/examples/jester.config.json +28 -0
- package/package.json +71 -0
- package/scripts/install.ps1 +30 -0
- package/scripts/install.sh +30 -0
- package/scripts/run-tests.mjs +32 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: Jester Review
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [main]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
jester:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
|
|
11
|
+
steps:
|
|
12
|
+
- name: Checkout
|
|
13
|
+
uses: actions/checkout@v4
|
|
14
|
+
with:
|
|
15
|
+
fetch-depth: 0
|
|
16
|
+
|
|
17
|
+
- name: Review pull request diff
|
|
18
|
+
uses: Martin123132/Memento-Mori@main
|
|
19
|
+
with:
|
|
20
|
+
fail-on: block
|
|
21
|
+
subject: pull request diff
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tone": "court_jester",
|
|
3
|
+
"intensity": 3,
|
|
4
|
+
"riskTolerance": "medium",
|
|
5
|
+
"hookFailOn": "block",
|
|
6
|
+
"blockedCommands": [
|
|
7
|
+
"git reset --hard",
|
|
8
|
+
"git clean -fd"
|
|
9
|
+
],
|
|
10
|
+
"sensitiveDomains": [
|
|
11
|
+
"auth",
|
|
12
|
+
"billing",
|
|
13
|
+
"payments",
|
|
14
|
+
"production",
|
|
15
|
+
"customer data"
|
|
16
|
+
],
|
|
17
|
+
"customRules": [
|
|
18
|
+
{
|
|
19
|
+
"id": "no-force-push-main",
|
|
20
|
+
"pattern": "git\\s+push\\s+--force(?:-with-lease)?\\s+origin\\s+main",
|
|
21
|
+
"severity": 5,
|
|
22
|
+
"title": "Force-push to main",
|
|
23
|
+
"detail": "This project treats force-pushing main as a stop-and-think event.",
|
|
24
|
+
"suggestedCheck": "Create a branch or use --force-with-lease only after confirming the protected branch policy.",
|
|
25
|
+
"kinds": ["command", "plan"]
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "memento-mori-jester",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "A local court-jester sidecar for AI coding agents: review plans, commands, diffs, and final claims before they get too pleased with themselves.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/Martin123132/Memento-Mori.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/Martin123132/Memento-Mori#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/Martin123132/Memento-Mori/issues"
|
|
13
|
+
},
|
|
14
|
+
"main": "./dist/core.js",
|
|
15
|
+
"types": "./dist/core.d.ts",
|
|
16
|
+
"bin": {
|
|
17
|
+
"jester": "dist/cli.js",
|
|
18
|
+
"memento-mori-jester": "dist/cli.js",
|
|
19
|
+
"memento-mori-jester-mcp": "dist/server.js"
|
|
20
|
+
},
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/core.d.ts",
|
|
24
|
+
"import": "./dist/core.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"!dist/**/*.test.*",
|
|
30
|
+
"docs",
|
|
31
|
+
"examples",
|
|
32
|
+
"scripts",
|
|
33
|
+
"LICENSE",
|
|
34
|
+
"README.md"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc -p tsconfig.json",
|
|
38
|
+
"start": "node dist/server.js",
|
|
39
|
+
"start:mcp": "node dist/server.js",
|
|
40
|
+
"test": "npm run build && node scripts/run-tests.mjs",
|
|
41
|
+
"doctor": "node dist/cli.js doctor",
|
|
42
|
+
"pack:dry": "npm pack --dry-run",
|
|
43
|
+
"prepare": "npm run build",
|
|
44
|
+
"prepublishOnly": "npm test && npm run pack:dry"
|
|
45
|
+
},
|
|
46
|
+
"keywords": [
|
|
47
|
+
"mcp",
|
|
48
|
+
"ai-agent",
|
|
49
|
+
"coding-agent",
|
|
50
|
+
"safety",
|
|
51
|
+
"cli",
|
|
52
|
+
"code-review",
|
|
53
|
+
"memento-mori",
|
|
54
|
+
"court-jester"
|
|
55
|
+
],
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
61
|
+
"zod": "^4.1.12"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@types/node": "^24.10.1",
|
|
65
|
+
"typescript": "^5.9.3"
|
|
66
|
+
},
|
|
67
|
+
"engines": {
|
|
68
|
+
"node": ">=20"
|
|
69
|
+
},
|
|
70
|
+
"license": "MIT"
|
|
71
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[string]$PackageSpec = "memento-mori-jester@latest",
|
|
3
|
+
[ValidateSet("npx", "global")]
|
|
4
|
+
[string]$Mode = "npx"
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
$ErrorActionPreference = "Stop"
|
|
8
|
+
|
|
9
|
+
function Assert-Command($Name, $InstallHint) {
|
|
10
|
+
if (-not (Get-Command $Name -ErrorAction SilentlyContinue)) {
|
|
11
|
+
throw "$Name was not found. $InstallHint"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
Assert-Command "node" "Install Node.js 20 or newer, then run this script again."
|
|
16
|
+
Assert-Command "npm.cmd" "Install npm with Node.js, then run this script again."
|
|
17
|
+
|
|
18
|
+
$nodeMajor = [int](& node -p "process.versions.node.split('.')[0]")
|
|
19
|
+
if ($nodeMajor -lt 20) {
|
|
20
|
+
throw "Node.js 20 or newer is required. Found: $(& node --version)"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if ($Mode -eq "global") {
|
|
24
|
+
& npm.cmd install -g $PackageSpec
|
|
25
|
+
& jester doctor
|
|
26
|
+
& jester mcp-config --mode global
|
|
27
|
+
} else {
|
|
28
|
+
& npx -y $PackageSpec doctor
|
|
29
|
+
& npx -y $PackageSpec mcp-config --mode npx --package $PackageSpec
|
|
30
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
PACKAGE_SPEC="${PACKAGE_SPEC:-memento-mori-jester@latest}"
|
|
5
|
+
MODE="${MODE:-npx}"
|
|
6
|
+
|
|
7
|
+
if ! command -v node >/dev/null 2>&1; then
|
|
8
|
+
echo "node was not found. Install Node.js 20 or newer, then run this script again." >&2
|
|
9
|
+
exit 1
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
if ! command -v npm >/dev/null 2>&1; then
|
|
13
|
+
echo "npm was not found. Install npm with Node.js, then run this script again." >&2
|
|
14
|
+
exit 1
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
NODE_MAJOR="$(node -p "process.versions.node.split('.')[0]")"
|
|
18
|
+
if [ "$NODE_MAJOR" -lt 20 ]; then
|
|
19
|
+
echo "Node.js 20 or newer is required. Found: $(node --version)" >&2
|
|
20
|
+
exit 1
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
if [ "$MODE" = "global" ]; then
|
|
24
|
+
npm install -g "$PACKAGE_SPEC"
|
|
25
|
+
jester doctor
|
|
26
|
+
jester mcp-config --mode global
|
|
27
|
+
else
|
|
28
|
+
npx -y "$PACKAGE_SPEC" doctor
|
|
29
|
+
npx -y "$PACKAGE_SPEC" mcp-config --mode npx --package "$PACKAGE_SPEC"
|
|
30
|
+
fi
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readdir } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
|
|
6
|
+
const testFiles = await findTestFiles("dist");
|
|
7
|
+
|
|
8
|
+
if (testFiles.length === 0) {
|
|
9
|
+
console.error("No compiled test files found in dist.");
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const result = spawnSync(process.execPath, ["--test", ...testFiles], {
|
|
14
|
+
stdio: "inherit"
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
process.exit(result.status ?? 1);
|
|
18
|
+
|
|
19
|
+
async function findTestFiles(dir) {
|
|
20
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
21
|
+
const files = await Promise.all(entries.map(async (entry) => {
|
|
22
|
+
const path = join(dir, entry.name);
|
|
23
|
+
|
|
24
|
+
if (entry.isDirectory()) {
|
|
25
|
+
return findTestFiles(path);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return entry.isFile() && entry.name.endsWith(".test.js") ? [path] : [];
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
return files.flat().sort();
|
|
32
|
+
}
|