omakit 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/LICENSE +21 -0
- package/README.md +229 -0
- package/bin/omakit +3 -0
- package/package.json +40 -0
- package/skills/omarchy-plugin-submit/SKILL.md +87 -0
- package/skills/omarchy-plugin-validation-watch/SKILL.md +62 -0
- package/tests/parity/corpus.mjs +62 -0
- package/tests/parity/run.mjs +194 -0
- package/tools/marketplace/README.md +64 -0
- package/tools/marketplace/agent-control.mjs +72 -0
- package/tools/marketplace/banner.mjs +307 -0
- package/tools/marketplace/cli.mjs +283 -0
- package/tools/marketplace/completion.mjs +263 -0
- package/tools/marketplace/doctor.mjs +156 -0
- package/tools/marketplace/effect.mjs +115 -0
- package/tools/marketplace/form.mjs +209 -0
- package/tools/marketplace/github.mjs +206 -0
- package/tools/marketplace/issue.mjs +80 -0
- package/tools/marketplace/local-transport.mjs +162 -0
- package/tools/marketplace/parity-output.mjs +26 -0
- package/tools/marketplace/paths.mjs +10 -0
- package/tools/marketplace/pin.mjs +203 -0
- package/tools/marketplace/plugin.mjs +64 -0
- package/tools/marketplace/preflight.mjs +164 -0
- package/tools/marketplace/progress.mjs +96 -0
- package/tools/marketplace/registry.mjs +216 -0
- package/tools/marketplace/report.mjs +192 -0
- package/tools/marketplace/run-baseline.mjs +72 -0
- package/tools/marketplace/setup.mjs +136 -0
- package/tools/marketplace/style.mjs +443 -0
- package/tools/marketplace/submit.mjs +341 -0
- package/tools/marketplace/tree.mjs +50 -0
- package/tools/marketplace/upgrade.mjs +179 -0
- package/tools/marketplace/usage.mjs +191 -0
- package/tools/marketplace/verify.mjs +70 -0
- package/tools/marketplace/watch.mjs +262 -0
- package/tools/marketplace/yaml.mjs +164 -0
- package/tools/subject/resolve.mjs +124 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Maarten Tolhuijs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/media/banner.gif" alt="omakit" width="440">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
**Everything knowable about an Omarchy Quattro plugin submission, checked
|
|
6
|
+
before you post it:** the tree, the manifest, the form, the commit, and the
|
|
7
|
+
marketplace's own security baseline with its outcome reported as it is. A
|
|
8
|
+
submission is judged at one exact commit and drifts from it the moment you
|
|
9
|
+
push; `watch` says when that has happened. All of it runs on your own machine
|
|
10
|
+
and publishes nothing: no issue, no comment, no label, nobody's attention spent
|
|
11
|
+
until you choose to.
|
|
12
|
+
|
|
13
|
+

