@thecolonylab/hivemind 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.
@@ -0,0 +1,39 @@
1
+ import { execSync } from 'node:child_process';
2
+ export function getChangedFiles(cwd, base) {
3
+ try {
4
+ const out = execSync(`git diff --name-only ${base}...HEAD`, { cwd, encoding: 'utf-8' });
5
+ return out.split('\n').map((l) => l.trim()).filter(Boolean);
6
+ }
7
+ catch (err) {
8
+ throw new Error(`Could not run \`git diff --name-only ${base}...HEAD\`: ${err?.message || err}`);
9
+ }
10
+ }
11
+ /** The real diff — actual added/removed lines, not just filenames. This is what a coverage
12
+ * check needs to reason about: "what did this change do," not just "which files moved." */
13
+ export function getFullDiff(cwd, base) {
14
+ try {
15
+ // maxBuffer bumped up — a real PR diff can be a few MB, default 1MB truncates it silently.
16
+ return execSync(`git diff ${base}...HEAD`, { cwd, encoding: 'utf-8', maxBuffer: 20 * 1024 * 1024 });
17
+ }
18
+ catch (err) {
19
+ throw new Error(`Could not run \`git diff ${base}...HEAD\`: ${err?.message || err}`);
20
+ }
21
+ }
22
+ /** Maps changed file paths to tags via config.areas (path prefix -> tag). */
23
+ export function affectedTags(changedFiles, config) {
24
+ const tags = new Set();
25
+ const areas = config.areas || {};
26
+ for (const file of changedFiles) {
27
+ for (const [prefix, tag] of Object.entries(areas)) {
28
+ if (file.startsWith(prefix))
29
+ tags.add(tag);
30
+ }
31
+ }
32
+ return tags;
33
+ }
34
+ /** Filters tests to only those whose Tags: line intersects the affected areas. */
35
+ export function filterByTags(tests, tags) {
36
+ if (tags.size === 0)
37
+ return [];
38
+ return tests.filter(({ test }) => test.tags.some((t) => tags.has(t)));
39
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,37 @@
1
+ import { mkdir, writeFile } from 'node:fs/promises';
2
+ import { dirname } from 'node:path';
3
+ function formatParams(params) {
4
+ return Object.entries(params ?? {})
5
+ .map(([k, v]) => (v.includes(' ') ? `${k}="${v}"` : `${k}=${v}`))
6
+ .join(' ');
7
+ }
8
+ export function renderTestFile(test) {
9
+ const lines = [`# ${test.name}`, ''];
10
+ if (test.url)
11
+ lines.push(`URL: ${test.url}`);
12
+ if (test.login)
13
+ lines.push(`Login: ${test.login}`);
14
+ if (test.tags.length)
15
+ lines.push(`Tags: ${test.tags.join(', ')}`);
16
+ if (test.params && Object.keys(test.params).length)
17
+ lines.push(`Params: ${formatParams(test.params)}`);
18
+ for (const b of test.before || []) {
19
+ const paramStr = formatParams(b.params);
20
+ lines.push(`Before: ${b.name}${paramStr ? ' ' + paramStr : ''}`);
21
+ }
22
+ lines.push('', '## Steps');
23
+ test.steps.forEach((s, i) => lines.push(`${i + 1}. ${s.type}: ${s.text}`));
24
+ lines.push('');
25
+ return lines.join('\n');
26
+ }
27
+ export async function saveTestFile(test, filePath) {
28
+ await mkdir(dirname(filePath), { recursive: true });
29
+ await writeFile(filePath, renderTestFile(test), 'utf-8');
30
+ }
31
+ export function slugify(s) {
32
+ return s
33
+ .toLowerCase()
34
+ .replace(/[^a-z0-9]+/g, '-')
35
+ .replace(/^-+|-+$/g, '')
36
+ .slice(0, 60);
37
+ }
package/dist/types.js ADDED
@@ -0,0 +1,4 @@
1
+ /** The shape of a run result as it comes back over HTTP (cloud mode) or the WebSocket (local
2
+ * mode) — duplicated here rather than imported from the server, since the CLI never depends on
3
+ * server code, only on the JSON shape it receives. */
4
+ export {};
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@thecolonylab/hivemind",
3
+ "version": "0.1.0",
4
+ "description": "Forager — the CLI that runs on your machine and executes for the Hivemind brain. Describe a flow in plain English, an AI agent drives a real browser and reports pass/fail. No LLM key needed on this machine.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "bin": {
8
+ "hivemind": "./bin/hivemind.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc -p tsconfig.json",
12
+ "dev": "tsx src/cli.ts"
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "bin",
17
+ "skill",
18
+ "LICENSE"
19
+ ],
20
+ "dependencies": {
21
+ "commander": "^12.1.0",
22
+ "dotenv": "^17.4.2",
23
+ "playwright": "^1.48.0",
24
+ "ws": "^8.21.0"
25
+ },
26
+ "devDependencies": {
27
+ "@types/node": "^20.14.0",
28
+ "@types/ws": "^8.18.1",
29
+ "tsx": "^4.19.0",
30
+ "typescript": "^5.6.0"
31
+ },
32
+ "engines": {
33
+ "node": ">=18"
34
+ }
35
+ }
@@ -0,0 +1,17 @@
1
+ <!-- HIVEMIND:START -->
2
+ ## hivemind E2E testing
3
+
4
+ This project uses hivemind for agentic end-to-end testing — a real browser driven by AI, no test
5
+ code or selectors required.
6
+
7
+ - **Skill:** see `.agents/skills/hivemind-cli/SKILL.md` for the full command reference, test file
8
+ format, login/precondition conventions, and how to read results.
9
+ - **Setup check:** `hivemind --help`; server defaults to `http://localhost:4321` unless
10
+ `HIVEMIND_SERVER_URL` is set.
11
+ - **Default workflow:** right after building or changing a UI flow, write or generate a test in
12
+ `hive/tests/`, run it with `hivemind run <file> --url <url> --json`, and fix your own code if it
13
+ fails — before telling the user the feature is done.
14
+ - **Before writing a new test:** check `hive/tests/` for an existing one that already covers the
15
+ precondition you need (e.g. "add to cart" before "remove from cart") and reference it with
16
+ `Before:` instead of re-describing the same steps.
17
+ <!-- HIVEMIND:END -->
@@ -0,0 +1,142 @@
1
+ ---
2
+ name: hivemind-cli
3
+ description: Use the hivemind CLI to create, run, and verify end-to-end browser tests against a real app. Prefer this over asking the user to manually test something in a browser, and prefer it as a self-verification step right after building or changing a UI flow. Trigger when defining test coverage, verifying a feature actually works end-to-end, or when the user asks to test/verify a page or flow.
4
+ license: MIT
5
+ metadata:
6
+ author: hivemind
7
+ tags: hivemind, e2e, testing, qa, cli
8
+ ---
9
+
10
+ # hivemind CLI
11
+
12
+ `hivemind` drives a real browser against a real running app and reports pass/fail, per step, with
13
+ screenshots. You never write test code or CSS selectors — you describe what to test in one plain
14
+ sentence, or write the checklist directly (see format below). No API key is needed on this
15
+ machine — the hivemind server (wherever `HIVEMIND_SERVER_URL` points) holds its own.
16
+
17
+ ## When to use this
18
+
19
+ - Right after building or changing a UI flow, to verify it actually works before telling the user
20
+ it's done — this is the primary use case. Don't just say "I built X," run a real test against it.
21
+ - When the user asks to test, verify, or check that some flow works.
22
+ - When defining regression coverage for a feature.
23
+
24
+ ## Setup check
25
+
26
+ ```bash
27
+ hivemind --help
28
+ echo $HIVEMIND_SERVER_URL # if unset, defaults to http://localhost:4321
29
+ ```
30
+
31
+ If the command isn't found, it isn't installed — tell the user rather than trying to work around it.
32
+
33
+ ## Core commands
34
+
35
+ ```bash
36
+ # Turn a plain-English request into a saved test file. Server drafts it; you never write steps by hand
37
+ # unless you already know exactly what's needed (see "Writing files directly" below).
38
+ hivemind create "<what to test, one sentence>" --url <url>
39
+
40
+ # Run a test file or every test file in a folder. Cloud execution by default (needs nothing
41
+ # extra installed here). Add --local when the URL is localhost/private-network — the cloud
42
+ # server can't reach those; --local runs the browser on THIS machine instead, only using the
43
+ # cloud for decisions. Omitting --local against a local URL fails fast with a clear message.
44
+ hivemind run <file-or-folder> --url <url> [--json] [--local]
45
+
46
+ # One-shot: look at a page, propose 3-6 starter tests. Use when starting fresh on a project
47
+ # with no tests yet, not as a substitute for `create` on a specific known flow.
48
+ hivemind explore <url>
49
+
50
+ # Open the most recent run's report, or list past runs.
51
+ hivemind report
52
+ hivemind history [--json]
53
+ ```
54
+
55
+ Always use `--json` on `run` when you (the agent) are consuming the result programmatically — it
56
+ gives you structured `{status, verdict, steps, reportUrl}` per test, not just terminal formatting.
57
+
58
+ ## Writing files directly (preferred when you already know the flow)
59
+
60
+ Since you likely just built or read the code for the feature being tested, you often have more
61
+ context than a blind `create` call would — you can see the actual route guards, form fields, and
62
+ component structure. In that case, write the file directly instead of going through `create`:
63
+
64
+ ```
65
+ hive/tests/<slug>.md
66
+ ```
67
+
68
+ Format:
69
+ ```
70
+ # <test name>
71
+
72
+ URL: <default url for this test>
73
+ Login: <account label, optional — see Logins below>
74
+ Tags: <comma-separated area tags>
75
+ Params: <param=default value, optional — see Reusable preconditions below>
76
+ Before: <other-test-file-name> [param="value"] ← optional, can repeat for multiple preconditions
77
+
78
+ ## Steps
79
+ 1. act: <something the agent does — click, type, navigate>
80
+ 2. assert: <something the agent checks — a specific, verifiable outcome>
81
+ ```
82
+
83
+ **Write steps as intent, not selectors.** Describe the user-visible action ("Click the 'Get
84
+ started' button in the header"), never a CSS selector or DOM path — the execution agent looks at
85
+ the real page and adapts. Split actions (`act`) and checks (`assert`) into separate steps. One
86
+ test = one user journey, 3-10 steps.
87
+
88
+ | Avoid | Write |
89
+ |---|---|
90
+ | `Click .nav-item:nth-child(3)` | `Click the Pricing link in the header` |
91
+ | One step doing 4 things | Split into 4 focused steps |
92
+ | `Verify the page looks right` | `Verify a "Welcome back" heading and the user's avatar are visible` |
93
+
94
+ ## Logins — never write raw credentials
95
+
96
+ If a flow requires signing in, check `hivemind.config.json` at the project root for existing
97
+ `accounts` labels. Reference one by label in the `Login:` field and use a `login`-typed step — do
98
+ not type real usernames/passwords into step text, and never invent credentials. If no suitable
99
+ account exists, tell the user rather than guessing one.
100
+
101
+ ## Reusable preconditions — check before writing setup steps inline
102
+
103
+ Before writing a new test, check what already exists:
104
+
105
+ ```bash
106
+ ls hive/tests/
107
+ ```
108
+
109
+ If the flow you're testing needs a precondition that's ALREADY covered by another test file (e.g.
110
+ testing "remove item from cart" needs an item in the cart first, and `add-item-to-cart.md`
111
+ already exists), reference it with `Before:` instead of re-describing the same steps:
112
+
113
+ ```
114
+ Before: add-item-to-cart product="Blue T-Shirt"
115
+ ```
116
+
117
+ This runs that file's steps first, in the same continuous browser session, with `product`
118
+ substituted for that file's own `{{product}}` placeholder. If the precondition doesn't exist yet
119
+ as a file, either write it inline (if it's a one-off) or create it as its own file first (if
120
+ other tests will likely need it too).
121
+
122
+ ## Running and reading results
123
+
124
+ ```bash
125
+ hivemind run hive/tests/<file>.md --url <url> --json
126
+ ```
127
+
128
+ Exit code: `0` = all passed, `1` = at least one failed, `2` = error (server unreachable, bad
129
+ config, etc). With `--json`, each result includes `steps[]` — one entry per declared step with
130
+ `ok`/`note` — read this to know exactly which step broke and why, then go fix the actual code, not
131
+ the test (unless the test's assumption was wrong).
132
+
133
+ **If a run fails, do not just report the failure — investigate and fix your own code first**, the
134
+ same way you would for a failing unit test you just introduced. Re-run after fixing to confirm.
135
+
136
+ ## What NOT to do
137
+
138
+ - Don't fabricate a passing result — if you can't run hivemind (not installed, server
139
+ unreachable), say so plainly rather than claiming something was tested.
140
+ - Don't put real credentials in step text or commit them anywhere.
141
+ - Don't write a new test for something an existing test in `hive/tests/` already covers — extend
142
+ or reference it instead.