@arjunkhera/atlas 0.3.51 → 0.3.52
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/.claude-plugin/plugin.json +1 -1
- package/door/cli.mjs +3 -2
- package/door/lib/gate.mjs +40 -5
- package/package.json +1 -1
- package/skills/lead/SKILL.md +1 -1
package/door/cli.mjs
CHANGED
|
@@ -140,6 +140,7 @@ const HELP = `atlas — the door into a repo's Atlas files
|
|
|
140
140
|
On a GitHub plan with no rulesets, apply changes nothing and reports advisory mode.
|
|
141
141
|
atlas gate ready --repo <owner/name> --pr <n> may this pull request merge: every required check green on its head
|
|
142
142
|
atlas gate audit --repo <owner/name> [--since <date>] each merge since the date (default: one day) that came before its checks were green
|
|
143
|
+
atlas gate audit --repo <owner/name> --commit <sha> one commit on the main branch: red when no pull request merged it, or one merged it before its checks were green
|
|
143
144
|
|
|
144
145
|
atlas judge seal <tasks.md> the fresh-agent test: check the judge's six candidates, print the seal and the three that run
|
|
145
146
|
atlas judge brief <tasks.md> <id> print the exact words for one run: the task, then the report form
|
|
@@ -180,7 +181,7 @@ export const FLAGS = Object.freeze({
|
|
|
180
181
|
view: { product: 'value', name: 'value', out: 'value' },
|
|
181
182
|
tests: { root: 'optional', halves: 'value', evidence: 'value', 'guards-from': 'value', tests: 'value', 'dry-run': 'switch', run: 'value', own: 'value', base: 'value', head: 'value', list: 'value', side: 'value', old: 'value', new: 'value', covers: 'switch', findings: 'value', repo: 'value', max: 'value', bot: 'value', since: 'value', out: 'value', text: 'switch', json: 'switch', scenario: 'value', language: 'value' },
|
|
182
183
|
upkeep: { root: 'optional', event: 'value', json: 'switch' },
|
|
183
|
-
gate: { repo: 'value', root: 'optional', 'dry-run': 'switch', off: 'switch', on: 'switch', pr: 'value', since: 'value' },
|
|
184
|
+
gate: { repo: 'value', root: 'optional', 'dry-run': 'switch', off: 'switch', on: 'switch', pr: 'value', since: 'value', commit: 'value' },
|
|
184
185
|
judge: { tasks: 'value', verdict: 'value', seal: 'value', runs: 'value', out: 'value', repo: 'value', budget: 'value', model: 'value' },
|
|
185
186
|
install: { local: 'switch', from: 'value', 'skip-global': 'switch', yes: 'switch', cloud: 'switch' },
|
|
186
187
|
upgrade: { version: 'optional', yes: 'switch' },
|
|
@@ -417,7 +418,7 @@ function upkeepVerb(chosen) {
|
|
|
417
418
|
}
|
|
418
419
|
|
|
419
420
|
function gateVerb(chosen) {
|
|
420
|
-
return gateCommand({ what: chosen._[1], repo: chosen.repo, root: rootOf(chosen), dryRun: Boolean(chosen['dry-run']), off: Boolean(chosen.off), on: Boolean(chosen.on), pr: chosen.pr, since: chosen.since }, line);
|
|
421
|
+
return gateCommand({ what: chosen._[1], repo: chosen.repo, root: rootOf(chosen), dryRun: Boolean(chosen['dry-run']), off: Boolean(chosen.off), on: Boolean(chosen.on), pr: chosen.pr, since: chosen.since, commit: chosen.commit }, line);
|
|
421
422
|
}
|
|
422
423
|
|
|
423
424
|
function judgeVerb(chosen) {
|
package/door/lib/gate.mjs
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
// 2. "atlas release tags" on v* tags: no update, no delete.
|
|
7
7
|
// The bypass list stays empty. --off and --on are the break glass.
|
|
8
8
|
//
|
|
9
|
-
// A private repo on a free GitHub plan gets no rulesets
|
|
10
|
-
// 2026
|
|
9
|
+
// A private repo on a free GitHub plan gets no rulesets. The owner chose on 24
|
|
10
|
+
// October 2026 to stay on that plan (decision dd90d8e8). There the
|
|
11
11
|
// gate is advisory: apply changes nothing and says so, `atlas gate ready`
|
|
12
12
|
// says if one pull request may merge, and `atlas gate audit` names each merge
|
|
13
13
|
// that came before its checks were green (design docs/design-docs/gate-advisory/).
|
|
@@ -211,7 +211,8 @@ export function readyCommand({ repo, pr }, line, gh = ghApi) {
|
|
|
211
211
|
|
|
212
212
|
// `atlas gate audit --since <date>`: each pull request merged since the date
|
|
213
213
|
// whose required checks were not all green at the moment of the merge.
|
|
214
|
-
export function auditCommand({ repo, since }, line, gh = ghApi) {
|
|
214
|
+
export function auditCommand({ repo, since, commit }, line, gh = ghApi) {
|
|
215
|
+
if (commit !== undefined) return commitAudit({ repo, commit }, line, gh);
|
|
215
216
|
const from = since && since !== true ? since : new Date(Date.now() - 864e5).toISOString().slice(0, 10);
|
|
216
217
|
if (Number.isNaN(Date.parse(from))) throw new GateError(`--since must be a date, not "${from}".`);
|
|
217
218
|
const closed = gh('GET', `repos/${repo}/pulls?state=closed&sort=updated&direction=desc&per_page=100`) ?? [];
|
|
@@ -239,12 +240,46 @@ export function auditCommand({ repo, since }, line, gh = ghApi) {
|
|
|
239
240
|
return red ? 1 : 0;
|
|
240
241
|
}
|
|
241
242
|
|
|
243
|
+
// `atlas gate audit --commit <sha>`: one commit that reached the main branch.
|
|
244
|
+
// The push job runs it on each push. A commit is good when a pull request
|
|
245
|
+
// merged it after that pull request's required checks were green. A commit
|
|
246
|
+
// that no pull request merged was pushed past the gate, so it is red.
|
|
247
|
+
function commitAudit({ repo, commit }, line, gh) {
|
|
248
|
+
if (!commit || commit === true || !/^[0-9a-f]{7,40}$/i.test(String(commit))) throw new GateError('--commit needs a commit SHA.');
|
|
249
|
+
// GitHub expands a short SHA, and names the first parent: the main branch
|
|
250
|
+
// just before this commit, whose atlas.yaml held the gate at that moment.
|
|
251
|
+
const found = gh('GET', `repos/${repo}/commits/${commit}`);
|
|
252
|
+
const sha = found?.sha;
|
|
253
|
+
if (!sha) throw new GateError(`there is no commit ${commit} in ${repo}.`);
|
|
254
|
+
const pull = (gh('GET', `repos/${repo}/commits/${sha}/pulls`) ?? []).find((each) => each.merged_at && each.merge_commit_sha === sha);
|
|
255
|
+
if (!pull) {
|
|
256
|
+
line(`- ✗ ${sha.slice(0, 7)} reached the main branch with no pull request: a push past the gate.`);
|
|
257
|
+
line('RED PUSH: look at it now; the main branch may hold an untested change.');
|
|
258
|
+
return 1;
|
|
259
|
+
}
|
|
260
|
+
const parent = found.parents?.[0]?.sha ?? pull.base.sha;
|
|
261
|
+
let checks;
|
|
262
|
+
try { checks = checksAt(gh, repo, parent); } catch (error) {
|
|
263
|
+
if (!(error instanceof GateError)) throw error;
|
|
264
|
+
line(`- atlas gate audit: ${sha.slice(0, 7)} is the merge of #${pull.number}; atlas.yaml before it listed no required_checks, so nothing to audit.`);
|
|
265
|
+
return 0;
|
|
266
|
+
}
|
|
267
|
+
const bad = checkStates(checks, checkRuns(gh, repo, pull.head.sha), pull.merged_at).filter((row) => row.state !== 'green');
|
|
268
|
+
if (bad.length) {
|
|
269
|
+
line(`- ✗ #${pull.number} merged ${pull.merged_at} before its checks were green: ${bad.map((row) => `${row.name} ${row.state}`).join(', ')}`);
|
|
270
|
+
line('RED MERGES: 1. Look at it now; the main branch may hold an untested change.');
|
|
271
|
+
return 1;
|
|
272
|
+
}
|
|
273
|
+
line(`- atlas gate audit: ${sha.slice(0, 7)} is the merge of #${pull.number}, after its ${checks.length} required check(s) were green.`);
|
|
274
|
+
return 0;
|
|
275
|
+
}
|
|
276
|
+
|
|
242
277
|
// `atlas gate apply|ready|audit`. Returns the exit code.
|
|
243
|
-
export function gateCommand({ what, repo, root, dryRun = false, off = false, on = false, pr, since }, line, gh = ghApi) {
|
|
278
|
+
export function gateCommand({ what, repo, root, dryRun = false, off = false, on = false, pr, since, commit }, line, gh = ghApi) {
|
|
244
279
|
if (!['apply', 'ready', 'audit'].includes(what)) throw new GateError(`there is no gate verb "${what ?? ''}". Use apply, ready or audit.`);
|
|
245
280
|
if (!repo || repo === true || !/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(repo)) throw new GateError(`atlas gate ${what} needs --repo <owner/name>.`);
|
|
246
281
|
if (what === 'ready') return readyCommand({ repo, pr }, line, gh);
|
|
247
|
-
if (what === 'audit') return auditCommand({ repo, since }, line, gh);
|
|
282
|
+
if (what === 'audit') return auditCommand({ repo, since, commit }, line, gh);
|
|
248
283
|
if (off && on) throw new GateError('pick --off or --on, not both.');
|
|
249
284
|
const mode = off ? 'off' : on ? 'on' : 'apply';
|
|
250
285
|
const facts = mode === 'apply' ? gateFacts(root) : null;
|
package/package.json
CHANGED
package/skills/lead/SKILL.md
CHANGED
|
@@ -105,7 +105,7 @@ set. A test keeps the two lists equal.
|
|
|
105
105
|
| `atlas design` | `folder` to learn where designs live; `check` before you show a design; `build` to make its page |
|
|
106
106
|
| `atlas view` | `build --product <id>` makes the project view page of one product, when the owner asks for it or after an Atlas release changes it. Publish it with only the grant the command prints |
|
|
107
107
|
| `atlas upkeep` | `check` before you ask for a merge: the docs index, dead doc links, and the tracker item a pull request names. The daily upkeep run calls it on the main branch |
|
|
108
|
-
| `atlas gate` | `apply` once per repo, by the owner on his Mac, after the repo's `required_checks` exist. `--dry-run` first. `--off` and `--on` are the break glass. On a plan with no rulesets it reports advisory mode. `ready` before each merge. `audit` in the daily upkeep run |
|
|
108
|
+
| `atlas gate` | `apply` once per repo, by the owner on his Mac, after the repo's `required_checks` exist. `--dry-run` first. `--off` and `--on` are the break glass. On a plan with no rulesets it reports advisory mode. `ready` before each merge. `audit` in the daily upkeep run, and with `--commit` in the push job of a repo that has one |
|
|
109
109
|
| `atlas judge` | In the fresh-agent test only, as the `atlas:fresh-agent-test` skill says. `seal` after the pick, `brief` to read a sealed ask, `run` for each sealed task, `check` after the grade |
|
|
110
110
|
|
|
111
111
|
A person merges every file that `atlas tooling` writes.
|