@theagilemonkeys/facility 0.11.4 → 0.12.1
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/README.md +61 -47
- package/package.json +3 -4
- package/src/cli.mjs +27 -176
- package/src/detect.mjs +24 -94
- package/src/doctor.mjs +54 -559
- package/src/init.mjs +92 -535
- package/templates/agents/address-review.md +53 -0
- package/templates/agents/architect.md +50 -0
- package/templates/agents/builder.md +58 -0
- package/templates/agents/ci-doctor.md +55 -0
- package/templates/agents/pr-reviewer.md +52 -0
- package/templates/agents/security-audit.md +54 -0
- package/modules/README.md +0 -35
- package/modules/ai-queryability/agents/queryability-reviewer.md +0 -35
- package/modules/ai-queryability/module.json +0 -9
- package/modules/ai-queryability/standard-section.md +0 -22
- package/modules/analytics/agents/analytics-reviewer.md +0 -32
- package/modules/analytics/commands/add-telemetry.md +0 -23
- package/modules/analytics/module.json +0 -10
- package/modules/analytics/standard-section.md +0 -23
- package/modules/database/agents/data-security-reviewer.md +0 -38
- package/modules/database/commands/new-migration.md +0 -24
- package/modules/database/guards/migration-versions.mjs +0 -41
- package/modules/database/guards/migrations-immutable.mjs +0 -57
- package/modules/database/hooks/protect-migrations.fragment.mjs +0 -10
- package/modules/database/module.json +0 -25
- package/modules/database/standard-section.md +0 -20
- package/modules/design-system/agents/design-reviewer.md +0 -37
- package/modules/design-system/module.json +0 -9
- package/modules/design-system/standard-section.md +0 -15
- package/src/add.mjs +0 -77
- package/src/platform-admin.mjs +0 -1552
- package/src/platform-config.mjs +0 -39
- package/src/platform.mjs +0 -1759
- package/src/render.mjs +0 -66
- package/templates/claude/settings.json +0 -71
- package/templates/delivery/verify.mjs +0 -157
- package/templates/doctor/resolve.mjs +0 -572
- package/templates/guards/README.md +0 -30
- package/templates/guards/_kit.mjs +0 -81
- package/templates/guards/actions-pinned.mjs +0 -38
- package/templates/guards/run.mjs +0 -111
- package/templates/guards/watchtower-locked.mjs +0 -66
- package/templates/prompts/address-review.md +0 -14
- package/templates/prompts/architect.md +0 -63
- package/templates/prompts/builder.md +0 -79
- package/templates/prompts/doctor.md +0 -69
- package/templates/prompts/review.md +0 -14
- package/templates/prompts/sweep.md +0 -75
- package/templates/receipts/collect.mjs +0 -297
- package/templates/review/finalize.mjs +0 -38
- package/templates/scripts/move-board-status.sh +0 -155
- package/templates/security/sync-findings.mjs +0 -226
- package/templates/standard/STANDARD.md +0 -141
- package/templates/standard/agents-block.md +0 -25
- package/templates/watchtower/budgets.json +0 -12
- package/templates/watchtower/canary.mjs +0 -216
- package/templates/watchtower/health.mjs +0 -148
- package/templates/watchtower/outcomes.mjs +0 -188
- package/templates/workflows/facility-address-review.yml +0 -154
- package/templates/workflows/facility-canary.yml +0 -61
- package/templates/workflows/facility-codex.yml +0 -327
- package/templates/workflows/facility-crew.yml +0 -351
- package/templates/workflows/facility-doctor.yml +0 -174
- package/templates/workflows/facility-review.yml +0 -135
- package/templates/workflows/facility-security-sweep.yml +0 -204
- package/templates/workflows/facility-watchtower.yml +0 -87
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
// facility module: database
|
|
2
|
-
//
|
|
3
|
-
// Applied migrations are immutable. This guard fails when a commit range
|
|
4
|
-
// modifies or deletes an existing migration file instead of adding a new one.
|
|
5
|
-
// In CI it diffs against the PR base; locally it diffs against the merge-base
|
|
6
|
-
// with the default branch.
|
|
7
|
-
import { execFileSync } from "node:child_process";
|
|
8
|
-
|
|
9
|
-
// Directories that hold ordered migration files. Adjust to your stack.
|
|
10
|
-
const MIGRATION_DIRS = [
|
|
11
|
-
"migrations/",
|
|
12
|
-
"supabase/migrations/",
|
|
13
|
-
"db/migrations/",
|
|
14
|
-
"prisma/migrations/",
|
|
15
|
-
];
|
|
16
|
-
|
|
17
|
-
// key: "<path>", value: written reason (e.g. "squashed baseline, 2026-01").
|
|
18
|
-
const ALLOWLIST = {};
|
|
19
|
-
|
|
20
|
-
function git(args) {
|
|
21
|
-
try {
|
|
22
|
-
return execFileSync("git", args, {
|
|
23
|
-
encoding: "utf8",
|
|
24
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
25
|
-
}).trim();
|
|
26
|
-
} catch {
|
|
27
|
-
return "";
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export default {
|
|
32
|
-
name: "migrations-immutable",
|
|
33
|
-
description: "existing migration files are never edited or deleted, only added",
|
|
34
|
-
run() {
|
|
35
|
-
const base =
|
|
36
|
-
process.env.GITHUB_BASE_SHA ||
|
|
37
|
-
git(["merge-base", "HEAD", `origin/${process.env.DEFAULT_BRANCH || "main"}`]) ||
|
|
38
|
-
git(["merge-base", "HEAD", "main"]);
|
|
39
|
-
if (!base) return []; // shallow clone or fresh repo — nothing to compare against
|
|
40
|
-
|
|
41
|
-
const out = git(["diff", "--name-status", base, "HEAD"]);
|
|
42
|
-
const violations = [];
|
|
43
|
-
for (const row of out.split("\n").filter(Boolean)) {
|
|
44
|
-
const [status, ...paths] = row.split("\t");
|
|
45
|
-
const path = paths[paths.length - 1];
|
|
46
|
-
if (!MIGRATION_DIRS.some((dir) => path.startsWith(dir))) continue;
|
|
47
|
-
if (status.startsWith("M") || status.startsWith("D") || status.startsWith("R")) {
|
|
48
|
-
if (ALLOWLIST[path]) continue;
|
|
49
|
-
violations.push({
|
|
50
|
-
file: path,
|
|
51
|
-
message: `migration ${status.startsWith("D") ? "deleted" : "modified"} — migrations are append-only; write a new one`,
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return violations;
|
|
56
|
-
},
|
|
57
|
-
};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
// facility module: database — migration immutability (PreToolUse)
|
|
2
|
-
if (/(^|\/)(supabase\/|db\/|prisma\/)?migrations\/[^/]+\.(sql|js|ts|rb|py)$/.test(filePath)) {
|
|
3
|
-
const tool = payload?.tool_name ?? "";
|
|
4
|
-
const isEdit = tool === "Edit" || tool === "MultiEdit";
|
|
5
|
-
if (isEdit) {
|
|
6
|
-
block(
|
|
7
|
-
"Migration files are immutable once written. Create a NEW timestamped migration instead.",
|
|
8
|
-
);
|
|
9
|
-
}
|
|
10
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "database",
|
|
3
|
-
"title": "Database",
|
|
4
|
-
"description": "Migrations are immutable and append-only; access control by default; privileged credentials stay out of user-facing paths.",
|
|
5
|
-
"standardSection": "standard-section.md",
|
|
6
|
-
"files": [
|
|
7
|
-
{
|
|
8
|
-
"from": "agents/data-security-reviewer.md",
|
|
9
|
-
"to": ".claude/agents/data-security-reviewer.md"
|
|
10
|
-
},
|
|
11
|
-
{
|
|
12
|
-
"from": "guards/migrations-immutable.mjs",
|
|
13
|
-
"to": "guards/migrations-immutable.mjs"
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
"from": "guards/migration-versions.mjs",
|
|
17
|
-
"to": "guards/migration-versions.mjs"
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
"from": "commands/new-migration.md",
|
|
21
|
-
"to": ".claude/commands/new-migration.md"
|
|
22
|
-
}
|
|
23
|
-
],
|
|
24
|
-
"hookRules": "hooks/protect-migrations.fragment.mjs"
|
|
25
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
### Database (facility module)
|
|
2
|
-
|
|
3
|
-
Migrations are the durable state of the database. They are **append-only**:
|
|
4
|
-
a change is a NEW migration, never an edit to one that may have been applied
|
|
5
|
-
anywhere. The `migrations-immutable` guard and the `.claude/hooks` rules
|
|
6
|
-
enforce this mechanically.
|
|
7
|
-
|
|
8
|
-
- New tables and collections start closed: enable row/document-level access
|
|
9
|
-
control where the platform supports it, deny by default, grant only the
|
|
10
|
-
minimum required operations.
|
|
11
|
-
- Authorization checks route through one shared helper layer — never inline
|
|
12
|
-
token/claim parsing inside individual policies or queries.
|
|
13
|
-
- Privileged credentials (service role, admin connections) stay out of
|
|
14
|
-
user-facing and agent-facing read paths. Any privileged action lives in a
|
|
15
|
-
reviewed application service with explicit permission checks and tests.
|
|
16
|
-
- Update seed data whenever a feature needs realistic data to test locally.
|
|
17
|
-
Seeds follow the domain: realistic names, states, relationships, and edge
|
|
18
|
-
cases — not toy rows that only satisfy a test selector.
|
|
19
|
-
- Empty results must be permission-safe: do not imply hidden data exists when
|
|
20
|
-
access control returns nothing.
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: design-reviewer
|
|
3
|
-
description: Reviews UI changes against the repo's design system and checks that critical UI flows carry browser evidence. Use when a change adds or modifies UI, layout, components, or styling.
|
|
4
|
-
tools: Read, Grep, Glob, Bash
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
You review product UI against this repository's design system and confirm
|
|
8
|
-
critical flows are verified in a browser. A UI that conflicts with the design
|
|
9
|
-
system is a product-quality issue.
|
|
10
|
-
|
|
11
|
-
## Authoritative references
|
|
12
|
-
- The design system source of truth declared in `STANDARD.md` (Design system
|
|
13
|
-
section) — read it before judging.
|
|
14
|
-
- The repo's design tokens / shared component layer — existing values come
|
|
15
|
-
first.
|
|
16
|
-
|
|
17
|
-
## What to check
|
|
18
|
-
1. Existing design tokens and helpers are reused before any new value; no
|
|
19
|
-
ad-hoc colors, spacing, or radii that bypass the token layer.
|
|
20
|
-
2. Components match the system's catalog: shapes, sizes, states, and
|
|
21
|
-
hierarchy expressed the way the system prescribes.
|
|
22
|
-
3. **Evidence**: UI flow changes include a browser verification note
|
|
23
|
-
(Playwright run, screenshots), or an explicit reason UI verification did
|
|
24
|
-
not apply.
|
|
25
|
-
4. Responsive behavior holds at the product's breakpoints when layout, text
|
|
26
|
-
fit, navigation, modals, or tables can be affected.
|
|
27
|
-
5. Empty, error, and loading states are designed, not accidental.
|
|
28
|
-
|
|
29
|
-
## How to verify
|
|
30
|
-
- `grep` the diff for raw color/spacing literals that should be tokens.
|
|
31
|
-
- Recommend the smallest browser run that covers the affected flows.
|
|
32
|
-
|
|
33
|
-
## Output contract
|
|
34
|
-
List design-system violations and missing evidence by severity with file:line
|
|
35
|
-
and the token/helper to use instead. Confirm which critical flows are covered
|
|
36
|
-
by browser evidence. Flag only design-system/UX-correctness gaps, not
|
|
37
|
-
subjective taste.
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "design-system",
|
|
3
|
-
"title": "Design system",
|
|
4
|
-
"description": "UI changes conform to your design system and critical flows carry browser evidence.",
|
|
5
|
-
"standardSection": "standard-section.md",
|
|
6
|
-
"files": [
|
|
7
|
-
{ "from": "agents/design-reviewer.md", "to": ".claude/agents/design-reviewer.md" }
|
|
8
|
-
]
|
|
9
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
### Design system (facility module)
|
|
2
|
-
|
|
3
|
-
A UI that conflicts with the design system is a product-quality issue, not a
|
|
4
|
-
matter of taste. Declare your source of truth here (a spec doc, a tokens
|
|
5
|
-
file, a published package) — the design reviewer reads it before judging.
|
|
6
|
-
|
|
7
|
-
- Use existing design tokens and shared components before inventing values.
|
|
8
|
-
Ad-hoc colors, spacing, and radii that bypass the token layer are defects.
|
|
9
|
-
- UI flow changes include browser evidence — a Playwright run, screenshots,
|
|
10
|
-
or a recorded check — or an explicit reason why UI verification did not
|
|
11
|
-
apply. "It compiles" is not evidence for layout.
|
|
12
|
-
- Verify responsive behavior at the breakpoints your product supports when a
|
|
13
|
-
change can affect layout, text fit, navigation, modals, or tables.
|
|
14
|
-
- Empty states, error states, and loading states are part of the surface —
|
|
15
|
-
design them, don't let them fall out of the happy path.
|
package/src/add.mjs
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
// `facility add <module>` — install a quality module: its STANDARD.md section,
|
|
2
|
-
// its reviewer subagent, its guards, and its hook rules.
|
|
3
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
4
|
-
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
5
|
-
import { insertHookRules, insertModuleSection } from "./render.mjs";
|
|
6
|
-
import { fail, heading, ok, skip, warn } from "./ui.mjs";
|
|
7
|
-
|
|
8
|
-
export async function addModule(name, { dir, pkgRoot, banner = true }) {
|
|
9
|
-
const moduleDir =
|
|
10
|
-
name.startsWith(".") || isAbsolute(name) ? resolve(dir, name) : join(pkgRoot, "modules", name);
|
|
11
|
-
|
|
12
|
-
const manifestPath = join(moduleDir, "module.json");
|
|
13
|
-
if (!existsSync(manifestPath)) {
|
|
14
|
-
const available = readdirSync(join(pkgRoot, "modules"), { withFileTypes: true })
|
|
15
|
-
.filter((entry) => entry.isDirectory())
|
|
16
|
-
.map((entry) => entry.name)
|
|
17
|
-
.join(", ");
|
|
18
|
-
fail(`Unknown module "${name}". Available: ${available} (or a local path).`);
|
|
19
|
-
return 1;
|
|
20
|
-
}
|
|
21
|
-
const module = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
22
|
-
if (banner) heading(`Adding module: ${module.title}`);
|
|
23
|
-
|
|
24
|
-
// 1. Files (reviewer subagents, guards) — never overwrite.
|
|
25
|
-
for (const file of module.files ?? []) {
|
|
26
|
-
const target = join(dir, file.to);
|
|
27
|
-
if (existsSync(target)) {
|
|
28
|
-
skip(`${file.to} exists — left untouched`);
|
|
29
|
-
continue;
|
|
30
|
-
}
|
|
31
|
-
mkdirSync(dirname(target), { recursive: true });
|
|
32
|
-
writeFileSync(target, readFileSync(join(moduleDir, file.from), "utf8"));
|
|
33
|
-
ok(file.to);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// 2. STANDARD.md section between the facility:modules markers.
|
|
37
|
-
const standardPath = join(dir, "STANDARD.md");
|
|
38
|
-
if (module.standardSection && existsSync(standardPath)) {
|
|
39
|
-
const section = readFileSync(join(moduleDir, module.standardSection), "utf8");
|
|
40
|
-
const { content, inserted } = insertModuleSection(readFileSync(standardPath, "utf8"), section, module.title);
|
|
41
|
-
if (inserted) {
|
|
42
|
-
writeFileSync(standardPath, content);
|
|
43
|
-
ok(`STANDARD.md — "${module.title}" section`);
|
|
44
|
-
} else {
|
|
45
|
-
skip(`STANDARD.md already has the "${module.title}" section`);
|
|
46
|
-
}
|
|
47
|
-
} else if (module.standardSection) {
|
|
48
|
-
warn("STANDARD.md not found — run `facility init` first.");
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// 3. Hook rules spliced into protect-files.mjs at the module marker.
|
|
52
|
-
if (module.hookRules) {
|
|
53
|
-
const hookPath = join(dir, ".claude/hooks/protect-files.mjs");
|
|
54
|
-
if (existsSync(hookPath)) {
|
|
55
|
-
const fragment = readFileSync(join(moduleDir, module.hookRules), "utf8");
|
|
56
|
-
const { content, inserted } = insertHookRules(readFileSync(hookPath, "utf8"), fragment, module.name);
|
|
57
|
-
if (inserted) {
|
|
58
|
-
writeFileSync(hookPath, content);
|
|
59
|
-
ok(".claude/hooks/protect-files.mjs — rules spliced");
|
|
60
|
-
} else {
|
|
61
|
-
skip(".claude/hooks/protect-files.mjs already has this module's rules");
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// 4. Record it in the manifest.
|
|
67
|
-
const facilityManifestPath = join(dir, ".facility.json");
|
|
68
|
-
if (existsSync(facilityManifestPath)) {
|
|
69
|
-
const manifest = JSON.parse(readFileSync(facilityManifestPath, "utf8"));
|
|
70
|
-
if (!manifest.modules?.includes(module.name)) {
|
|
71
|
-
manifest.modules = [...(manifest.modules ?? []), module.name];
|
|
72
|
-
writeFileSync(facilityManifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return 0;
|
|
77
|
-
}
|