|
|
14
|
+
|
|
15
|
+
The plugin above is refused for three things the marketplace itself refuses,
|
|
16
|
+
and warned about a fourth: it ships instruction files an agent will read once
|
|
17
|
+
installed. **103 marketplace issues mention exactly that, and no automated check
|
|
18
|
+
reports it, so today an author finds out from a human review round.** It is a
|
|
19
|
+
warning and not a refusal, because the marketplace does list plugins that ship
|
|
20
|
+
them: 6 of 34 inspected do, at the commit that was listed.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
omakit submit <plugin-repo> --category Widgets --tags bar,quickshell
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Fifteen checks, each naming its source and, when it fails, the measured reason it
|
|
27
|
+
exists. A blocking failure produces no submission body at all, because a refusal
|
|
28
|
+
that still hands you the body is only a suggestion.
|
|
29
|
+
|
|
30
|
+
## Why it exists
|
|
31
|
+
|
|
32
|
+
Four numbers, all measured on public marketplace data on 2026-09-12. Method,
|
|
33
|
+
limits and the rest of the figures: [docs/MEASUREMENTS.md](docs/MEASUREMENTS.md).
|
|
34
|
+
|
|
35
|
+
| Measured | Consequence |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| 39 submissions fell out on the title prefix alone, and 11 more are malformed in the body, one by a single word | the format is generated from the pinned form and judged by the marketplace's own parser |
|
|
38
|
+
| 1,215 of the 2,916 listings with a recorded baseline needed a human to look, because of a capability | the official baseline runs locally on the exact commit first, and names the capability |
|
|
39
|
+
| 103 issues mention agent-control files, which no automated check reports | submit names every one with its remedy, before a reviewer has to |
|
|
40
|
+
| 73% of parked submissions have a HEAD the marketplace never saw; 46% of the maintainer's own revalidation requests never produced one | a validation watch that names the one action which re-runs validation |
|
|
41
|
+
|
|
42
|
+
It does not claim to unblock the maintainer. His review writing barely repeats,
|
|
43
|
+
his median time from submission to publication is hours, and the queue waiting on
|
|
44
|
+
him is a median half a day old. The honest size of what this saves him is the
|
|
45
|
+
staleness paragraph he has written by hand on 358 issues, roughly 5.5% of his
|
|
46
|
+
review writing. The rest of the benefit is the submitter's.
|
|
47
|
+
[docs/MARKETPLACE.md](docs/MARKETPLACE.md) states that in full.
|
|
48
|
+
|
|
49
|
+
## Install
|
|
50
|
+
|
|
51
|
+
On Omarchy, or any Arch:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
yay -S omakit
|
|
55
|
+
omakit setup
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Anywhere with Node 22 or newer:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm install --global omakit
|
|
62
|
+
omakit setup
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Or read what you run:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
git clone --depth 1 https://github.com/mtolhuys/omakit ~/.local/share/omakit
|
|
69
|
+
ln -s ~/.local/share/omakit/bin/omakit ~/.local/bin/omakit
|
|
70
|
+
omakit setup
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
| Needs | Why |
|
|
74
|
+
| --- | --- |
|
|
75
|
+
| Node 22 or newer | the tool is plain ESM with no dependencies and no build step. A stock Omarchy has it through `mise`, along with `git`, `yay`, `gh` and `ttfx` |
|
|
76
|
+
| `git` | the pin, and reading a subject's tree at an exact commit |
|
|
77
|
+
| network, once | `omakit pin`. After that, `submit` and `verify` on a local repository need none at all |
|
|
78
|
+
| 15 MB on disk | the pinned checkout, in `$XDG_CACHE_HOME/omakit/marketplace`, or `~/.cache/omakit/marketplace` |
|
|
79
|
+
|
|
80
|
+
Updates come from whichever installer you used: `omarchy-update` or `yay -Syu`
|
|
81
|
+
for the package, `npm i -g omakit@latest` for npm, `omakit upgrade` for a
|
|
82
|
+
clone. Nothing in omakit updates itself, and `omarchy-mise-install npm:omakit`
|
|
83
|
+
would, so it is not the way in.
|
|
84
|
+
|
|
85
|
+
## Watch
|
|
86
|
+
|
|
87
|
+

|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
omakit watch <submission-issue-url>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
That submission passed validation and passed the security baseline with zero
|
|
94
|
+
findings. It is stuck because the marketplace validated one exact commit, and
|
|
95
|
+
the only action that makes it validate a newer one is editing the issue body. Pushing the fix does
|
|
96
|
+
nothing. Commenting "fixed in `abc123`" does nothing. **73% of the 464
|
|
97
|
+
submissions parked in their author's court have a default-branch HEAD the
|
|
98
|
+
marketplace never saw.**
|
|
99
|
+
|
|
100
|
+
## Commands
|
|
101
|
+
|
|
102
|
+
Agent-first: the expected user is a coding agent submitting a plugin on an
|
|
103
|
+
owner's behalf. Zero dependencies, plain ESM, one entry point, no build step.
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
omakit setup # the environment, the pin, tab completion, and what to try first
|
|
107
|
+
omakit submit <plugin-repo> --category <c> --tags <a,b>
|
|
108
|
+
omakit watch <issue-url> # the commit the marketplace validated, against the plugin's current HEAD
|
|
109
|
+
omakit verify <plugin-repo> # the official security baseline over the local transport, reported verbatim
|
|
110
|
+
omakit parity # the baseline over GitHub versus the local transport, on real listings; writes the evidence
|
|
111
|
+
omakit doctor # what is installed, what is pinned, and what has moved
|
|
112
|
+
omakit pin # what setup does for the pin, on its own
|
|
113
|
+
omakit upgrade # fast-forwards this checkout of omakit itself
|
|
114
|
+
omakit help --agent # the operating instructions, for the agent running this
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+

