@arjunkhera/atlas 0.3.7 → 0.3.9
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/agents/artifact-renderer.md +22 -22
- package/agents/verifier.md +29 -0
- package/door/cli.mjs +62 -12
- package/door/kit-releases.json +4 -0
- package/door/lib/design-build.mjs +409 -0
- package/door/lib/design.mjs +199 -118
- package/door/lib/markdown.mjs +160 -0
- package/door/lib/proof.mjs +127 -0
- package/door/lib/tests.mjs +190 -0
- package/package.json +2 -1
- package/skills/lead/SKILL.md +4 -1
- package/skills/sdlc-task/SKILL.md +33 -24
- package/skills/sdlc-task/design/README.md +187 -0
- package/skills/sdlc-task/design/parts/actors.md +26 -0
- package/skills/sdlc-task/design/parts/alternatives.md +24 -0
- package/skills/sdlc-task/design/parts/build.md +23 -0
- package/skills/sdlc-task/design/parts/calls.md +25 -0
- package/skills/sdlc-task/design/parts/change.md +27 -0
- package/skills/sdlc-task/design/parts/data.md +22 -0
- package/skills/sdlc-task/design/parts/done.md +23 -0
- package/skills/sdlc-task/design/parts/edges.md +24 -0
- package/skills/sdlc-task/design/parts/goals.md +27 -0
- package/skills/sdlc-task/design/parts/key.md +25 -0
- package/skills/sdlc-task/design/parts/migration.md +22 -0
- package/skills/sdlc-task/design/parts/order.md +24 -0
- package/skills/sdlc-task/design/parts/problem.md +22 -0
- package/skills/sdlc-task/design/parts/proof.md +24 -0
- package/skills/sdlc-task/design/parts/proposal.md +24 -0
- package/skills/sdlc-task/design/parts/records.md +24 -0
- package/skills/sdlc-task/design/parts/repos.md +25 -0
- package/skills/sdlc-task/design/parts/risks.md +24 -0
- package/skills/sdlc-task/design/parts/rollout.md +24 -0
- package/skills/sdlc-task/design/parts/routes.md +24 -0
- package/skills/sdlc-task/design/parts/scorecard.md +25 -0
- package/skills/sdlc-task/design/parts/security.md +22 -0
- package/skills/sdlc-task/design/parts/shared-decisions.md +24 -0
- package/skills/sdlc-task/design/parts/states.md +25 -0
- package/skills/sdlc-task/design/parts/stories.md +26 -0
- package/skills/sdlc-task/design/parts/summary.md +33 -0
- package/skills/sdlc-task/design/parts/why.md +22 -0
- package/skills/sdlc-task/design/parts/words.md +29 -0
- package/skills/sdlc-task/design/parts/yardstick.md +25 -0
- package/skills/sdlc-task/design/parts.yaml +306 -0
- package/skills/sdlc-task/lifecycle.yaml +2 -2
- package/skills/tests/SKILL.md +234 -0
- package/tests/contract.mjs +398 -0
- package/tests/drivers/function.mjs +30 -0
- package/tests/drivers/http.mjs +68 -0
- package/tests/drivers/index.mjs +65 -0
- package/tests/drivers/mcp-stdio.mjs +174 -0
- package/tests/environment.mjs +227 -0
- package/tests/errors.mjs +27 -0
- package/tests/evidence.mjs +113 -0
- package/tests/fresh.mjs +42 -0
- package/tests/guards.mjs +159 -0
- package/tests/index.mjs +11 -0
- package/tests/link-check.mjs +576 -0
- package/tests/procs.mjs +43 -0
- package/tests/redact.mjs +58 -0
- package/tests/scenario.mjs +325 -0
- package/tests/stand-in.mjs +74 -0
- package/tests/tests-yaml.mjs +258 -0
- package/tests/wait.mjs +44 -0
- package/tests/yaml.mjs +327 -0
- package/agents/artifact-format/walkthrough.html +0 -706
- package/skills/sdlc-task/templates/design-doc.md +0 -126
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
name: artifact-renderer
|
|
3
3
|
description: >
|
|
4
4
|
Dedicated Sonnet subagent that renders a design doc, PRD, review, or task explainer into
|
|
5
|
-
the owner-ratified HTML artifact treatment
|
|
6
|
-
Claude-website family, written for a smart newcomer ("assume like a fresher"), diagram-rich,
|
|
5
|
+
the owner-ratified HTML artifact treatment (one light theme in the
|
|
6
|
+
Claude-website family), or draws one custom figure for a design part, written for a smart newcomer ("assume like a fresher"), diagram-rich,
|
|
7
7
|
with every stable id backlinked to its definition. Invoked by the sdlc-task design loop and
|
|
8
8
|
any session presenting a design/task/review to the owner — rendering is mechanical work and
|
|
9
9
|
runs on Sonnet (sdlc-task skill, "Model tiering"). Input: a repo markdown doc path (+ optional emphasis
|
|
@@ -23,26 +23,26 @@ itself carries). Write the finished HTML to the output path the caller names, an
|
|
|
23
23
|
return only a one-paragraph summary of what you rendered (sections, diagram count,
|
|
24
24
|
any content you had to omit and why).
|
|
25
25
|
|
|
26
|
-
##
|
|
27
|
-
|
|
28
|
-
**A design
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
26
|
+
## Designs: figures only. Every other doc: an Organic page
|
|
27
|
+
|
|
28
|
+
**A design is a folder** with `design.yaml` and one file for each part.
|
|
29
|
+
`atlas design build <folder>` builds its page, with the rail, the bars, the
|
|
30
|
+
keys and both themes. You never build a design's page by hand.
|
|
31
|
+
|
|
32
|
+
For a design, the caller asks you for **one custom figure** for one part:
|
|
33
|
+
git lanes, a time line, a scorecard or a data diff. Write it as HTML inside a
|
|
34
|
+
fenced block with the info string `figure`, and return the block. The rules
|
|
35
|
+
are in `${CLAUDE_PLUGIN_ROOT}/skills/sdlc-task/design/README.md`, under
|
|
36
|
+
"Figures":
|
|
37
|
+
|
|
38
|
+
- Use the page tokens, such as `var(--accent)`, `var(--line)` and
|
|
39
|
+
`var(--card)`, so the figure works in the light and the dark theme. Never
|
|
40
|
+
write a colour with no token.
|
|
41
|
+
- A step has a title and one or two sentences. The reader sets the pace.
|
|
42
|
+
The figure prints as stills, and it works with its script removed.
|
|
43
|
+
- Meaning is never by colour alone.
|
|
44
|
+
- Close every tag. `atlas design check <folder>` flags a figure that does
|
|
45
|
+
not.
|
|
46
46
|
|
|
47
47
|
**Every other doc** (an older design, a PRD, a review, a task explainer)
|
|
48
48
|
renders in the Organic page format below.
|
package/agents/verifier.md
CHANGED
|
@@ -76,6 +76,35 @@ Verified at <the head commit>, in a fresh worktree.
|
|
|
76
76
|
Links made for this run: <none, or each ignored file linked>.
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
+
## Scenario proofs
|
|
80
|
+
|
|
81
|
+
Use this section when the definition of done names scenario assertions,
|
|
82
|
+
such as `week-conflict/e3#a1b2c3`. The steps above still apply. These steps
|
|
83
|
+
replace step 2 for those lines.
|
|
84
|
+
|
|
85
|
+
1. Make a fresh worktree of the branch, as in the steps above.
|
|
86
|
+
2. Start the product from `atlas/tests.yaml` with run secrets. The kit in
|
|
87
|
+
`<area>/test/atlas/` does this when the scenarios run. Set `ATLAS_GUARDS_FROM`
|
|
88
|
+
to `atlas/tests.yaml` of the main branch. A scenario that needs a provided
|
|
89
|
+
secret follows the rules of the section "Ignored files and secrets".
|
|
90
|
+
3. Run the scenarios that the line names, with the runner command of `tests.yaml`.
|
|
91
|
+
Note the run id. Evidence goes to `<area>/test/evidence/<run id>/`.
|
|
92
|
+
4. For each named assertion, make your own check through a raw driver of
|
|
93
|
+
the kit (`test/atlas/drivers/`). Do not use the actions of the repo or its tests.
|
|
94
|
+
Write a short script in your scratch folder. It starts the environment, sends the
|
|
95
|
+
calls of the assertion, and reads the answers. Keep the answer that proves the result.
|
|
96
|
+
5. Write the `--own` file in your scratch folder. It is a JSON object with one
|
|
97
|
+
entry for each assertion: `{ "week-conflict/e3": { "result": "pass", "proof": "refused, revision 2" } }`.
|
|
98
|
+
6. Print the table with `atlas tests proof`. Give it `--root` for the area,
|
|
99
|
+
`--run` for the run id, and `--own` for your file.
|
|
100
|
+
Put the table under the heading of the proof comment. A blocked or failed way
|
|
101
|
+
in shows its reason in the table.
|
|
102
|
+
7. Run the privacy check on the comment, and post it, as the steps above say.
|
|
103
|
+
In a cloud session `gh pr comment` may be blocked. Then do not retry.
|
|
104
|
+
Return the path of the comment file to the caller. The caller posts it.
|
|
105
|
+
8. A line is PASS only when the run and your own check both pass. If they
|
|
106
|
+
differ, mark the line FAIL and show both results.
|
|
107
|
+
|
|
79
108
|
## Never-read and never-quote paths (rules in `${CLAUDE_PLUGIN_ROOT}/work/protected-paths.json`)
|
|
80
109
|
|
|
81
110
|
These deny rules bind every sub-agent that reads a repo.
|
package/door/cli.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// The atlas command: install, upgrade, doctor, check, status, the tooling
|
|
3
|
-
// writer, the kind drift report, the code-read resolver, the STE check
|
|
4
|
-
// the
|
|
3
|
+
// writer, the kind drift report, the code-read resolver, the STE check, the
|
|
4
|
+
// design check and page builder, and the tests verbs (the link check and the
|
|
5
|
+
// test kit writer).
|
|
5
6
|
//
|
|
6
7
|
// Stage 1 of the target design retired `setup`, `change`, `helpers` and
|
|
7
8
|
// `test onboarding`: code that guesses meaning retires (decided 28
|
|
@@ -10,7 +11,7 @@
|
|
|
10
11
|
//
|
|
11
12
|
// Nothing here writes to the work graph, and nothing here merges. A person
|
|
12
13
|
// merges every file the tooling writer writes, because both steer agents.
|
|
13
|
-
import { resolve, join, dirname } from 'node:path';
|
|
14
|
+
import { resolve, join, dirname, basename } from 'node:path';
|
|
14
15
|
import { fileURLToPath } from 'node:url';
|
|
15
16
|
import { readFileSync, existsSync, realpathSync } from 'node:fs';
|
|
16
17
|
import { spawnSync } from 'node:child_process';
|
|
@@ -22,8 +23,11 @@ import { scan, toText, verdict, CHECK_VERSION, SPECS } from '../shape/check.mjs'
|
|
|
22
23
|
import { packagePackageVersion } from './lib/releases.mjs';
|
|
23
24
|
import { install, upgrade, doctor } from './lib/install.mjs';
|
|
24
25
|
import { checkPaths, LIMITS } from './lib/ste.mjs';
|
|
25
|
-
import {
|
|
26
|
+
import { checkDesignFolder } from './lib/design.mjs';
|
|
27
|
+
import { writeDesignPage, readTracker } from './lib/design-build.mjs';
|
|
26
28
|
import { loadPrivateTerms } from './lib/privacy.mjs';
|
|
29
|
+
import { checkCommand as testsCheck, writeCommand as testsWrite } from './lib/tests.mjs';
|
|
30
|
+
import { proofCommand as testsProof } from './lib/proof.mjs';
|
|
27
31
|
|
|
28
32
|
export const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
29
33
|
const ATLAS_VERSION = packagePackageVersion(PACKAGE_ROOT);
|
|
@@ -44,7 +48,21 @@ const HELP = `atlas — the door into a repo's Atlas files
|
|
|
44
48
|
atlas ste <file or folder> … measure markdown and HTML against the STE limits
|
|
45
49
|
--share also run the privacy filter, quotes included
|
|
46
50
|
--terms <file> private terms; default ~/.config/atlas/private-terms.txt
|
|
47
|
-
atlas design <
|
|
51
|
+
atlas design check <folder> … check a design folder: each needed part, no state line, every code in the Key
|
|
52
|
+
atlas design build <folder> build the design's page from its folder
|
|
53
|
+
--tracker <file> the tracker data, as JSON, from the lead
|
|
54
|
+
--out <file> the page; default docs/artifacts/<folder name>.html
|
|
55
|
+
--draft build even when the check has findings, and mark the page a draft
|
|
56
|
+
|
|
57
|
+
atlas tests check --root <area> run the link check on the tests of an area
|
|
58
|
+
--halves <list> static, lint, run; default all three
|
|
59
|
+
--evidence <dir> where the evidence files are; default <area>/test/evidence
|
|
60
|
+
--guards-from <file> tests.yaml of the main branch; a changed guard part is a finding
|
|
61
|
+
--run <id> read the evidence of this run only; default the newest run
|
|
62
|
+
atlas tests write --root <area> copy the shipped test kit into <area>/test/atlas/
|
|
63
|
+
atlas tests proof --root <area> print the proof table of one run, one row for each assertion
|
|
64
|
+
--run <id> the run; default the newest run in the evidence folder
|
|
65
|
+
--own <file> JSON of the verifier's own checks: { id: { result, proof } }
|
|
48
66
|
|
|
49
67
|
atlas install install Atlas for every folder on this Mac
|
|
50
68
|
atlas upgrade [--version <v>] check, show and install a newer release
|
|
@@ -70,7 +88,8 @@ export const FLAGS = Object.freeze({
|
|
|
70
88
|
'kind-drift': { root: 'optional', 'record-kind': 'value', registry: 'value', repo: 'value' },
|
|
71
89
|
check: { root: 'optional', repo: 'value', 'fail-on': 'value' },
|
|
72
90
|
ste: { share: 'switch', terms: 'value' },
|
|
73
|
-
design: {},
|
|
91
|
+
design: { tracker: 'value', out: 'value', draft: 'switch' },
|
|
92
|
+
tests: { root: 'optional', halves: 'value', evidence: 'value', 'guards-from': 'value', tests: 'value', 'dry-run': 'switch', run: 'value', own: 'value' },
|
|
74
93
|
install: { local: 'switch', from: 'value', 'skip-global': 'switch', yes: 'switch' },
|
|
75
94
|
upgrade: { version: 'optional', yes: 'switch' },
|
|
76
95
|
doctor: {},
|
|
@@ -208,18 +227,48 @@ function steCommand(chosen) {
|
|
|
208
227
|
}
|
|
209
228
|
|
|
210
229
|
function designCommand(chosen) {
|
|
211
|
-
const
|
|
212
|
-
|
|
230
|
+
const what = chosen._[1];
|
|
231
|
+
const folders = chosen._.slice(2);
|
|
232
|
+
if (what !== 'check' && what !== 'build') throw new Error('use atlas design check <folder> or atlas design build <folder>');
|
|
233
|
+
if (!folders.length) throw new Error(`give a design folder: atlas design ${what} <folder>`);
|
|
234
|
+
if (what === 'check' && (chosen.tracker !== undefined || chosen.out !== undefined || chosen.draft)) throw new Error('--tracker, --out and --draft work only with atlas design build.');
|
|
235
|
+
if (what === 'build') {
|
|
236
|
+
if (folders.length > 1) throw new Error('atlas design build takes one folder.');
|
|
237
|
+
const folder = resolve(folders[0]);
|
|
238
|
+
const out = resolve(chosen.out ?? join('docs', 'artifacts', `${basename(folder)}.html`));
|
|
239
|
+
const tracker = chosen.tracker !== undefined ? readTracker(resolve(chosen.tracker)) : null;
|
|
240
|
+
const result = writeDesignPage(folder, out, { tracker, draft: Boolean(chosen.draft) });
|
|
241
|
+
if (!result.html) {
|
|
242
|
+
for (const finding of result.findings) line(`${join(folders[0], finding.file)}:${finding.line} ${finding.rule} ${finding.why}`);
|
|
243
|
+
line('');
|
|
244
|
+
line(`No page written: the check has ${result.findings.length} finding(s). Fix them, or build a draft with --draft.`);
|
|
245
|
+
return 1;
|
|
246
|
+
}
|
|
247
|
+
line(`Wrote ${out}: ${result.parts} parts, ${result.groups} groups, ${result.figures} figure(s).${tracker ? '' : ' No tracker data: the tracker parts say so.'}`);
|
|
248
|
+
if (result.findings.length) line(`A draft: the check has ${result.findings.length} finding(s). Run atlas design check ${folders[0]}.`);
|
|
249
|
+
return 0;
|
|
250
|
+
}
|
|
213
251
|
let count = 0;
|
|
214
|
-
for (const
|
|
215
|
-
for (const finding of
|
|
252
|
+
for (const folder of folders) {
|
|
253
|
+
for (const finding of checkDesignFolder(resolve(folder))) { count += 1; line(`${join(folder, finding.file)}:${finding.line} ${finding.rule} ${finding.why}`); }
|
|
216
254
|
}
|
|
217
255
|
line('');
|
|
218
|
-
line(`${
|
|
219
|
-
line(count ? 'Fix the
|
|
256
|
+
line(`${folders.length} design(s) read; ${count} finding(s). The parts each kind needs are in skills/sdlc-task/design/parts.yaml.`);
|
|
257
|
+
line(count ? 'Fix the design by hand. This check never rewrites.' : 'GREEN');
|
|
220
258
|
return count ? 1 : 0;
|
|
221
259
|
}
|
|
222
260
|
|
|
261
|
+
function testsCommand(chosen) {
|
|
262
|
+
const root = rootOf(chosen);
|
|
263
|
+
const what = chosen._[1];
|
|
264
|
+
if (what === 'check') {
|
|
265
|
+
return testsCheck({ halves: chosen.halves, evidence: chosen.evidence, tests: chosen.tests, guardsFrom: chosen['guards-from'], run: chosen.run }, root, line, PACKAGE_ROOT);
|
|
266
|
+
}
|
|
267
|
+
if (what === 'write') return testsWrite({ dryRun: Boolean(chosen['dry-run']) }, root, PACKAGE_ROOT, line);
|
|
268
|
+
if (what === 'proof') return testsProof({ run: chosen.run, own: chosen.own, evidence: chosen.evidence }, root, line);
|
|
269
|
+
throw new Error(`there is no tests verb "${what ?? ''}". Use check, write or proof.`);
|
|
270
|
+
}
|
|
271
|
+
|
|
223
272
|
function checkCommand(chosen) {
|
|
224
273
|
const root = rootOf(chosen);
|
|
225
274
|
const report = scan({ root, repoId: chosen.repo ?? null });
|
|
@@ -250,6 +299,7 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
250
299
|
case 'check': return checkCommand(chosen);
|
|
251
300
|
case 'ste': return steCommand(chosen);
|
|
252
301
|
case 'design': return designCommand(chosen);
|
|
302
|
+
case 'tests': return testsCommand(chosen);
|
|
253
303
|
default: throw new Error(`there is no verb "${command}". Run "atlas help".`);
|
|
254
304
|
}
|
|
255
305
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
{
|
|
2
|
+
"note": "Every kit of the folder tests/ that a release of Atlas shipped, as the kit hash of its manifest (the sha256 of the sorted lines of path and file hash). The kit of this package is always accepted and need not be listed. When a release changes anything in tests/, add the kit hash of the release before it here. atlas tests check reads this list; git history is never read.",
|
|
3
|
+
"releases": []
|
|
4
|
+
}
|