@pablozrrrr/jevguard 0.1.0 → 0.2.2

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": "@pablozrrrr/jevguard",
3
- "version": "0.1.0",
3
+ "version": "0.2.2",
4
4
  "description": "OpenCode plugin that reviews a completed agent turn against a repository semantic rule using Jev.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -17,11 +17,13 @@
17
17
  "README.md",
18
18
  "LICENSE",
19
19
  "skills/jevguard-rules/SKILL.md",
20
- "skills/jevguard-rules/validate-rules.js"
20
+ "skills/jevguard-rules/validate-rules.js",
21
+ "skills/jev-init/SKILL.md",
22
+ "skills/jev-init/validate-init.js"
21
23
  ],
22
24
  "engines": {
23
25
  "bun": ">=1.1.0",
24
- "opencode": ">=1.18.31 <2"
26
+ "opencode": ">=1.18.32 <2"
25
27
  },
26
28
  "repository": {
27
29
  "type": "git",
@@ -0,0 +1,253 @@
1
+ ---
2
+ name: jev-init
3
+ description: Use when a repository has no JevGuard policy yet and the user wants to bootstrap `.jev/rules.md` and `.jev/config.yaml` from explicit constraints and strong local evidence. Bounded, read-only inventory; stops if either file already exists; previews both files and requires explicit confirmation before writing. Do not use to edit an existing policy, for credentials, or to run a review.
4
+ license: MIT
5
+ compatibility: opencode >=1.18.32 <2
6
+ ---
7
+
8
+ # JevGuard init
9
+
10
+ Bootstrap the first repository policy that JevGuard reads from `.jev/rules.md` and
11
+ `.jev/config.yaml`. The user states the constraints they want enforced; this skill
12
+ reads a **bounded** inventory of the repository to ground those constraints and to
13
+ infer only strongly evidenced local conventions, drafts both files with explicit
14
+ provenance, validates the exact candidates with the same parser JevGuard uses, and
15
+ writes nothing until the user confirms both files by name.
16
+
17
+ Initialization runs exactly once per repository. After it writes a policy, all later
18
+ rule authoring belongs to the `jevguard-rules` skill.
19
+
20
+ ## Non-negotiables
21
+
22
+ - **Never overwrite an existing policy.** Check `.jev/rules.md` and `.jev/config.yaml`
23
+ first. If either exists, stop, change nothing, and direct the user to the
24
+ `jevguard-rules` skill for any rule change. This skill only creates a policy where
25
+ none exists.
26
+ - **Never read, print, or copy a secret value, secret file, or secret store.** Do not
27
+ read environment variables, `.env` or `.env.*` files, credential, key, token, or
28
+ keychain/credential-store files, or `.git/config`. Do not run a command that would
29
+ expose them.
30
+ - **Never run the public `jevguard` CLI and never call Jev/TypeSafe inference.** This
31
+ skill makes no Jev call. The only program it invokes is the bundled validator next to
32
+ this `SKILL.md`.
33
+ - **Never invent architecture.** Record a rule as `inferred` only when local evidence
34
+ strongly corroborates it. When evidence is weak or speculative, omit the rule
35
+ instead of guessing.
36
+ - **Never persist conversation text.** A `user` provenance entry records only
37
+ `source: user` and, when useful, repository-relative evidence paths. It never
38
+ contains the user's words, the prompt, or any chat content.
39
+ - **Never overwrite an existing policy file.** Create `.jev/rules.md` and
40
+ `.jev/config.yaml` only with an exclusive-create primitive (`wx`/`O_EXCL`) that
41
+ refuses an existing path, and roll back only the file(s) this run created if either
42
+ target cannot be created. If the host cannot provide that primitive, write neither
43
+ file and present the validated drafts instead.
44
+ - **Never write either file before an explicit, both-files-by-name confirmation** and a
45
+ valid validator result on the exact staged candidates.
46
+
47
+ ## Workflow
48
+
49
+ ### 1. Confirm this is greenfield
50
+
51
+ Read whether `.jev/rules.md` and `.jev/config.yaml` exist. If either exists, stop
52
+ immediately: report which file is present, state that initialization is complete or
53
+ has already started, and tell the user to use the `jevguard-rules` skill to author,
54
+ add, edit, or repair rules. Do not read, draft, stage, or write anything in that case.
55
+
56
+ ### 2. Elicit the user's constraints
57
+
58
+ If the invocation does not already state the constraints the user wants enforced, ask
59
+ exactly one focused question: what policies should JevGuard enforce in this
60
+ repository? An explicit `none` is a valid answer: then there are no acceptable rules,
61
+ and step 9 writes nothing.
62
+
63
+ Record every constraint the user gives as an explicit, `user`-sourced rule. Keep the
64
+ user's stated intent; do not translate it into a broader rule than they asked for. Ask
65
+ only for facts that are genuinely missing, one question at a time.
66
+
67
+ ### 3. Read a bounded inventory
68
+
69
+ Read only enough to ground the user's constraints and to corroborate concrete local
70
+ conventions. The inventory is bounded to:
71
+
72
+ - agent and contributor instructions such as `AGENTS.md` and `CONTRIBUTING.md`;
73
+ - the README and files under `docs/`;
74
+ - the project structure (directory and file names);
75
+ - language, build, test, format, and lint configuration (for example `package.json`,
76
+ `tsconfig.json`, a formatter or linter config);
77
+ - representative source files **only** when they corroborate one concrete candidate
78
+ rule that the user asked for or that strong instructions already support.
79
+
80
+ Stop as soon as the constraints are grounded. Do not read the whole repository, do not
81
+ read generated or vendor directories, and do not read any path excluded above. When a
82
+ file could contain a secret, do not open it.
83
+
84
+ ### 4. Derive rules and provenance
85
+
86
+ Every rule you keep gets exactly one provenance entry. A rule is kept only when it
87
+ passes one of these bars:
88
+
89
+ - **`source: user`** — the user stated the constraint. This is the only source that may
90
+ use `severity: error`; still prefer `warning` unless the user asked for `error`.
91
+ - **`source: inferred`** — a strongly evidenced local convention. Record it only with
92
+ **strong corroboration**: a normative document or instruction (an `AGENTS.md`,
93
+ `CONTRIBUTING.md`, or a policy doc) **plus** independent evidence from source code,
94
+ configuration, or project structure that agrees. An inferred rule must be
95
+ `severity: warning` and cite **at least two** safe evidence paths. The bundled
96
+ validator mechanically enforces the `warning` severity and the two-path minimum, but
97
+ it cannot prove that the corroboration is genuinely normative or independent; that
98
+ semantic bar stays yours.
99
+
100
+ A single README sentence, an isolated code sample, personal preference, or an
101
+ aspiration the repository does not already follow is **not** strong evidence. Exclude
102
+ speculative rules and say which candidates you dropped and why.
103
+
104
+ Each rule block keeps the document grammar; `severity` and `scope` remain the only
105
+ accepted metadata. Provenance is **never** written inside a rule block.
106
+
107
+ ### 5. Write the provenance preamble before the rules
108
+
109
+ Provenance lives in one fenced YAML manifest at the very top of `.jev/rules.md`,
110
+ before the first `##` rule heading. The rules parser ignores everything before the
111
+ first rule heading, so the manifest never becomes policy.
112
+
113
+ ````md
114
+ ```yaml
115
+ rules:
116
+ ARCH-001:
117
+ source: user
118
+ LANG-002:
119
+ source: inferred
120
+ evidence:
121
+ - AGENTS.md
122
+ - package.json
123
+ ```
124
+
125
+ ## ARCH-001
126
+
127
+ severity: error
128
+
129
+ ### Rule
130
+
131
+ ...
132
+ ````
133
+
134
+ The manifest shape is exact:
135
+
136
+ - the top level is one `rules` mapping and nothing else;
137
+ - each key is a rule ID that also appears as a valid `##` rule heading;
138
+ - every valid rule has exactly one entry and every entry maps to a valid rule;
139
+ - `source` is exactly `user` or `inferred`;
140
+ - `evidence` is optional for `user` and **required with at least two safe paths for
141
+ `inferred`**; the validator rejects an `inferred` entry with fewer than two safe
142
+ paths, an inferred rule that did not parse as `warning`, and any `.git`, absolute,
143
+ traversal, or denied-secret path;
144
+ - each evidence path is a repository-relative POSIX path (no leading `/`, no `\`, no
145
+ `..`, no drive letter, no URL) and is never a secret path.
146
+
147
+ If a candidate rule is dropped, it appears in neither the rules nor the manifest.
148
+
149
+ ### 6. Generate the default configuration
150
+
151
+ Write the canonical V0.1 defaults to `.jev/config.yaml`, thresholds first and then the
152
+ remediation section, exactly:
153
+
154
+ ```yaml
155
+ version: 1
156
+
157
+ thresholds:
158
+ error:
159
+ warn: 0.40
160
+ fail: 0.70
161
+ warning:
162
+ warn: 0.60
163
+
164
+ remediation:
165
+ auto_propose: true
166
+ propose_on:
167
+ - FAIL
168
+ ```
169
+
170
+ Do not invent thresholds or add keys. The default configuration is valid and uses the
171
+ documented defaults. Never pin `remediation.model`: when it is absent the proposer
172
+ inherits the host model, which is the only portable choice. A hard-coded provider
173
+ model can be absent on the user's machine and would make every proposal fail.
174
+
175
+ ### 7. Preview both files and require explicit confirmation
176
+
177
+ Show the user the complete candidate `.jev/rules.md` — including the provenance
178
+ preamble — and the complete candidate `.jev/config.yaml`, each with its intended exact
179
+ path. For every rule, state its `source` and, when inferring, the evidence that
180
+ corroborates it. List any candidate you dropped.
181
+
182
+ Ask for explicit confirmation that names **both** exact files, for example
183
+ `.jev/rules.md` and `.jev/config.yaml`. A vague `ok` does not count. If the user
184
+ changes any constraint, source, or rule, return to step 4 and draft again.
185
+
186
+ ### 8. Stage the confirmed candidates exclusively, then validate
187
+
188
+ Only after that confirmation, create the two staging files in `.jev/` with a fresh
189
+ random identifier generated now, for example
190
+ `.jev/rules.md.jev-init-<random-id>.tmp` and
191
+ `.jev/config.yaml.jev-init-<random-id>.tmp`. The host's ordinary file tool cannot
192
+ guarantee exclusive create, so stage through a tiny temporary script that:
193
+
194
+ - creates `.jev` if it does not exist;
195
+ - opens each staging path with an exclusive-create flag (`wx`, or `O_CREAT | O_EXCL`)
196
+ so an existing file or symlink makes the open fail instead of being followed or
197
+ overwritten;
198
+ - writes the exact confirmed candidate bytes;
199
+ - exits non-zero without touching any other path if either open fails.
200
+
201
+ Do not pass a fixed or reused name. Record the two absolute staging paths as owned by
202
+ this execution; all later validation and deletion apply only to those paths. If you
203
+ cannot run a script with an exclusive-create primitive, stop before writing anything
204
+ and present the drafts to the user instead.
205
+
206
+ Validate exactly those staged candidates with the bundled helper from this skill's
207
+ base directory:
208
+
209
+ ```sh
210
+ bun "<skill-base-dir>/validate-init.js" ".jev/rules.md.jev-init-<random-id>.tmp" ".jev/config.yaml.jev-init-<random-id>.tmp"
211
+ ```
212
+
213
+ The helper prints only JSON: `status`, the valid rule IDs, and deterministic codes. It
214
+ never prints rule text, config values, evidence contents, file contents, or
215
+ credentials. If it reports `invalid` or `error`, report the safe codes, remove only
216
+ your own recorded staging files, and leave the repository policy untouched.
217
+
218
+ ### 9. Commit both files exclusively, or write nothing
219
+
220
+ Commit only when the exact staged candidates validated as `valid` and there is at least
221
+ one acceptable rule. Immediately before committing, re-check that neither
222
+ `.jev/rules.md` nor `.jev/config.yaml` exists. Then run a tiny temporary script that:
223
+
224
+ - creates `.jev` if it does not exist;
225
+ - opens each target with an exclusive-create flag (`wx`, or `O_CREAT | O_EXCL`), so a
226
+ path that appeared since the re-check makes the open fail rather than being
227
+ overwritten or followed through a symlink;
228
+ - writes the exact validated staged bytes;
229
+ - if either open or write fails, closes what it opened, deletes only the target file(s)
230
+ this run created, and exits non-zero — it never overwrites, truncates, or deletes a
231
+ preexisting file;
232
+ - removes only its own staging files and the temporary script.
233
+
234
+ The script reads only its own staged files; it must not open any other repository file,
235
+ environment variable, or secret. If the host cannot run a script with an
236
+ exclusive-create primitive, write neither target, remove only your own staging files,
237
+ present the validated drafts, and do not claim success.
238
+
239
+ If there are no acceptable rules, write nothing: create neither target, remove only
240
+ your own staging files, and report that no policy was bootstrapped. Never write a
241
+ speculative rule, and never write a configuration without the rules it belongs to.
242
+
243
+ After committing, read both files back and validate them once more with the helper. If
244
+ the result is not `valid`, stop and report rather than claiming success.
245
+
246
+ ## Reporting
247
+
248
+ Report both written paths, every final rule ID with its `source` and severity, the
249
+ helper's safe codes, and any candidate rule you excluded as speculative or
250
+ weakly evidenced. Never echo secret values, credentials, environment values, or the
251
+ contents of non-policy files. Never claim a policy was written when the validator did
252
+ not return `valid`, the exclusive commit did not succeed, or the user did not confirm
253
+ both files by name.