|
|
118
|
+
|
|
119
|
+
`omakit setup` checks the environment, fetches the marketplace checkout that
|
|
120
|
+
every rule is read from, installs tab completion for the shell you run it from
|
|
121
|
+
(bash, zsh or fish, read from `$SHELL`), and tells you what to try first. It is
|
|
122
|
+
idempotent. The fetch takes about 2 seconds and 15 MB, because it takes only the
|
|
123
|
+
seven files omakit reads out of that repository rather than the 325 MB it is at
|
|
124
|
+
that commit. The completion script knows the subcommands and their flags,
|
|
125
|
+
completes a directory for `<target>`, and offers the categories and tags the
|
|
126
|
+
pin's submission form actually has.
|
|
127
|
+
|
|
128
|
+
There is nothing to authenticate. If you have `gh auth login` done, omakit
|
|
129
|
+
reads that credential for GET requests and stores nothing; a token in
|
|
130
|
+
`GH_TOKEN` or `GITHUB_TOKEN` reaches it the same way, because `gh` honours
|
|
131
|
+
those itself. Without either, `watch` and `parity` share GitHub's
|
|
132
|
+
60-requests-an-hour unauthenticated allowance, and `submit` and `verify` on a
|
|
133
|
+
local repository do not touch the network at all (a `<url>@<sha>` target is
|
|
134
|
+
fetched once, over git, into the cache). omakit reads no environment variable of its own,
|
|
135
|
+
and `omakit doctor` names the credential source it found, or that it found
|
|
136
|
+
none.
|
|
137
|
+
|
|
138
|
+
Every colour omakit prints is an ANSI palette index, so your Omarchy theme
|
|
139
|
+
decides what it looks like, and nothing is said by colour alone. What the
|
|
140
|
+
terminal shows and why is [docs/TUI.md](docs/TUI.md); which index each role
|
|
141
|
+
gets, measured over all 32 installed themes, is
|
|
142
|
+
[docs/PALETTE.md](docs/PALETTE.md).
|
|
143
|
+
|
|
144
|
+
## What it is doing
|
|
145
|
+
|
|
146
|
+
Nothing about the submission format is written down in this repository. The
|
|
147
|
+
title prefix, the six form headings in order, the nine categories, the thirteen
|
|
148
|
+
tags and the exact text of the five checklist items are all read from
|
|
149
|
+
`.github/ISSUE_TEMPLATE/submit-plugin.yml` in a marketplace checkout pinned to an
|
|
150
|
+
exact commit. The rendered body is then handed to the marketplace's own
|
|
151
|
+
`parseCurrentSubmission` from that same commit. If it accepts the body here, it
|
|
152
|
+
accepts it there.
|
|
153
|
+
|
|
154
|
+
The security baseline is the marketplace's own code, imported unmodified and run
|
|
155
|
+
over a local snapshot with no network. Omakit adds no rule, renames no outcome,
|
|
156
|
+
and never restates the result as a safety claim: the baseline does no data-flow
|
|
157
|
+
analysis and is not a security review, and the output says so in the
|
|
158
|
+
marketplace's own words.
|
|
159
|
+
|
|
160
|
+
Every check is labelled. `[marketplace-pin]` is the marketplace's rule, read from
|
|
161
|
+
the pin. `[omakit]` is this project's own check, derived from public issue data.
|
|
162
|
+
Those are not marketplace policy and do not claim to be.
|
|
163
|
+
|
|
164
|
+
## Updating
|
|
165
|
+
|
|
166
|
+
Two different things could mean "upgrade" here, and only one of them may ever
|
|
167
|
+
move on its own. That distinction is now enforced rather than argued.
|
|
168
|
+
|
|
169
|
+
**The tool:**
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
omakit upgrade # fast-forwards this checkout of omakit itself
|
|
173
|
+
omakit upgrade --dry-run
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
It refuses a dirty tree, a detached HEAD, a remote that is not this repository,
|
|
177
|
+
and anything that is not a fast-forward, and it names what to run yourself in
|
|
178
|
+
each case. It is not a self-updater of the kind this repository warns other
|
|
179
|
+
people about: it fast-forwards a Git checkout you cloned, from the remote you
|
|
180
|
+
cloned it from, and it touches nothing else. On a package install it says so and
|
|
181
|
+
names the installer's own command: `npm i -g omakit@latest`, or
|
|
182
|
+
`sudo pacman -Syu omakit` for the Arch package. `git -C ~/.local/share/omakit pull` still works
|
|
183
|
+
and does the same thing.
|
|
184
|
+
|
|
185
|
+
**The pin** does not move by itself, ever, and `omakit upgrade` does not move it
|
|
186
|
+
either: a test asserts that its source does not so much as mention the pin or
|
|
187
|
+
the cache. Bumping it changes where the submission contract and the baseline
|
|
188
|
+
policy are read from, and the procedure in
|
|
189
|
+
[docs/UPSTREAM_CONTRACT.md](docs/UPSTREAM_CONTRACT.md) ends in re-proving
|
|
190
|
+
transport parity and committing the evidence. `omakit doctor` tells you when the
|
|
191
|
+
pin is behind the marketplace's current branch and then leaves it alone. That the
|
|
192
|
+
pin can go stale unnoticed is the same defect class `omakit watch` reports, so it
|
|
193
|
+
would be poor form to hide it here.
|
|
194
|
+
|
|
195
|
+
## Evidence, not claims
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
npm test # 147 tests, node --test, no dependencies
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
| Claim | Proof |
|
|
202
|
+
| --- | --- |
|
|
203
|
+
| The local transport produces the marketplace's own result | 30 of 30 identical, [docs/evidence/parity/](docs/evidence/parity/) |
|
|
204
|
+
| A local run touches no network | run inside `unshare -rn`, [docs/evidence/offline/](docs/evidence/offline/) |
|
|
205
|
+
| The generated body is well formed | the marketplace's own parser, `tests/unit/issue.test.mjs` |
|
|
206
|
+
| Nothing writes to the marketplace | `tests/unit/read-only.test.mjs`, over every source file |
|
|
207
|
+
| No agent-control file can reach a plugin | `tests/unit/self-containment.test.mjs` |
|
|
208
|
+
| The GIFs above are real output | captures and renderer in [docs/media/](docs/media/) |
|
|
209
|
+
|
|
210
|
+
Committed evidence records a digest of each side rather than the results
|
|
211
|
+
themselves: findings about a specific third-party plugin are not this project's
|
|
212
|
+
to publish.
|
|
213
|
+
|
|
214
|
+
## Documentation
|
|
215
|
+
|
|
216
|
+
| Document | For |
|
|
217
|
+
| --- | --- |
|
|
218
|
+
| [docs/SUBMIT.md](docs/SUBMIT.md) | every check and what it decides |
|
|
219
|
+
| [docs/VALIDATION_WATCH.md](docs/VALIDATION_WATCH.md) | the validation watch: what the marketplace validated, and what moves it |
|
|
220
|
+
| [docs/MEASUREMENTS.md](docs/MEASUREMENTS.md) | every number, its method and its limits |
|
|
221
|
+
| [docs/UPSTREAM_CONTRACT.md](docs/UPSTREAM_CONTRACT.md) | the seam, the pin, the boundaries |
|
|
222
|
+
| [docs/MARKETPLACE.md](docs/MARKETPLACE.md) | who this actually helps |
|
|
223
|
+
| [docs/PALETTE.md](docs/PALETTE.md) | every installed Omarchy theme measured, and which palette index each role gets |
|
|
224
|
+
| [docs/TUI.md](docs/TUI.md) | what the terminal shows, and why it looks that way |
|
|
225
|
+
| [AGENTS.md](AGENTS.md) | changing this repository |
|
|
226
|
+
|
|
227
|
+
MIT. Derived work built on public data from
|
|
228
|
+
`omacom/omarchy-plugin-marketplace`; not affiliated with or endorsed by that
|
|
229
|
+
project.
|
package/bin/omakit
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "omakit",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The safe place to find out: everything knowable about an Omarchy Quattro plugin submission before you post it, on your own machine. Agent-first, read-only, posts nothing, zero dependencies.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Maarten Tolhuijs",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"omarchy",
|
|
9
|
+
"quattro",
|
|
10
|
+
"plugin",
|
|
11
|
+
"marketplace",
|
|
12
|
+
"preflight",
|
|
13
|
+
"cli",
|
|
14
|
+
"agent"
|
|
15
|
+
],
|
|
16
|
+
"type": "module",
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=22"
|
|
19
|
+
},
|
|
20
|
+
"bin": {
|
|
21
|
+
"omakit": "bin/omakit"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"pin": "node tools/marketplace/cli.mjs pin",
|
|
25
|
+
"test": "node --test tests/unit/*.test.mjs",
|
|
26
|
+
"parity": "node tools/marketplace/cli.mjs parity --count 30",
|
|
27
|
+
"doctor": "node tools/marketplace/cli.mjs doctor"
|
|
28
|
+
},
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/mtolhuys/omakit.git"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"bin",
|
|
35
|
+
"tools",
|
|
36
|
+
"skills",
|
|
37
|
+
"tests/parity/corpus.mjs",
|
|
38
|
+
"tests/parity/run.mjs"
|
|
39
|
+
]
|
|
40
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: omarchy-plugin-submit
|
|
3
|
+
description: Submit an Omarchy Quattro plugin to the plugin marketplace on its owner's behalf. Use when asked to submit, list or publish a plugin to the Omarchy marketplace, or to check whether a plugin is ready to submit. Runs every pre-submission check, produces the exact issue title and body, and posts nothing.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Submitting an Omarchy plugin
|
|
7
|
+
|
|
8
|
+
## The one thing to get right
|
|
9
|
+
|
|
10
|
+
**You do not create the issue.** This tool produces a title and a body. Creating
|
|
11
|
+
the issue is a separate, explicit act that needs the plugin owner's approval
|
|
12
|
+
first, which is what the marketplace's own agent instructions require. Show the
|
|
13
|
+
owner the title, the body and the verdicts, ask, and only then post it.
|
|
14
|
+
|
|
15
|
+
## Run it
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
omakit pin # once, and after any pin change: fetches the pinned marketplace checkout
|
|
19
|
+
omakit submit <path-to-the-plugin-repo> --category <category> --tags <a,b>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The plugin's name and id come from the root `manifest.json`. The repository URL
|
|
23
|
+
comes from `origin`. You supply the category and the tags, because nobody else
|
|
24
|
+
can: they are an editorial choice about where the plugin belongs.
|
|
25
|
+
|
|
26
|
+
If you do not know which category and tags are allowed, run the command without
|
|
27
|
+
them. The failing checks print the controlled lists, read from the pinned form.
|
|
28
|
+
|
|
29
|
+
Useful flags: `--notes` for the Maintainer notes field, `--suggest-tag` for the
|
|
30
|
+
optional suggestion, `--name` when the manifest has no name, `--json` for a
|
|
31
|
+
machine-readable result, `--offline` to skip the one check that needs the network.
|
|
32
|
+
|
|
33
|
+
## Reading the result
|
|
34
|
+
|
|
35
|
+
Exit code 0 means every blocking check passed and the output contains the issue
|
|
36
|
+
title and body. Exit code 1 means it refused, and no body was produced.
|
|
37
|
+
|
|
38
|
+
Each check names a source. `[marketplace-pin]` is the marketplace's own rule, read
|
|
39
|
+
from a pinned checkout. `[omakit]` is this tool's own check, derived from public
|
|
40
|
+
issue data. Do not describe those to the owner as marketplace requirements.
|
|
41
|
+
|
|
42
|
+
A failing check prints the failing paths, a remedy and the measured reason it
|
|
43
|
+
exists. Fix the cause, do not work around the check.
|
|
44
|
+
|
|
45
|
+
## The two refusals people argue with
|
|
46
|
+
|
|
47
|
+
**`tree.agent-control`.** Agent-control files anywhere in the installable tree
|
|
48
|
+
(`AGENTS.md`, `CLAUDE.md`, `SKILL.md`, `.mcp.json`, anything under `.claude/` or
|
|
49
|
+
`.codex/`, instruction files under `skills/`) are read by whatever agent the user
|
|
50
|
+
runs next, and 103 marketplace issues mention them. This is a warning, not a
|
|
51
|
+
refusal: the marketplace lists plugins that ship them (6 of 34 inspected at
|
|
52
|
+
their listed commit), so the body is still produced. Tell the owner, and offer
|
|
53
|
+
the remedy: move the guidance to a non-agent filename such as `DEVELOPMENT.md`,
|
|
54
|
+
untrack the originals so they leave the installable tree, and keep a recursive
|
|
55
|
+
check in the release process so they cannot return. The owner decides; do not
|
|
56
|
+
strip files from their tree on your own.
|
|
57
|
+
|
|
58
|
+
**`submission.validation-commit`.** The marketplace validates the commit it
|
|
59
|
+
resolves when the issue is opened or edited, which is the pushed default-branch
|
|
60
|
+
HEAD, not whatever is checked out locally. Push first, then submit. 73% of submissions
|
|
61
|
+
parked in their author's court have a HEAD the marketplace never saw.
|
|
62
|
+
|
|
63
|
+
## What the baseline result means
|
|
64
|
+
|
|
65
|
+
`baseline.preflight` runs the marketplace's own security baseline over a local
|
|
66
|
+
snapshot of the exact commit and reports it verbatim.
|
|
67
|
+
|
|
68
|
+
- `passed`: nothing in the baseline holds the submission back.
|
|
69
|
+
- `review-required`: no findings, but one or more of the seven capabilities is
|
|
70
|
+
present, so a maintainer must look at this exact commit. Not a defect. Worth
|
|
71
|
+
explaining in `--notes` rather than hiding.
|
|
72
|
+
- `needs-fixes`: findings. Only `sudoers-dangerous-passwordless-command` and
|
|
73
|
+
`privileged-process-control-from-shared-temp` block publication under the
|
|
74
|
+
current enforcement mode; the rest a maintainer may accept for that commit.
|
|
75
|
+
Fixing them first avoids a human round either way.
|
|
76
|
+
|
|
77
|
+
Never restate any of this as a safety claim. The baseline performs no data-flow
|
|
78
|
+
analysis and is not a security review; the output says so in the marketplace's own
|
|
79
|
+
words, and so should you.
|
|
80
|
+
|
|
81
|
+
## After the issue exists
|
|
82
|
+
|
|
83
|
+
Tell the owner the one thing nobody tells them: the marketplace validated one
|
|
84
|
+
exact commit, and **editing the issue body** is the only action that makes it
|
|
85
|
+
validate a newer one. Pushing a fix does nothing. Commenting "fixed in `abc123`" does nothing.
|
|
86
|
+
Then use `omakit watch <issue-url>` to check it later, and see
|
|
87
|
+
`skills/omarchy-plugin-validation-watch/SKILL.md`.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: omarchy-plugin-validation-watch
|
|
3
|
+
description: Diagnose an Omarchy marketplace plugin submission that has gone quiet or is stuck waiting. Use when a submission issue has had no progress, when a reviewer asked for a fresh validation, or when fixes were pushed but nothing happened. Checks whether the validated commit has fallen behind the repository and names the one action that re-runs validation.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# A submission that has gone quiet
|
|
7
|
+
|
|
8
|
+
## The mechanism, first
|
|
9
|
+
|
|
10
|
+
The marketplace validates **one exact commit**, and the review that follows is
|
|
11
|
+
of that commit. The only action that makes it validate a newer one is **editing
|
|
12
|
+
the issue body**.
|
|
13
|
+
|
|
14
|
+
- The only workflow with a direct `issues` trigger fires on
|
|
15
|
+
`opened, edited, reopened, labeled, unlabeled`.
|
|
16
|
+
- There is no `issue_comment` trigger anywhere in the marketplace.
|
|
17
|
+
- The daily HEAD comparison covers plugins that are already listed, not open
|
|
18
|
+
submissions.
|
|
19
|
+
|
|
20
|
+
So pushing a fix does nothing, and commenting "fixed in `abc123`" does nothing.
|
|
21
|
+
Both feel like progress. Neither is. This is the single most common reason a
|
|
22
|
+
submission sits still: of the 464 submissions parked in their author's court, 73%
|
|
23
|
+
have a default-branch HEAD the marketplace never saw, and 82% of the authors whose
|
|
24
|
+
push came after a review comment had also commented: engaged, and stuck.
|
|
25
|
+
|
|
26
|
+
## Check it
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
omakit watch https://github.com/omacom/omarchy-plugin-marketplace/issues/<number>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Read-only. It does not comment, label, or edit anything, and it cannot. It reads
|
|
33
|
+
the default branch through the REST API when a credential is available, taking
|
|
34
|
+
it from the operator's `gh` login (which itself honours `GH_TOKEN` and
|
|
35
|
+
`GITHUB_TOKEN`); without one it falls back to the public commit feed. Never ask the operator for a token: run
|
|
36
|
+
`omakit doctor` and read the `github.auth` line, which names the source.
|
|
37
|
+
|
|
38
|
+
## Acting on each verdict
|
|
39
|
+
|
|
40
|
+
**`stale`.** The validated commit is behind the repository. Tell the owner plainly: the marketplace has not
|
|
41
|
+
seen the newer commit, and the fix is to **edit the issue body** (any edit
|
|
42
|
+
re-triggers validation and the baseline against the new commit). Do not advise
|
|
43
|
+
them to push again, and do not advise them to comment. If you are asked to do it,
|
|
44
|
+
that is an edit to their issue: get their explicit approval and do it yourself,
|
|
45
|
+
outside this tool.
|
|
46
|
+
|
|
47
|
+
**`current`.** The validated commit is the current HEAD. The submission is genuinely waiting
|
|
48
|
+
on a person, or on a fix the reviewer asked for that has not been made. Read the
|
|
49
|
+
review comments and address the substance. Do not edit the issue to "bump" it: a
|
|
50
|
+
fresh validation clears the reviewer's human decision and costs him a complete
|
|
51
|
+
re-read of the plugin.
|
|
52
|
+
|
|
53
|
+
**`unknown`.** There is no validated commit to compare, the last baseline did not
|
|
54
|
+
complete, or the repository's HEAD could not be read. The output says which. Never
|
|
55
|
+
report this as `current`.
|
|
56
|
+
|
|
57
|
+
## Before you conclude that the reviewer is behind
|
|
58
|
+
|
|
59
|
+
Check the assumption. The maintainer's own queue is a median half a day old, and
|
|
60
|
+
his median time from submission to publication is hours. If a submission has been
|
|
61
|
+
still for five days, the overwhelmingly likely reason is that it is waiting on its
|
|
62
|
+
author, not on him.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Deterministic parity corpus: listed marketplace repositories at their exact
|
|
2
|
+
// listing-validated commits, read from the pinned marketplace registry so the
|
|
3
|
+
// set is reproducible and never hand-picked for a favourable result.
|
|
4
|
+
//
|
|
5
|
+
// The registry records the outcome the marketplace itself computed for each
|
|
6
|
+
// listing (`automatedSecurityBaseline.outcome`). The corpus is stratified on
|
|
7
|
+
// that outcome so a run always contains repositories whose official result is
|
|
8
|
+
// not `passed`: for a corpus of n, ceil(n/8) needs-fixes, ceil(n/4)
|
|
9
|
+
// review-required, the rest passed, each stratum sampled by a fixed stride
|
|
10
|
+
// over the repositories sorted by URL. `offset` shifts every stratum.
|
|
11
|
+
|
|
12
|
+
import { readFileSync } from "node:fs"
|
|
13
|
+
import { join } from "node:path"
|
|
14
|
+
|
|
15
|
+
const STRATA = ["needs-fixes", "review-required", "passed"]
|
|
16
|
+
|
|
17
|
+
function registrySources(pinDir) {
|
|
18
|
+
const registry = JSON.parse(readFileSync(join(pinDir, "registry.json"), "utf8"))
|
|
19
|
+
const list = Array.isArray(registry.sources) ? registry.sources : Object.values(registry.sources)
|
|
20
|
+
return list
|
|
21
|
+
.filter((source) => typeof source?.repo === "string" && /^[a-f0-9]{40}$/i.test(source?.listingValidatedCommit || ""))
|
|
22
|
+
.map((source) => {
|
|
23
|
+
const recorded = source.automatedSecurityBaseline || null
|
|
24
|
+
return {
|
|
25
|
+
repo: source.repo,
|
|
26
|
+
commit: source.listingValidatedCommit.toLowerCase(),
|
|
27
|
+
type: source.type,
|
|
28
|
+
registryOutcome: recorded?.outcome || null,
|
|
29
|
+
registryOutcomeCommit: recorded?.commit ? String(recorded.commit).toLowerCase() : null,
|
|
30
|
+
registryBaselineVersion: recorded?.version || null,
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
.sort((a, b) => a.repo.localeCompare(b.repo))
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function strataSizes(count) {
|
|
37
|
+
const needsFixes = Math.ceil(count / 8)
|
|
38
|
+
const reviewRequired = Math.ceil(count / 4)
|
|
39
|
+
return { "needs-fixes": needsFixes, "review-required": reviewRequired, passed: Math.max(0, count - needsFixes - reviewRequired) }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function sample(list, count, offset) {
|
|
43
|
+
if (count <= 0 || list.length === 0) return []
|
|
44
|
+
const step = Math.max(1, Math.floor(list.length / count))
|
|
45
|
+
const picked = []
|
|
46
|
+
for (let i = offset % Math.max(1, list.length); picked.length < count && picked.length < list.length; i = (i + step) % list.length) {
|
|
47
|
+
if (picked.includes(list[i])) break
|
|
48
|
+
picked.push(list[i])
|
|
49
|
+
}
|
|
50
|
+
return picked
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function parityCorpus(pinDir, count = 30, offset = 0) {
|
|
54
|
+
const sources = registrySources(pinDir)
|
|
55
|
+
const sizes = strataSizes(count)
|
|
56
|
+
const picked = []
|
|
57
|
+
for (const stratum of STRATA) {
|
|
58
|
+
const pool = sources.filter((s) => s.registryOutcome === stratum)
|
|
59
|
+
picked.push(...sample(pool, sizes[stratum], offset))
|
|
60
|
+
}
|
|
61
|
+
return picked.sort((a, b) => a.repo.localeCompare(b.repo))
|
|
62
|
+
}
|