@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.
Files changed (71) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/GLOSSARY.template.md +33 -0
  3. package/README.md +96 -0
  4. package/dist/index.d.ts +20 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +20 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/presets/js.d.ts +63 -0
  9. package/dist/presets/js.d.ts.map +1 -0
  10. package/dist/presets/js.js +112 -0
  11. package/dist/presets/js.js.map +1 -0
  12. package/dist/presets/kmp.d.ts +27 -0
  13. package/dist/presets/kmp.d.ts.map +1 -0
  14. package/dist/presets/kmp.js +253 -0
  15. package/dist/presets/kmp.js.map +1 -0
  16. package/dist/presets/kotlin.d.ts +40 -0
  17. package/dist/presets/kotlin.d.ts.map +1 -0
  18. package/dist/presets/kotlin.js +172 -0
  19. package/dist/presets/kotlin.js.map +1 -0
  20. package/dist/presets/swift.d.ts +10 -0
  21. package/dist/presets/swift.d.ts.map +1 -0
  22. package/dist/presets/swift.js +285 -0
  23. package/dist/presets/swift.js.map +1 -0
  24. package/dist/rules/acceptance-language.d.ts +95 -0
  25. package/dist/rules/acceptance-language.d.ts.map +1 -0
  26. package/dist/rules/acceptance-language.js +443 -0
  27. package/dist/rules/acceptance-language.js.map +1 -0
  28. package/dist/rules/gates.d.ts +125 -0
  29. package/dist/rules/gates.d.ts.map +1 -0
  30. package/dist/rules/gates.js +285 -0
  31. package/dist/rules/gates.js.map +1 -0
  32. package/dist/rules/kotlin.d.ts +323 -0
  33. package/dist/rules/kotlin.d.ts.map +1 -0
  34. package/dist/rules/kotlin.js +722 -0
  35. package/dist/rules/kotlin.js.map +1 -0
  36. package/dist/rules/ports-and-adapters.d.ts +86 -0
  37. package/dist/rules/ports-and-adapters.d.ts.map +1 -0
  38. package/dist/rules/ports-and-adapters.js +366 -0
  39. package/dist/rules/ports-and-adapters.js.map +1 -0
  40. package/dist/rules/scoping.d.ts +68 -0
  41. package/dist/rules/scoping.d.ts.map +1 -0
  42. package/dist/rules/scoping.js +93 -0
  43. package/dist/rules/scoping.js.map +1 -0
  44. package/dist/rules/spec-test-parity.d.ts +164 -0
  45. package/dist/rules/spec-test-parity.d.ts.map +1 -0
  46. package/dist/rules/spec-test-parity.js +456 -0
  47. package/dist/rules/spec-test-parity.js.map +1 -0
  48. package/dist/rules/swift.d.ts +50 -0
  49. package/dist/rules/swift.d.ts.map +1 -0
  50. package/dist/rules/swift.js +50 -0
  51. package/dist/rules/swift.js.map +1 -0
  52. package/dist/rules/ubiquitous-language.d.ts +36 -0
  53. package/dist/rules/ubiquitous-language.d.ts.map +1 -0
  54. package/dist/rules/ubiquitous-language.js +140 -0
  55. package/dist/rules/ubiquitous-language.js.map +1 -0
  56. package/dist/scripts/scope-report.d.ts +3 -0
  57. package/dist/scripts/scope-report.d.ts.map +1 -0
  58. package/dist/scripts/scope-report.js +184 -0
  59. package/dist/scripts/scope-report.js.map +1 -0
  60. package/kiro/README.md +20 -0
  61. package/kiro/kiro-agent.template.json +45 -0
  62. package/kiro/kiro-transcript-to-claude.py +183 -0
  63. package/kiro/probity-kiro-translate.py +132 -0
  64. package/kiro/probity-kiro.sh +87 -0
  65. package/kiro/skill-activation-forced-eval.sh +45 -0
  66. package/package.json +68 -0
  67. package/probity.config.kmp.ts +40 -0
  68. package/probity.config.kotlin.ts +37 -0
  69. package/probity.config.swift.ts +38 -0
  70. package/probity.config.ts +43 -0
  71. 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
+ })