@jjchill/probity-rules 0.1.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/CHANGELOG.md +18 -0
- package/GLOSSARY.template.md +33 -0
- package/README.md +96 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/presets/js.d.ts +63 -0
- package/dist/presets/js.d.ts.map +1 -0
- package/dist/presets/js.js +112 -0
- package/dist/presets/js.js.map +1 -0
- package/dist/presets/kmp.d.ts +27 -0
- package/dist/presets/kmp.d.ts.map +1 -0
- package/dist/presets/kmp.js +253 -0
- package/dist/presets/kmp.js.map +1 -0
- package/dist/presets/kotlin.d.ts +40 -0
- package/dist/presets/kotlin.d.ts.map +1 -0
- package/dist/presets/kotlin.js +172 -0
- package/dist/presets/kotlin.js.map +1 -0
- package/dist/presets/swift.d.ts +10 -0
- package/dist/presets/swift.d.ts.map +1 -0
- package/dist/presets/swift.js +285 -0
- package/dist/presets/swift.js.map +1 -0
- package/dist/rules/acceptance-language.d.ts +95 -0
- package/dist/rules/acceptance-language.d.ts.map +1 -0
- package/dist/rules/acceptance-language.js +443 -0
- package/dist/rules/acceptance-language.js.map +1 -0
- package/dist/rules/gates.d.ts +125 -0
- package/dist/rules/gates.d.ts.map +1 -0
- package/dist/rules/gates.js +285 -0
- package/dist/rules/gates.js.map +1 -0
- package/dist/rules/kotlin.d.ts +323 -0
- package/dist/rules/kotlin.d.ts.map +1 -0
- package/dist/rules/kotlin.js +722 -0
- package/dist/rules/kotlin.js.map +1 -0
- package/dist/rules/ports-and-adapters.d.ts +86 -0
- package/dist/rules/ports-and-adapters.d.ts.map +1 -0
- package/dist/rules/ports-and-adapters.js +366 -0
- package/dist/rules/ports-and-adapters.js.map +1 -0
- package/dist/rules/scoping.d.ts +68 -0
- package/dist/rules/scoping.d.ts.map +1 -0
- package/dist/rules/scoping.js +93 -0
- package/dist/rules/scoping.js.map +1 -0
- package/dist/rules/spec-test-parity.d.ts +164 -0
- package/dist/rules/spec-test-parity.d.ts.map +1 -0
- package/dist/rules/spec-test-parity.js +456 -0
- package/dist/rules/spec-test-parity.js.map +1 -0
- package/dist/rules/swift.d.ts +50 -0
- package/dist/rules/swift.d.ts.map +1 -0
- package/dist/rules/swift.js +50 -0
- package/dist/rules/swift.js.map +1 -0
- package/dist/rules/ubiquitous-language.d.ts +36 -0
- package/dist/rules/ubiquitous-language.d.ts.map +1 -0
- package/dist/rules/ubiquitous-language.js +140 -0
- package/dist/rules/ubiquitous-language.js.map +1 -0
- package/dist/scripts/scope-report.d.ts +3 -0
- package/dist/scripts/scope-report.d.ts.map +1 -0
- package/dist/scripts/scope-report.js +184 -0
- package/dist/scripts/scope-report.js.map +1 -0
- package/kiro/README.md +20 -0
- package/kiro/kiro-agent.template.json +45 -0
- package/kiro/kiro-transcript-to-claude.py +183 -0
- package/kiro/probity-kiro-translate.py +132 -0
- package/kiro/probity-kiro.sh +87 -0
- package/kiro/skill-activation-forced-eval.sh +45 -0
- package/package.json +68 -0
- package/probity.config.kmp.ts +40 -0
- package/probity.config.kotlin.ts +37 -0
- package/probity.config.swift.ts +38 -0
- package/probity.config.ts +43 -0
- package/scripts/spec-parity.mjs +345 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Translation helper for the Probity <-> Kiro PreToolUse shim.
|
|
4
|
+
|
|
5
|
+
Two subcommands, both stdin -> stdout so the shim can pipe cleanly
|
|
6
|
+
(the earlier inline `python3 - <<'PY'` form clashed the heredoc with the
|
|
7
|
+
piped payload on stdin, silently producing empty output = allow):
|
|
8
|
+
|
|
9
|
+
event Read a Kiro preToolUse event JSON on stdin, write the
|
|
10
|
+
equivalent claude-code payload JSON on stdout. Emits NOTHING
|
|
11
|
+
(and exits 0) for non-mutating tools, so the shim can fast-allow.
|
|
12
|
+
A transcript path, if provided via $TRANSCRIPT_TMP, is attached
|
|
13
|
+
so Probity's history-based rules work under Kiro.
|
|
14
|
+
|
|
15
|
+
reason Read a Probity claude-code response JSON on stdin. If it is a
|
|
16
|
+
deny, write the permissionDecisionReason on stdout; otherwise
|
|
17
|
+
write nothing. The shim turns a non-empty reason into `exit 2`.
|
|
18
|
+
"""
|
|
19
|
+
import json
|
|
20
|
+
import os
|
|
21
|
+
import sys
|
|
22
|
+
|
|
23
|
+
WRITE_TOOLS = {"fs_write", "write", "fsWrite"}
|
|
24
|
+
SHELL_TOOLS = {"shell", "execute_bash", "execute_cmd", "executeBash", "executeCmd"}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _insert_result(path, cwd, content, insert_line):
|
|
28
|
+
"""Reconstruct a file's content after a Kiro `insert`, so content-based
|
|
29
|
+
Probity rules (e.g. the glossary guard) see the true result rather than
|
|
30
|
+
only the introduced text. The pending write hasn't run yet, so the file on
|
|
31
|
+
disk is the pre-write state; fall back to the introduced text alone if it
|
|
32
|
+
cannot be read."""
|
|
33
|
+
full = path if os.path.isabs(path) else os.path.join(cwd, path)
|
|
34
|
+
try:
|
|
35
|
+
with open(full, "r", encoding="utf-8") as handle:
|
|
36
|
+
existing = handle.read()
|
|
37
|
+
except OSError:
|
|
38
|
+
return content
|
|
39
|
+
if isinstance(insert_line, int) and not isinstance(insert_line, bool):
|
|
40
|
+
lines = existing.splitlines(keepends=True)
|
|
41
|
+
idx = max(0, min(insert_line, len(lines)))
|
|
42
|
+
block = content if content.endswith("\n") else content + "\n"
|
|
43
|
+
return "".join(lines[:idx]) + block + "".join(lines[idx:])
|
|
44
|
+
separator = "" if existing == "" or existing.endswith("\n") else "\n"
|
|
45
|
+
return existing + separator + content
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def cmd_event():
|
|
49
|
+
try:
|
|
50
|
+
event = json.load(sys.stdin)
|
|
51
|
+
except Exception:
|
|
52
|
+
return 0 # unparseable -> emit nothing -> shim allows
|
|
53
|
+
if not isinstance(event, dict):
|
|
54
|
+
return 0
|
|
55
|
+
|
|
56
|
+
tool = event.get("tool_name") or ""
|
|
57
|
+
ti = event.get("tool_input")
|
|
58
|
+
ti = ti if isinstance(ti, dict) else {}
|
|
59
|
+
cwd = event.get("cwd") or os.getcwd()
|
|
60
|
+
|
|
61
|
+
if tool in SHELL_TOOLS:
|
|
62
|
+
payload = {"tool_name": "Bash", "tool_input": {"command": ti.get("command", "")}}
|
|
63
|
+
elif tool in WRITE_TOOLS:
|
|
64
|
+
path = ti.get("path", "")
|
|
65
|
+
if ti.get("command") == "strReplace":
|
|
66
|
+
payload = {
|
|
67
|
+
"tool_name": "Edit",
|
|
68
|
+
"tool_input": {
|
|
69
|
+
"file_path": path,
|
|
70
|
+
"old_string": ti.get("oldStr", ""),
|
|
71
|
+
"new_string": ti.get("newStr", ""),
|
|
72
|
+
"replace_all": bool(ti.get("replaceAll", False)),
|
|
73
|
+
},
|
|
74
|
+
"cwd": cwd,
|
|
75
|
+
}
|
|
76
|
+
elif ti.get("command") == "insert":
|
|
77
|
+
# insert ADDS to an existing file; a Write of only the introduced
|
|
78
|
+
# text would tell Probity the whole file became that text. Rebuild
|
|
79
|
+
# the true resulting content from the pre-write file on disk.
|
|
80
|
+
payload = {
|
|
81
|
+
"tool_name": "Write",
|
|
82
|
+
"tool_input": {
|
|
83
|
+
"file_path": path,
|
|
84
|
+
"content": _insert_result(path, cwd, ti.get("content", ""), ti.get("insertLine")),
|
|
85
|
+
},
|
|
86
|
+
"cwd": cwd,
|
|
87
|
+
}
|
|
88
|
+
else: # create -> Write of the whole-file content
|
|
89
|
+
payload = {
|
|
90
|
+
"tool_name": "Write",
|
|
91
|
+
"tool_input": {"file_path": path, "content": ti.get("content", "")},
|
|
92
|
+
"cwd": cwd,
|
|
93
|
+
}
|
|
94
|
+
else:
|
|
95
|
+
return 0 # not a mutating tool -> allow without invoking probity
|
|
96
|
+
|
|
97
|
+
transcript = os.environ.get("TRANSCRIPT_TMP") or ""
|
|
98
|
+
if transcript:
|
|
99
|
+
payload["transcript_path"] = transcript
|
|
100
|
+
|
|
101
|
+
sys.stdout.write(json.dumps(payload))
|
|
102
|
+
return 0
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def cmd_reason():
|
|
106
|
+
raw = sys.stdin.read().strip()
|
|
107
|
+
if not raw:
|
|
108
|
+
return 0
|
|
109
|
+
try:
|
|
110
|
+
obj = json.loads(raw)
|
|
111
|
+
except Exception:
|
|
112
|
+
return 0
|
|
113
|
+
if not isinstance(obj, dict):
|
|
114
|
+
return 0
|
|
115
|
+
out = obj.get("hookSpecificOutput", {})
|
|
116
|
+
if isinstance(out, dict) and out.get("permissionDecision") == "deny":
|
|
117
|
+
sys.stdout.write(out.get("permissionDecisionReason", "blocked by Probity"))
|
|
118
|
+
return 0
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def main(argv):
|
|
122
|
+
mode = argv[1] if len(argv) > 1 else ""
|
|
123
|
+
if mode == "event":
|
|
124
|
+
return cmd_event()
|
|
125
|
+
if mode == "reason":
|
|
126
|
+
return cmd_reason()
|
|
127
|
+
sys.stderr.write("usage: probity-kiro-translate.py {event|reason}\n")
|
|
128
|
+
return 64
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
if __name__ == "__main__":
|
|
132
|
+
sys.exit(main(sys.argv))
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Probity <-> Kiro PreToolUse shim.
|
|
4
|
+
#
|
|
5
|
+
# Probity (github.com/nizos/probity) ships vendor adapters for
|
|
6
|
+
# claude-code, codex, and github-copilot -- but not Kiro. This shim lets
|
|
7
|
+
# the SAME probity.config.ts enforce the mysudovpn-ios workflow under Kiro
|
|
8
|
+
# by translating between Kiro's hook contract and the claude-code one:
|
|
9
|
+
#
|
|
10
|
+
# 1. Kiro fires `preToolUse` with an event JSON on stdin:
|
|
11
|
+
# {"hook_event_name":"preToolUse","cwd":..,"tool_name":"fs_write",
|
|
12
|
+
# "tool_input":{...}}
|
|
13
|
+
# and BLOCKS a tool when the hook exits 2 (STDERR is returned to the LLM).
|
|
14
|
+
#
|
|
15
|
+
# 2. Probity's claude-code vendor expects a Claude-shaped payload
|
|
16
|
+
# {"tool_name":"Write|Edit|Bash|..","tool_input":{..},"cwd":..,
|
|
17
|
+
# "transcript_path":..}
|
|
18
|
+
# and signals a block by printing a deny JSON to stdout with exit 0:
|
|
19
|
+
# {"hookSpecificOutput":{"permissionDecision":"deny",
|
|
20
|
+
# "permissionDecisionReason":"Probity: ..."}}
|
|
21
|
+
#
|
|
22
|
+
# The event<->payload and response<->reason translation lives in
|
|
23
|
+
# probity-kiro-translate.py (kept out of this script so stdin pipes
|
|
24
|
+
# cleanly). We attach a transduced transcript so history-based rules
|
|
25
|
+
# (green-gate, TDD) work, then convert a deny response into `exit 2`.
|
|
26
|
+
#
|
|
27
|
+
# Fail-safe posture: a genuine rule violation blocks (exit 2). Shim-internal
|
|
28
|
+
# errors (bad JSON, missing probity) warn on STDERR and ALLOW (exit 0) so a
|
|
29
|
+
# tooling bug never wedges the session; the commit green-gate remains the
|
|
30
|
+
# correctness backstop.
|
|
31
|
+
|
|
32
|
+
set -u
|
|
33
|
+
|
|
34
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
35
|
+
ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
36
|
+
PROBITY="$ROOT/node_modules/.bin/probity"
|
|
37
|
+
TRANSLATE="$SCRIPT_DIR/probity-kiro-translate.py"
|
|
38
|
+
TRANSDUCER="$SCRIPT_DIR/kiro-transcript-to-claude.py"
|
|
39
|
+
|
|
40
|
+
EVENT="$(cat)"
|
|
41
|
+
|
|
42
|
+
# Probity discovers probity.config.ts and node_modules from cwd.
|
|
43
|
+
cd "$ROOT" 2>/dev/null || true
|
|
44
|
+
|
|
45
|
+
if [ ! -x "$PROBITY" ]; then
|
|
46
|
+
echo "probity-kiro: probity not installed at $PROBITY (run npm install)" >&2
|
|
47
|
+
exit 0
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# --- Transcript: transduce Kiro's session JSONL to the Anthropic shape ----
|
|
51
|
+
TRANSCRIPT_TMP=""
|
|
52
|
+
if [ -n "${KIRO_SESSION_ID:-}" ]; then
|
|
53
|
+
KIRO_JSONL="$HOME/.kiro/sessions/cli/${KIRO_SESSION_ID}.jsonl"
|
|
54
|
+
if [ -f "$KIRO_JSONL" ] && command -v python3 >/dev/null 2>&1; then
|
|
55
|
+
# Trailing X's only: BSD/macOS mktemp substitutes a run of X's solely when
|
|
56
|
+
# it ends the template. A `.jsonl` suffix here would be taken literally,
|
|
57
|
+
# colliding on every second invocation. Probity reads the path, not the
|
|
58
|
+
# extension, so no suffix is needed.
|
|
59
|
+
TRANSCRIPT_TMP="$(mktemp "${TMPDIR:-/tmp}/probity-kiro-transcript.XXXXXX")"
|
|
60
|
+
if ! python3 "$TRANSDUCER" "$KIRO_JSONL" >"$TRANSCRIPT_TMP" 2>/dev/null; then
|
|
61
|
+
rm -f "$TRANSCRIPT_TMP"
|
|
62
|
+
TRANSCRIPT_TMP=""
|
|
63
|
+
fi
|
|
64
|
+
fi
|
|
65
|
+
fi
|
|
66
|
+
export TRANSCRIPT_TMP
|
|
67
|
+
|
|
68
|
+
cleanup() { [ -n "$TRANSCRIPT_TMP" ] && rm -f "$TRANSCRIPT_TMP"; }
|
|
69
|
+
trap cleanup EXIT
|
|
70
|
+
|
|
71
|
+
# --- Translate the Kiro event to a claude-code payload --------------------
|
|
72
|
+
# Empty stdout == non-mutating tool (or unparseable) -> allow, skip probity.
|
|
73
|
+
PAYLOAD="$(printf '%s' "$EVENT" | python3 "$TRANSLATE" event)"
|
|
74
|
+
if [ -z "$PAYLOAD" ]; then
|
|
75
|
+
exit 0
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# --- Invoke Probity and translate its response to Kiro's exit codes -------
|
|
79
|
+
RESPONSE="$(printf '%s' "$PAYLOAD" | "$PROBITY" --agent claude-code 2>/dev/null)"
|
|
80
|
+
REASON="$(printf '%s' "$RESPONSE" | python3 "$TRANSLATE" reason)"
|
|
81
|
+
|
|
82
|
+
if [ -n "$REASON" ]; then
|
|
83
|
+
printf '%s\n' "$REASON" >&2
|
|
84
|
+
exit 2
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
exit 0
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# userPromptSubmit hook that forces explicit skill evaluation.
|
|
3
|
+
#
|
|
4
|
+
# Kiro CLI port of .claude/hooks/skill-activation-forced-eval.sh. Kiro has
|
|
5
|
+
# no Skill() tool, so "activation" means the agent READS the relevant
|
|
6
|
+
# SKILL.md before implementing. This hook's stdout is injected into context
|
|
7
|
+
# on every user prompt (see Kiro's Hooks docs: userPromptSubmit stdout is
|
|
8
|
+
# added to the agent's context on exit 0).
|
|
9
|
+
#
|
|
10
|
+
# Install either project-locally (.kiro/hooks/) — referenced by
|
|
11
|
+
# kiro-agent.template.json — or user-wide (~/.kiro/hooks/) for a global
|
|
12
|
+
# default agent. Both work; the project-local copy keeps a checkout
|
|
13
|
+
# self-contained (no per-machine global prerequisite).
|
|
14
|
+
|
|
15
|
+
cat <<'EOF'
|
|
16
|
+
INSTRUCTION: MANDATORY SKILL ACTIVATION SEQUENCE
|
|
17
|
+
|
|
18
|
+
Step 1 - EVALUATE (do this in your response):
|
|
19
|
+
For each skill listed in this session's available skills, state:
|
|
20
|
+
[skill-name] - YES/NO - [one-line reason]
|
|
21
|
+
|
|
22
|
+
Step 2 - ACTIVATE (do this immediately after Step 1):
|
|
23
|
+
IF any skills are YES -> Read that skill's SKILL.md (e.g.
|
|
24
|
+
.kiro/skills/<skill-name>/SKILL.md) for EACH relevant skill NOW, and follow it.
|
|
25
|
+
IF no skills are YES -> State "No skills needed" and proceed.
|
|
26
|
+
|
|
27
|
+
Step 3 - IMPLEMENT:
|
|
28
|
+
Only after Step 2 is complete, proceed with implementation.
|
|
29
|
+
|
|
30
|
+
CRITICAL: You MUST load (read) each YES skill's SKILL.md in Step 2 before
|
|
31
|
+
implementing. The evaluation (Step 1) is WORTHLESS unless you ACTIVATE (Step 2)
|
|
32
|
+
the skills. Skip the whole sequence only for trivial conversational replies that
|
|
33
|
+
touch no skill's domain.
|
|
34
|
+
|
|
35
|
+
Example of correct sequence:
|
|
36
|
+
- test-driven-development: YES - changing behaviour, needs RED->GREEN->REFACTOR
|
|
37
|
+
- code-review-and-quality: YES - will review the diff before done
|
|
38
|
+
- perfetto-sql: NO - no trace analysis in this task
|
|
39
|
+
|
|
40
|
+
[Then IMMEDIATELY read the SKILL.md for each YES skill:]
|
|
41
|
+
> Read .kiro/skills/test-driven-development/SKILL.md
|
|
42
|
+
> Read .kiro/skills/code-review-and-quality/SKILL.md
|
|
43
|
+
|
|
44
|
+
[THEN and ONLY THEN start implementation]
|
|
45
|
+
EOF
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jjchill/probity-rules",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Versioned Probity rule presets and CLI tooling for the agent-skills catalog (test-driven-development, ports-and-adapters, acceptance-testing, spec-test parity, ubiquitous-language) — see hooks/PROBITY.md.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./dist/index.js",
|
|
9
|
+
"./rules/*": "./dist/rules/*.js",
|
|
10
|
+
"./presets/*": "./dist/presets/*.js",
|
|
11
|
+
"./package.json": "./package.json"
|
|
12
|
+
},
|
|
13
|
+
"bin": {
|
|
14
|
+
"probity-scope-report": "dist/scripts/scope-report.js",
|
|
15
|
+
"probity-spec-parity": "scripts/spec-parity.mjs"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"scripts/spec-parity.mjs",
|
|
20
|
+
"kiro/kiro-agent.template.json",
|
|
21
|
+
"kiro/kiro-transcript-to-claude.py",
|
|
22
|
+
"kiro/probity-kiro-translate.py",
|
|
23
|
+
"kiro/probity-kiro.sh",
|
|
24
|
+
"kiro/skill-activation-forced-eval.sh",
|
|
25
|
+
"kiro/README.md",
|
|
26
|
+
"probity.config.ts",
|
|
27
|
+
"probity.config.kotlin.ts",
|
|
28
|
+
"probity.config.kmp.ts",
|
|
29
|
+
"probity.config.swift.ts",
|
|
30
|
+
"GLOSSARY.template.md",
|
|
31
|
+
"README.md",
|
|
32
|
+
"CHANGELOG.md"
|
|
33
|
+
],
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@nizos/probity": "^1.10.0"
|
|
36
|
+
},
|
|
37
|
+
"peerDependenciesMeta": {
|
|
38
|
+
"@ast-grep/napi": {
|
|
39
|
+
"optional": true
|
|
40
|
+
},
|
|
41
|
+
"@ast-grep/lang-kotlin": {
|
|
42
|
+
"optional": true
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"picomatch": "^4.0.4",
|
|
47
|
+
"jiti": "^2.6.1"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@ast-grep/lang-kotlin": "^0.0.7",
|
|
51
|
+
"@ast-grep/napi": "^0.45.1",
|
|
52
|
+
"@nizos/probity": "^1.10.0",
|
|
53
|
+
"@types/node": "^22.0.0",
|
|
54
|
+
"@types/picomatch": "^3.0.2",
|
|
55
|
+
"tsx": "^4.19.0",
|
|
56
|
+
"typescript": "^5.6.0"
|
|
57
|
+
},
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "tsc -p tsconfig.json",
|
|
60
|
+
"clean": "rm -rf dist",
|
|
61
|
+
"typecheck": "tsc --noEmit",
|
|
62
|
+
"test": "tsx --test rules/*.test.mts scripts/*.test.mjs",
|
|
63
|
+
"test:kiro": "for f in kiro/*.test.py; do python3 \"$f\" || exit 1; done",
|
|
64
|
+
"eval": "tsx evals/workflow-eval.ts",
|
|
65
|
+
"prepublishOnly": "npm run clean && npm run build && npm test",
|
|
66
|
+
"pack:check": "npm pack --dry-run"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Probity config template — Kotlin Multiplatform preset.
|
|
3
|
+
*
|
|
4
|
+
* Same enforcement as probity.config.kotlin.ts, recalibrated for a
|
|
5
|
+
* KMP codebase with ports-and-adapters codified per feature module:
|
|
6
|
+
* source sets (`commonMain`/`androidMain`/`desktopMain`/`iosMain`,
|
|
7
|
+
* tests in `commonTest`/`androidHostTest`/…), core vs adapter split
|
|
8
|
+
* by package (`domain`/`port`/`usecase`/`presentation` vs
|
|
9
|
+
* `adapter`/`di`/`ui`), kotlin.test + hand-written fakes with NO
|
|
10
|
+
* mocking library, Koin at the composition root only, and
|
|
11
|
+
* acceptance tests driven through a Robot DSL at the ViewModel
|
|
12
|
+
* boundary with Markdown Given/When/Then specs in docs/specs/.
|
|
13
|
+
*
|
|
14
|
+
* Install (not yet published — see probity.config.ts for the
|
|
15
|
+
* clone-path note):
|
|
16
|
+
*
|
|
17
|
+
* npm install -D @nizos/probity @jjchill/probity-rules
|
|
18
|
+
*
|
|
19
|
+
* Probity still runs on Node: `npm install -D @nizos/probity`
|
|
20
|
+
* (plus optionally @ast-grep/napi @ast-grep/lang-kotlin for the TDD
|
|
21
|
+
* fast-path) next to gradlew.
|
|
22
|
+
*
|
|
23
|
+
* EDIT: the rule entries live in `presets/kmp.ts` (`kmpRuleEntries`).
|
|
24
|
+
* The globs inside it (core/domain packages, source sets, adapter
|
|
25
|
+
* packages) are calibrated to the reference codebase above — audit
|
|
26
|
+
* them against your tree with `npx probity-scope-report` and adjust
|
|
27
|
+
* to your layout. The optional `parity` second argument turns on the
|
|
28
|
+
* per-scenario driver mapping; see the commented example in
|
|
29
|
+
* presets/kmp.ts.
|
|
30
|
+
*/
|
|
31
|
+
import { dirname } from 'node:path'
|
|
32
|
+
import { fileURLToPath } from 'node:url'
|
|
33
|
+
|
|
34
|
+
import { defineConfig } from '@nizos/probity'
|
|
35
|
+
|
|
36
|
+
import { kmpRuleEntries } from '@jjchill/probity-rules/presets/kmp'
|
|
37
|
+
|
|
38
|
+
const ROOT = dirname(fileURLToPath(import.meta.url))
|
|
39
|
+
|
|
40
|
+
export default defineConfig({ rules: kmpRuleEntries(ROOT) })
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Probity config template — Kotlin/JVM/Android preset.
|
|
3
|
+
*
|
|
4
|
+
* Same enforcement as probity.config.ts (see hooks/PROBITY.md) with
|
|
5
|
+
* the deterministic layer swapped to Kotlin-shaped rules. Calibrated
|
|
6
|
+
* against a multi-module Android codebase (Gradle per project,
|
|
7
|
+
* `<module>-core` / `<module>-ui` split, Mockito-kotlin + JUnit 4,
|
|
8
|
+
* AWS/Amplify/Apollo/OkHttp/Retrofit/Room vendor stack) — adjust the
|
|
9
|
+
* options below to your layout.
|
|
10
|
+
*
|
|
11
|
+
* Install (not yet published — see probity.config.ts for the
|
|
12
|
+
* clone-path note):
|
|
13
|
+
*
|
|
14
|
+
* npm install -D @nizos/probity @jjchill/probity-rules
|
|
15
|
+
*
|
|
16
|
+
* Note Probity itself still runs on Node: the consuming Kotlin
|
|
17
|
+
* project needs a one-dependency package.json next to gradlew.
|
|
18
|
+
*
|
|
19
|
+
* EDIT THESE OPTIONS to your layout — see presets/kotlin.ts
|
|
20
|
+
* (`KotlinPresetOptions`) for the full list and every option's
|
|
21
|
+
* current default:
|
|
22
|
+
* - coreGlobs — your core modules (e.g. `*-core` of a core/ui split)
|
|
23
|
+
* - staticMockGlobs — your test source sets
|
|
24
|
+
* - acceptanceTestGlobs / acceptanceLanguageGlobs — your spec layer
|
|
25
|
+
* - seamHint — your ambient-effect port(s)
|
|
26
|
+
* - commitCommand — your real Gradle test task
|
|
27
|
+
*/
|
|
28
|
+
import { dirname } from 'node:path'
|
|
29
|
+
import { fileURLToPath } from 'node:url'
|
|
30
|
+
|
|
31
|
+
import { defineConfig } from '@nizos/probity'
|
|
32
|
+
|
|
33
|
+
import { kotlinRuleEntries } from '@jjchill/probity-rules/presets/kotlin'
|
|
34
|
+
|
|
35
|
+
const ROOT = dirname(fileURLToPath(import.meta.url))
|
|
36
|
+
|
|
37
|
+
export default defineConfig({ rules: kotlinRuleEntries(ROOT) })
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Probity config template — Swift/iOS preset.
|
|
3
|
+
*
|
|
4
|
+
* Same enforcement stack as the Kotlin presets (see hooks/PROBITY.md),
|
|
5
|
+
* recalibrated for a native iOS app: an Xcode workspace with the
|
|
6
|
+
* acceptance suite in AcceptanceTests/ following the four-layer model
|
|
7
|
+
* (Specs + Component test glue / Scenarios / DSL / Drivers), XCUITest
|
|
8
|
+
* plus an app-hosted component-test target, MVVM view models over
|
|
9
|
+
* use-case ports, and Markdown Given/When/Then specs in docs/specs/.
|
|
10
|
+
* Calibrated against a production CocoaPods + SwiftPM app — adjust
|
|
11
|
+
* globs and package names to your layout.
|
|
12
|
+
*
|
|
13
|
+
* Install (not yet published — see probity.config.ts for the
|
|
14
|
+
* clone-path note):
|
|
15
|
+
*
|
|
16
|
+
* npm install -D @nizos/probity @jjchill/probity-rules
|
|
17
|
+
*
|
|
18
|
+
* Probity runs on Node: `npm install -D @nizos/probity` (a
|
|
19
|
+
* one-dependency package.json with `"type": "module"` next to the
|
|
20
|
+
* xcworkspace is fine).
|
|
21
|
+
*
|
|
22
|
+
* EDIT: the rule entries live in `presets/swift.ts`
|
|
23
|
+
* (`swiftRuleEntries`). The globs inside it (AcceptanceTests/ layers,
|
|
24
|
+
* App/Sources packages) are calibrated to the reference app above —
|
|
25
|
+
* audit them against your tree with `npx probity-scope-report` before
|
|
26
|
+
* trusting the gate; the file's own comments flag which patterns need
|
|
27
|
+
* per-project calibration (test command, driver scopes).
|
|
28
|
+
*/
|
|
29
|
+
import { dirname } from 'node:path'
|
|
30
|
+
import { fileURLToPath } from 'node:url'
|
|
31
|
+
|
|
32
|
+
import { defineConfig } from '@nizos/probity'
|
|
33
|
+
|
|
34
|
+
import { swiftRuleEntries } from '@jjchill/probity-rules/presets/swift'
|
|
35
|
+
|
|
36
|
+
const ROOT = dirname(fileURLToPath(import.meta.url))
|
|
37
|
+
|
|
38
|
+
export default defineConfig({ rules: swiftRuleEntries(ROOT) })
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Probity config template for agent-skills projects — plain JS/TS
|
|
3
|
+
* preset.
|
|
4
|
+
*
|
|
5
|
+
* Copy this file to your project root as `probity.config.ts`, install
|
|
6
|
+
* the rules package and Probity itself:
|
|
7
|
+
*
|
|
8
|
+
* npm install -D @nizos/probity @jjchill/probity-rules
|
|
9
|
+
*
|
|
10
|
+
* (not yet published — until then, install from a clone:
|
|
11
|
+
* npm install -D @nizos/probity /path/to/agent-skills/hooks/probity
|
|
12
|
+
* after running `npm run build` in that directory), then wire the
|
|
13
|
+
* hook (see hooks/PROBITY.md).
|
|
14
|
+
*
|
|
15
|
+
* EDIT THESE OPTIONS to your layout — the defaults below describe a
|
|
16
|
+
* common src/core + src/adapters project and WILL need adjusting:
|
|
17
|
+
* - coreGlobs — where your core/domain code lives
|
|
18
|
+
* - infrastructureImports — your stack's known vendor/framework imports
|
|
19
|
+
* - specGlobs — where your acceptance specs live
|
|
20
|
+
* - glossaryPath — absolute path to a ubiquitous-language glossary
|
|
21
|
+
* - commitCommand / commitSuccessPattern / commitFailurePattern
|
|
22
|
+
* — your real test command and its output shapes
|
|
23
|
+
* See presets/js.ts (`JsPresetOptions`) for the full list and every
|
|
24
|
+
* option's current default.
|
|
25
|
+
*
|
|
26
|
+
* Brownfield? The mutation-probe and characterization round-trips
|
|
27
|
+
* (`withMutationProbe`/`enforceProbeReversion`,
|
|
28
|
+
* `withCharacterizationTest`/`enforceCharacterizationResolution`,
|
|
29
|
+
* re-exported from `@jjchill/probity-rules/rules/kotlin` despite the
|
|
30
|
+
* filename — language-neutral) sanction retrofitting tests onto
|
|
31
|
+
* pre-existing behavior, which the plain TDD gate otherwise blocks (a
|
|
32
|
+
* test for existing behavior is born green). Wire them when you start
|
|
33
|
+
* backfilling coverage; see hooks/PROBITY.md.
|
|
34
|
+
*/
|
|
35
|
+
import { defineConfig } from '@nizos/probity'
|
|
36
|
+
|
|
37
|
+
import { jsRuleEntries } from '@jjchill/probity-rules/presets/js'
|
|
38
|
+
|
|
39
|
+
export default defineConfig({
|
|
40
|
+
rules: jsRuleEntries({
|
|
41
|
+
// glossaryPath: fileURLToPath(new URL('./docs/GLOSSARY.md', import.meta.url)),
|
|
42
|
+
}),
|
|
43
|
+
})
|