create-religion 0.4.0 → 0.5.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-religion",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "A file-backed, spec-driven AI development workflow. Spec before code, small reviewed diffs, and project state in markdown so a cleared context costs nothing.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Nate",
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Blocks first-tier commands that were not approved in the conversation.
|
|
4
|
-
*
|
|
5
|
-
* This enforces nothing new. The Authority section of the project entry file already says
|
|
6
|
-
* merging, pushing, deploying, publishing, deleting data, and rewriting history each need
|
|
7
|
-
* a fresh yes. The hook exists because that rule is prose, and prose can be forgotten
|
|
8
|
-
* mid-task. It is a safety net for one tool, never a rule of its own.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { readFileSync } from "node:fs";
|
|
12
|
-
|
|
13
|
-
const PATTERNS = [
|
|
14
|
-
{ re: /\bgit\s+push\b/, what: "pushing to a remote" },
|
|
15
|
-
{ re: /\bgit\s+merge\b/, what: "merging" },
|
|
16
|
-
{ re: /\bgit\s+(?:rebase|reset\s+--hard|filter-branch)\b/, what: "rewriting history" },
|
|
17
|
-
{ re: /\bgit\s+commit\b.*--amend\b/, what: "rewriting a commit" },
|
|
18
|
-
{ re: /\bnpm\s+publish\b|\bpnpm\s+publish\b|\byarn\s+publish\b/, what: "publishing" },
|
|
19
|
-
{ re: /\b(?:vercel|railway|render)\s+(?:deploy|up)\b/, what: "deploying" },
|
|
20
|
-
{ re: /\brm\s+-[a-z]*r[a-z]*f?\b/, what: "recursive deletion" }
|
|
21
|
-
];
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Degrade to a prompt when this guard cannot do its job.
|
|
25
|
-
*
|
|
26
|
-
* A guard that fails open becomes the exact outcome it exists to prevent: the command runs
|
|
27
|
-
* and nobody was asked. Failing closed is no better, because one malformed payload from a
|
|
28
|
-
* runtime change would block every push, merge, publish or deploy until somebody edits a hook. Asking is the
|
|
29
|
-
* honest middle: the user sees the command and decides, and the cost of a bug here is one
|
|
30
|
-
* extra prompt rather than a silent pass.
|
|
31
|
-
*/
|
|
32
|
-
function askBecauseGuardFailed(error) {
|
|
33
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
34
|
-
process.stdout.write(JSON.stringify({
|
|
35
|
-
hookSpecificOutput: {
|
|
36
|
-
hookEventName: "PreToolUse",
|
|
37
|
-
permissionDecision: "ask",
|
|
38
|
-
permissionDecisionReason:
|
|
39
|
-
`The first-tier guard hook could not run, so this command was not checked.\n\n` +
|
|
40
|
-
`Reason: ${detail}\n\n` +
|
|
41
|
-
`Approve it only if you would have approved it anyway. The guard is not covering ` +
|
|
42
|
-
`you right now, and that is worth reporting.`
|
|
43
|
-
}
|
|
44
|
-
}));
|
|
45
|
-
process.exit(0);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Covers the whole hook, not only the reads below: any throw reaches this and still asks.
|
|
49
|
-
process.on("uncaughtException", askBecauseGuardFailed);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
let input = "";
|
|
53
|
-
try {
|
|
54
|
-
input = readFileSync(0, "utf8");
|
|
55
|
-
} catch (error) {
|
|
56
|
-
askBecauseGuardFailed(error);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
let command = "";
|
|
60
|
-
try {
|
|
61
|
-
const payload = JSON.parse(input);
|
|
62
|
-
command = payload?.tool_input?.command ?? "";
|
|
63
|
-
} catch (error) {
|
|
64
|
-
askBecauseGuardFailed(error);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (!command) process.exit(0);
|
|
68
|
-
|
|
69
|
-
// A force flag makes an otherwise ordinary command destructive, so it is always first tier.
|
|
70
|
-
const forced = /--force\b|(?:^|\s)-f(?:\s|$)/.test(command) && /\bgit\s+push\b/.test(command);
|
|
71
|
-
|
|
72
|
-
for (const { re, what } of PATTERNS) {
|
|
73
|
-
if (!re.test(command)) continue;
|
|
74
|
-
|
|
75
|
-
const reason =
|
|
76
|
-
`Blocked: ${what}${forced ? " (forced)" : ""} is a first-tier action.\n\n` +
|
|
77
|
-
`The Authority section of this project's entry file requires an explicit yes for it, ` +
|
|
78
|
-
`in this conversation. The one narrow exception is an automated run under ` +
|
|
79
|
-
`git.mode pull-request, which may push branches it created after enumerating exactly ` +
|
|
80
|
-
`that at invocation. This prompt is a net, not a second opinion: if that grant was ` +
|
|
81
|
-
`given, confirm and continue.\n\n` +
|
|
82
|
-
`If the user has already approved this exact action, say so and ask them to confirm ` +
|
|
83
|
-
`once more, then proceed. Do not edit or disable this hook to get past it.`;
|
|
84
|
-
|
|
85
|
-
process.stdout.write(JSON.stringify({
|
|
86
|
-
hookSpecificOutput: {
|
|
87
|
-
hookEventName: "PreToolUse",
|
|
88
|
-
permissionDecision: "ask",
|
|
89
|
-
permissionDecisionReason: reason
|
|
90
|
-
}
|
|
91
|
-
}));
|
|
92
|
-
process.exit(0);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
process.exit(0);
|