tribunal-kit 5.8.2 → 5.8.4

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.
Files changed (101) hide show
  1. package/.agent/ARCHITECTURE.md +12 -12
  2. package/.agent/agents/complexity-reviewer.md +53 -0
  3. package/.agent/agents/precedence-reviewer.md +12 -12
  4. package/.agent/agents/swarm-worker-registry.md +3 -3
  5. package/.agent/history/integrity_manifest.json +958 -0
  6. package/.agent/history/memory/.memory.idx +305 -1
  7. package/.agent/history/memory/MEMORY.md +21 -1
  8. package/.agent/rules/GEMINI.md +31 -28
  9. package/.agent/scripts/case_law_manager.js +3 -15
  10. package/.agent/scripts/context_broker.js +3 -1
  11. package/.agent/scripts/guardrail_engine.js +643 -0
  12. package/.agent/scripts/integrity_manifest.js +486 -0
  13. package/.agent/scripts/signal_detector.js +1 -1
  14. package/.agent/scripts/skill_evolution.js +3 -15
  15. package/.agent/scripts/skill_integrator.js +2 -12
  16. package/.agent/scripts/swarm_dispatcher.js +2 -12
  17. package/.agent/skills/12-principles-of-animation/SKILL.md +69 -0
  18. package/.agent/skills/60fps-animation/SKILL.md +78 -0
  19. package/.agent/skills/accessible-animation/SKILL.md +86 -0
  20. package/.agent/skills/adapt/SKILL.md +75 -0
  21. package/.agent/skills/animation-on-scroll/SKILL.md +110 -0
  22. package/.agent/skills/animation-systems/SKILL.md +69 -0
  23. package/.agent/skills/antfu-conventions/SKILL.md +74 -0
  24. package/.agent/skills/app-builder/SKILL.md +1 -1
  25. package/.agent/skills/apple-design/SKILL.md +108 -0
  26. package/.agent/skills/audit-and-fix/SKILL.md +83 -0
  27. package/.agent/skills/baseline-ui/SKILL.md +74 -0
  28. package/.agent/skills/better-colors/SKILL.md +124 -0
  29. package/.agent/skills/better-typography/SKILL.md +111 -0
  30. package/.agent/skills/better-ui/SKILL.md +102 -0
  31. package/.agent/skills/bolder/SKILL.md +68 -0
  32. package/.agent/skills/build-primitive/SKILL.md +70 -0
  33. package/.agent/skills/clarify/SKILL.md +75 -0
  34. package/.agent/skills/cobejs/SKILL.md +96 -0
  35. package/.agent/skills/codebase-design/SKILL.md +84 -0
  36. package/.agent/skills/colorize/SKILL.md +77 -0
  37. package/.agent/skills/compact-landing/SKILL.md +70 -0
  38. package/.agent/skills/company-logos/SKILL.md +73 -0
  39. package/.agent/skills/create-design-md/SKILL.md +104 -0
  40. package/.agent/skills/critique/SKILL.md +95 -0
  41. package/.agent/skills/delight/SKILL.md +65 -0
  42. package/.agent/skills/design-lab/SKILL.md +59 -0
  43. package/.agent/skills/diagnosing-bugs/SKILL.md +190 -0
  44. package/.agent/skills/distill/SKILL.md +65 -0
  45. package/.agent/skills/domain-modeling/SKILL.md +78 -0
  46. package/.agent/skills/fixing-accessibility/SKILL.md +98 -0
  47. package/.agent/skills/fixing-metadata/SKILL.md +97 -0
  48. package/.agent/skills/fixing-motion-performance/SKILL.md +96 -0
  49. package/.agent/skills/gpt-taste/SKILL.md +68 -0
  50. package/.agent/skills/harden/SKILL.md +74 -0
  51. package/.agent/skills/impeccable/SKILL.md +72 -0
  52. package/.agent/skills/improve-codebase-architecture/SKILL.md +67 -0
  53. package/.agent/skills/improve-ui/SKILL.md +83 -0
  54. package/.agent/skills/landing-page/SKILL.md +88 -0
  55. package/.agent/skills/lint-and-validate/SKILL.md +1 -2
  56. package/.agent/skills/local-first-architecture/SKILL.md +66 -0
  57. package/.agent/skills/lottie-animation/SKILL.md +82 -0
  58. package/.agent/skills/marquee-loop/SKILL.md +96 -0
  59. package/.agent/skills/masked-reveal/SKILL.md +88 -0
  60. package/.agent/skills/micro-interaction/SKILL.md +100 -0
  61. package/.agent/skills/morphing-icons/SKILL.md +85 -0
  62. package/.agent/skills/page-transition-animation/SKILL.md +108 -0
  63. package/.agent/skills/parallel-agents/SKILL.md +5 -5
  64. package/.agent/skills/polish/SKILL.md +63 -0
  65. package/.agent/skills/pricing-page/SKILL.md +68 -0
  66. package/.agent/skills/progressive-blur/SKILL.md +100 -0
  67. package/.agent/skills/project-idioms/SKILL.md +7 -7
  68. package/.agent/skills/quieter/SKILL.md +68 -0
  69. package/.agent/skills/react-doctor/SKILL.md +70 -0
  70. package/.agent/skills/redesign-skill/SKILL.md +65 -0
  71. package/.agent/skills/shape/SKILL.md +73 -0
  72. package/.agent/skills/soft-skill/SKILL.md +72 -0
  73. package/.agent/skills/sounds-on-the-web/SKILL.md +100 -0
  74. package/.agent/skills/svg-animation/SKILL.md +91 -0
  75. package/.agent/skills/swiss-design/SKILL.md +64 -0
  76. package/.agent/skills/taste-skill/SKILL.md +71 -0
  77. package/.agent/skills/tdd-workflow/SKILL.md +36 -165
  78. package/.agent/skills/test-result-analyzer/SKILL.md +1 -1
  79. package/.agent/skills/thermo-nuclear-code-quality-review/SKILL.md +82 -0
  80. package/.agent/skills/to-spring-or-not-to-spring/SKILL.md +66 -0
  81. package/.agent/skills/transitions-dev/SKILL.md +101 -0
  82. package/.agent/skills/typeset/SKILL.md +76 -0
  83. package/.agent/skills/ui-skills-root/SKILL.md +85 -0
  84. package/.agent/skills/web-quality-audit/SKILL.md +67 -0
  85. package/.agent/workflows/fix.md +2 -2
  86. package/.agent/workflows/preview.md +5 -5
  87. package/.agent/workflows/status.md +1 -1
  88. package/.agent/workflows/tribunal-full.md +3 -3
  89. package/.agent/workflows/tribunal-speed.md +2 -2
  90. package/README.md +348 -238
  91. package/bin/tribunal-kit.js +62 -1482
  92. package/dist/cli.js +13 -0
  93. package/dist/commands/align.js +1 -1
  94. package/dist/commands/compile.js +1 -1
  95. package/dist/commands/guardrail.js +275 -0
  96. package/dist/commands/init.js +10 -9
  97. package/dist/commands/optimize.js +318 -0
  98. package/dist/utils/version.js +1 -1
  99. package/package.json +10 -8
  100. package/scripts/fix-vbc.js +98 -0
  101. package/scripts/fix-vbc.ps1 +119 -0
@@ -0,0 +1,486 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * integrity_manifest.js — Tribunal Kit Integrity Manifest Compiler
4
+ * =================================================================
5
+ * Crawls the entire .agent/ directory and generates a machine-readable
6
+ * integrity_manifest.json — the single source of truth for every named
7
+ * reference in the system.
8
+ *
9
+ * This manifest is consumed by:
10
+ * - guardrail_engine.js (deterministic validation)
11
+ * - verify_all.js (pre-deploy checks)
12
+ * - context_broker.js (context assembly)
13
+ *
14
+ * Usage:
15
+ * node .agent/scripts/integrity_manifest.js → Generate manifest
16
+ * node .agent/scripts/integrity_manifest.js --output json → Print to stdout
17
+ * node .agent/scripts/integrity_manifest.js --validate → Generate + validate
18
+ *
19
+ * Zero external dependencies. Node.js stdlib only.
20
+ */
21
+
22
+ "use strict";
23
+
24
+ const fs = require("fs");
25
+ const path = require("path");
26
+
27
+ // ── Constants ─────────────────────────────────────────────────────────────────
28
+
29
+ const AGENT_DIR_NAME = ".agent";
30
+
31
+ // ── YAML Frontmatter Parser (regex-based, zero deps) ─────────────────────────
32
+
33
+ function parseFrontmatter(content) {
34
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
35
+ if (!match) return {};
36
+
37
+ const yaml = {};
38
+ const lines = match[1].split(/\r?\n/);
39
+ for (const line of lines) {
40
+ const kv = line.match(/^(\w[\w-]*):\s*(.+)$/);
41
+ if (kv) {
42
+ yaml[kv[1].trim()] = kv[2].trim();
43
+ }
44
+ }
45
+ return yaml;
46
+ }
47
+
48
+ // ── Directory Helpers ─────────────────────────────────────────────────────────
49
+
50
+ function safeReaddir(dir) {
51
+ try {
52
+ return fs.readdirSync(dir);
53
+ } catch {
54
+ return [];
55
+ }
56
+ }
57
+
58
+ function safeReadFile(filePath) {
59
+ try {
60
+ return fs.readFileSync(filePath, "utf8");
61
+ } catch {
62
+ return "";
63
+ }
64
+ }
65
+
66
+ // ── Agent Crawler ─────────────────────────────────────────────────────────────
67
+
68
+ function crawlAgents(agentDir) {
69
+ const agentsDir = path.join(agentDir, "agents");
70
+ const files = safeReaddir(agentsDir).filter((f) => f.endsWith(".md"));
71
+
72
+ const reviewers = [];
73
+ const specialists = [];
74
+ const allAgents = [];
75
+
76
+ for (const file of files) {
77
+ const name = file.replace(/\.md$/, "");
78
+ allAgents.push(name);
79
+
80
+ // Classify: reviewer if name contains "reviewer", "auditor", or "tester"
81
+ // or if frontmatter has role: reviewer
82
+ const content = safeReadFile(path.join(agentsDir, file));
83
+ const fm = parseFrontmatter(content);
84
+ const isReviewer =
85
+ /reviewer|auditor|tester/i.test(name) ||
86
+ (fm.role && /reviewer/i.test(fm.role));
87
+
88
+ if (isReviewer) {
89
+ reviewers.push(name);
90
+ } else {
91
+ specialists.push(name);
92
+ }
93
+ }
94
+
95
+ return {
96
+ total: allAgents.length,
97
+ reviewers: reviewers.sort(),
98
+ specialists: specialists.sort(),
99
+ reviewer_count: reviewers.length,
100
+ all: allAgents.sort(),
101
+ };
102
+ }
103
+
104
+ // ── Skill Crawler ─────────────────────────────────────────────────────────────
105
+
106
+ function crawlSkills(agentDir) {
107
+ const skillsDir = path.join(agentDir, "skills");
108
+ const entries = safeReaddir(skillsDir);
109
+ const names = [];
110
+
111
+ for (const entry of entries) {
112
+ const skillPath = path.join(skillsDir, entry, "SKILL.md");
113
+ if (fs.existsSync(skillPath)) {
114
+ const content = safeReadFile(skillPath);
115
+ const fm = parseFrontmatter(content);
116
+ names.push(fm.name || entry);
117
+ }
118
+ }
119
+
120
+ return {
121
+ total: names.length,
122
+ names: names.sort(),
123
+ };
124
+ }
125
+
126
+ // ── Script Crawler ────────────────────────────────────────────────────────────
127
+
128
+ function crawlScripts(agentDir) {
129
+ const scriptsDir = path.join(agentDir, "scripts");
130
+ const files = safeReaddir(scriptsDir).filter(
131
+ (f) => f.endsWith(".js") || f.endsWith(".py"),
132
+ );
133
+
134
+ const fileMap = {};
135
+ for (const file of files) {
136
+ const relPath = path.join(AGENT_DIR_NAME, "scripts", file);
137
+ fileMap[file] = relPath.replace(/\\/g, "/");
138
+ }
139
+
140
+ return {
141
+ total: files.length,
142
+ files: fileMap,
143
+ };
144
+ }
145
+
146
+ // ── Workflow Crawler ──────────────────────────────────────────────────────────
147
+
148
+ function crawlWorkflows(agentDir) {
149
+ const workflowsDir = path.join(agentDir, "workflows");
150
+ const files = safeReaddir(workflowsDir).filter((f) => f.endsWith(".md"));
151
+ const names = files.map((f) => f.replace(/\.md$/, ""));
152
+
153
+ return {
154
+ total: names.length,
155
+ names: names.sort(),
156
+ };
157
+ }
158
+
159
+ // ── Cross-Reference Extractor ─────────────────────────────────────────────────
160
+
161
+ /**
162
+ * Scans a file's content for references to other .agent/ assets.
163
+ * Patterns detected:
164
+ * - agents/X.md, agents/X
165
+ * - skills/X/SKILL.md, skill name references
166
+ * - scripts/X.js, scripts/X.py
167
+ * - workflows/X.md
168
+ * - node .agent/scripts/X
169
+ */
170
+ function extractCrossReferences(filePath, content, agentDir) {
171
+ const refs = [];
172
+ const relSource = path.relative(agentDir, filePath).replace(/\\/g, "/");
173
+
174
+ // Agent references: agents/name.md or `agent-name`
175
+ const agentRefRegex =
176
+ /(?:agents\/)([\w-]+)(?:\.md)?/g;
177
+ let m;
178
+ while ((m = agentRefRegex.exec(content)) !== null) {
179
+ const refFile = `agents/${m[1]}.md`;
180
+ const fullPath = path.join(agentDir, refFile);
181
+ refs.push({
182
+ source: relSource,
183
+ ref: refFile,
184
+ exists: fs.existsSync(fullPath),
185
+ type: "agent",
186
+ });
187
+ }
188
+
189
+ // Script references: scripts/name.js or scripts/name.py
190
+ const scriptRefRegex =
191
+ /(?:scripts\/)([\w_-]+)\.(js|py)/g;
192
+ while ((m = scriptRefRegex.exec(content)) !== null) {
193
+ const refFile = `scripts/${m[1]}.${m[2]}`;
194
+ const fullPath = path.join(agentDir, refFile);
195
+ refs.push({
196
+ source: relSource,
197
+ ref: refFile,
198
+ exists: fs.existsSync(fullPath),
199
+ type: "script",
200
+ });
201
+ }
202
+
203
+ // Workflow references: workflows/name.md
204
+ const workflowRefRegex = /(?:workflows\/)([\w-]+)(?:\.md)?/g;
205
+ while ((m = workflowRefRegex.exec(content)) !== null) {
206
+ const precedingText = content.substring(Math.max(0, m.index - 100), m.index);
207
+ if (precedingText.includes(".github/") || precedingText.includes("github.com/")) {
208
+ continue;
209
+ }
210
+ const refFile = `workflows/${m[1]}.md`;
211
+ const fullPath = path.join(agentDir, refFile);
212
+ refs.push({
213
+ source: relSource,
214
+ ref: refFile,
215
+ exists: fs.existsSync(fullPath),
216
+ type: "workflow",
217
+ });
218
+ }
219
+
220
+ // Deduplicate
221
+ const seen = new Set();
222
+ return refs.filter((r) => {
223
+ const key = `${r.source}→${r.ref}`;
224
+ if (seen.has(key)) return false;
225
+ seen.add(key);
226
+ return true;
227
+ });
228
+ }
229
+
230
+ // ── Numeric Claim Extractor ───────────────────────────────────────────────────
231
+
232
+ /**
233
+ * Finds numeric claims about asset counts in a file.
234
+ * Patterns: "N reviewers", "N agents", "N skills", "N workflows", "N scripts"
235
+ */
236
+ function extractNumericClaims(filePath, content, agentDir, actualCounts) {
237
+ const claims = [];
238
+ const relSource = path.relative(agentDir, filePath).replace(/\\/g, "/");
239
+ const lines = content.split(/\r?\n/);
240
+
241
+ const claimPatterns = [
242
+ { regex: /(\d+)[-\s]+(?:parallel\s+)?(?:reviewers?|agents?)/gi, entity: "reviewers" },
243
+ { regex: /(\d+)\s*(?:specialist\s+)?agents?\b/gi, entity: "agents" },
244
+ { regex: /(\d+)\s*(?:modular\s+)?skills?\b/gi, entity: "skills" },
245
+ { regex: /(\d+)\s*(?:slash\s+)?workflows?\b/gi, entity: "workflows" },
246
+ { regex: /(\d+)\s*(?:JS\s+)?scripts?\b/gi, entity: "scripts" },
247
+ ];
248
+
249
+ for (let i = 0; i < lines.length; i++) {
250
+ const line = lines[i];
251
+ for (const { regex, entity } of claimPatterns) {
252
+ regex.lastIndex = 0;
253
+ let match;
254
+ while ((match = regex.exec(line)) !== null) {
255
+ const claimed = parseInt(match[1], 10);
256
+ // Skip tiny numbers (likely not count claims) and very large numbers
257
+ if (claimed < 3 || claimed > 500) continue;
258
+
259
+ const actual = actualCounts[entity];
260
+ if (actual !== undefined) {
261
+ claims.push({
262
+ source: `${relSource}:L${i + 1}`,
263
+ claim: `${claimed} ${entity}`,
264
+ actual,
265
+ valid: claimed === actual,
266
+ });
267
+ }
268
+ }
269
+ }
270
+ }
271
+
272
+ return claims;
273
+ }
274
+
275
+ // ── File Walker ───────────────────────────────────────────────────────────────
276
+
277
+ function walkMdFiles(dir, fileList = []) {
278
+ if (!fs.existsSync(dir)) return fileList;
279
+
280
+ const entries = safeReaddir(dir);
281
+ for (const entry of entries) {
282
+ const fullPath = path.join(dir, entry);
283
+ try {
284
+ const stat = fs.statSync(fullPath);
285
+ if (stat.isDirectory()) {
286
+ // Skip node_modules, .git, history, .backups, .shared
287
+ if (
288
+ ["node_modules", ".git", "history", ".backups", ".shared"].includes(
289
+ entry,
290
+ )
291
+ ) {
292
+ continue;
293
+ }
294
+ walkMdFiles(fullPath, fileList);
295
+ } else if (entry.endsWith(".md") || entry.endsWith(".json")) {
296
+ if (entry.startsWith("http") || entry.startsWith("#") || entry.startsWith("https://github.com/")) {
297
+ continue;
298
+ }
299
+ fileList.push(fullPath);
300
+ }
301
+ } catch {
302
+ // Skip files we can't stat
303
+ }
304
+ }
305
+ return fileList;
306
+ }
307
+
308
+ // ── Main: Generate Manifest ───────────────────────────────────────────────────
309
+
310
+ function generateManifest(projectRoot) {
311
+ const agentDir = path.join(projectRoot, AGENT_DIR_NAME);
312
+
313
+ if (!fs.existsSync(agentDir)) {
314
+ return {
315
+ error: `No ${AGENT_DIR_NAME}/ directory found at ${projectRoot}`,
316
+ };
317
+ }
318
+
319
+ // Phase 1: Crawl all entity types
320
+ const agents = crawlAgents(agentDir);
321
+ const skills = crawlSkills(agentDir);
322
+ const scripts = crawlScripts(agentDir);
323
+ const workflows = crawlWorkflows(agentDir);
324
+
325
+ // Phase 2: Extract cross-references from all markdown files
326
+ const allFiles = walkMdFiles(agentDir);
327
+ const allRefs = [];
328
+ const allClaims = [];
329
+
330
+ const actualCounts = {
331
+ reviewers: agents.reviewer_count,
332
+ agents: agents.total,
333
+ skills: skills.total,
334
+ workflows: workflows.total,
335
+ scripts: scripts.total,
336
+ };
337
+
338
+ for (const file of allFiles) {
339
+ const content = safeReadFile(file);
340
+ if (!content) continue;
341
+
342
+ const refs = extractCrossReferences(file, content, agentDir);
343
+ allRefs.push(...refs);
344
+
345
+ const claims = extractNumericClaims(file, content, agentDir, actualCounts);
346
+ allClaims.push(...claims);
347
+ }
348
+
349
+ // Phase 3: Deduplicate cross-references
350
+ const seenRefs = new Set();
351
+ const uniqueRefs = allRefs.filter((r) => {
352
+ const key = `${r.source}→${r.ref}`;
353
+ if (seenRefs.has(key)) return false;
354
+ seenRefs.add(key);
355
+ return true;
356
+ });
357
+
358
+ // Phase 4: Build manifest
359
+ let version = "unknown";
360
+ try {
361
+ const pkg = JSON.parse(
362
+ safeReadFile(path.join(projectRoot, "package.json")) || "{}",
363
+ );
364
+ version = pkg.version || "unknown";
365
+ } catch {
366
+ // Ignore
367
+ }
368
+
369
+ const manifest = {
370
+ version,
371
+ generated_at: new Date().toISOString(),
372
+ agents,
373
+ skills,
374
+ scripts,
375
+ workflows,
376
+ cross_references: uniqueRefs,
377
+ numeric_claims: allClaims,
378
+ integrity: {
379
+ phantom_references: uniqueRefs.filter((r) => !r.exists).length,
380
+ invalid_claims: allClaims.filter((c) => !c.valid).length,
381
+ total_references: uniqueRefs.length,
382
+ total_claims: allClaims.length,
383
+ },
384
+ };
385
+
386
+ return manifest;
387
+ }
388
+
389
+ // ── Persist Manifest ──────────────────────────────────────────────────────────
390
+
391
+ function saveManifest(manifest, projectRoot) {
392
+ const historyDir = path.join(projectRoot, AGENT_DIR_NAME, "history");
393
+ if (!fs.existsSync(historyDir)) {
394
+ fs.mkdirSync(historyDir, { recursive: true });
395
+ }
396
+
397
+ const outputPath = path.join(historyDir, "integrity_manifest.json");
398
+ fs.writeFileSync(outputPath, JSON.stringify(manifest, null, 2), "utf8");
399
+ return outputPath;
400
+ }
401
+
402
+ // ── CLI Entry Point ───────────────────────────────────────────────────────────
403
+
404
+ function main() {
405
+ const args = process.argv.slice(2);
406
+ const projectRoot = process.cwd();
407
+ const outputJson = args.includes("--output") && args.includes("json");
408
+ const validateOnly = args.includes("--validate");
409
+
410
+ const manifest = generateManifest(projectRoot);
411
+
412
+ if (manifest.error) {
413
+ console.error(`❌ ${manifest.error}`);
414
+ process.exit(1);
415
+ }
416
+
417
+ if (outputJson) {
418
+ console.log(JSON.stringify(manifest, null, 2));
419
+ return;
420
+ }
421
+
422
+ // Save to disk
423
+ const outputPath = saveManifest(manifest, projectRoot);
424
+
425
+ // Print summary
426
+ const { integrity } = manifest;
427
+ console.log(`\n🛡️ Integrity Manifest Generated`);
428
+ console.log(` Path: ${outputPath}`);
429
+ console.log(` ─────────────────────────────────`);
430
+ console.log(` Agents: ${manifest.agents.total} (${manifest.agents.reviewer_count} reviewers)`);
431
+ console.log(` Skills: ${manifest.skills.total}`);
432
+ console.log(` Scripts: ${manifest.scripts.total}`);
433
+ console.log(` Workflows: ${manifest.workflows.total}`);
434
+ console.log(` References: ${integrity.total_references}`);
435
+ console.log(` Claims: ${integrity.total_claims}`);
436
+ console.log(` ─────────────────────────────────`);
437
+
438
+ if (integrity.phantom_references > 0) {
439
+ console.log(` ⚠️ Phantom references: ${integrity.phantom_references}`);
440
+ const phantoms = manifest.cross_references.filter((r) => !r.exists);
441
+ for (const p of phantoms) {
442
+ console.log(` ❌ ${p.source} → ${p.ref}`);
443
+ }
444
+ }
445
+
446
+ if (integrity.invalid_claims > 0) {
447
+ console.log(` ⚠️ Invalid claims: ${integrity.invalid_claims}`);
448
+ const invalid = manifest.numeric_claims.filter((c) => !c.valid);
449
+ for (const c of invalid) {
450
+ console.log(` ❌ ${c.source}: says "${c.claim}" but actual is ${c.actual}`);
451
+ }
452
+ }
453
+
454
+ if (
455
+ integrity.phantom_references === 0 &&
456
+ integrity.invalid_claims === 0
457
+ ) {
458
+ console.log(` ✅ All references valid. All claims accurate.`);
459
+ }
460
+
461
+ console.log();
462
+
463
+ if (validateOnly) {
464
+ const exitCode =
465
+ integrity.phantom_references > 0 || integrity.invalid_claims > 0 ? 1 : 0;
466
+ process.exit(exitCode);
467
+ }
468
+ }
469
+
470
+ // ── Exports ───────────────────────────────────────────────────────────────────
471
+
472
+ module.exports = {
473
+ generateManifest,
474
+ saveManifest,
475
+ parseFrontmatter,
476
+ crawlAgents,
477
+ crawlSkills,
478
+ crawlScripts,
479
+ crawlWorkflows,
480
+ extractCrossReferences,
481
+ extractNumericClaims,
482
+ };
483
+
484
+ if (require.main === module) {
485
+ main();
486
+ }
@@ -15,7 +15,7 @@
15
15
 
16
16
  "use strict";
17
17
 
18
- const fs = require("fs");
18
+ const _fs = require("fs");
19
19
  const path = require("path");
20
20
 
21
21
  const SIGNAL_TYPES = {
@@ -42,21 +42,9 @@ const {
42
42
  RESET,
43
43
  } = require("./_colors");
44
44
 
45
- // ── Find .agent directory ─────────────────────────────────────────────────────
46
- function findAgentDir() {
47
- let current = path.resolve(process.cwd());
48
- const root = path.parse(current).root;
49
- while (current !== root) {
50
- const candidate = path.join(current, ".agent");
51
- if (fs.existsSync(candidate) && fs.statSync(candidate).isDirectory())
52
- return candidate;
53
- current = path.dirname(current);
54
- }
55
- console.error(
56
- `${RED}✖ Error: '.agent' directory not found. Please run 'npx tribunal-kit init' first.${RESET}`,
57
- );
58
- process.exit(1);
59
- }
45
+ // ── Shared Utilities ──────────────────────────────────────────────────────────
46
+ const { findAgentDir } = require("./_utils");
47
+
60
48
 
61
49
  const AGENT_DIR = findAgentDir();
62
50
  const SKILL_DIR = path.join(AGENT_DIR, "skills", "project-idioms");
@@ -24,18 +24,8 @@ const { CYAN, GREEN, YELLOW, RED, BOLD, RESET } = require("./_colors");
24
24
 
25
25
  const REPORT_FILE = "skill-integration-report.md";
26
26
 
27
- function findAgentDir(startPathStr) {
28
- let current = path.resolve(startPathStr);
29
- const root = path.parse(current).root;
30
- while (current !== root) {
31
- const agentDir = path.join(current, ".agent");
32
- if (fs.existsSync(agentDir) && fs.statSync(agentDir).isDirectory()) {
33
- return agentDir;
34
- }
35
- current = path.dirname(current);
36
- }
37
- return null;
38
- }
27
+ const { findAgentDir } = require("./_utils");
28
+
39
29
 
40
30
  function getAssociatedScript(skillDir, scriptsDir) {
41
31
  /** Check if the skill has an explicit frontmatter script or an implicit script file. */
@@ -89,18 +89,8 @@ const MAX_GOAL_LENGTH = 200;
89
89
  const MAX_CONTEXT_LENGTH = 800;
90
90
  const MAX_WORKERS_PER_SWARM = 5;
91
91
 
92
- function findAgentDir(startPath) {
93
- let current = path.resolve(startPath);
94
- const root = path.parse(current).root;
95
- while (current !== root) {
96
- const agentDir = path.join(current, ".agent");
97
- if (fs.existsSync(agentDir) && fs.statSync(agentDir).isDirectory()) {
98
- return agentDir;
99
- }
100
- current = path.dirname(current);
101
- }
102
- return null;
103
- }
92
+ const { findAgentDir } = require("./_utils");
93
+
104
94
 
105
95
  // ─── Legacy mode: validate orchestrator micro-worker payloads ──────────────────
106
96
 
@@ -0,0 +1,69 @@
1
+ ---
2
+ name: 12-principles-of-animation
3
+ description: Application of Disney's 12 Principles of Animation (Squash & Stretch, Anticipation, Staging, Follow Through, Slow In & Slow Out, Arc, Secondary Action, Timing, Exaggeration, Solid Drawing, Appeal) to modern web UI motion.
4
+ version: 1.0.0
5
+ last-updated: 2026-07-22
6
+ applies-to-model: gemini-3-6-flash, claude-3-7-sonnet
7
+ routing:
8
+ domain: UI Animation Theory & Disney Principles
9
+ tier: pro
10
+ co-requires: [emil-design-eng, motion-engineering, 60fps-animation]
11
+ trigger-signals:
12
+ strong: [12-principles-of-animation, Disney animation principles, squash and stretch UI, anticipation animation, staging UI motion, follow through web]
13
+ weak: [animation principles, ui animation theory]
14
+ ---
15
+
16
+ # 12 Principles of Animation — Web UI Motion Theory
17
+
18
+ Translate Disney's 12 classic principles of animation into modern CSS, Web API, and Framer Motion code patterns.
19
+
20
+ ---
21
+
22
+ ## The 6 Essential Web Principles
23
+
24
+ ### 1. Squash & Stretch (Scale Elasticity)
25
+ - Compress elements slightly on impact (e.g. button press down `scale(0.97)`), then stretch slightly on release (`scale(1.02)` -> `scale(1)`).
26
+ - **Rule**: Preserve overall volume. If height decreases by 5%, width must expand by 5%.
27
+
28
+ ### 2. Anticipation (Pre-Motion Cue)
29
+ - Before a major movement (e.g. modal sliding up), perform a micro-backwards movement (e.g. shift down `2px` for `40ms`) to prepare the user's eye.
30
+
31
+ ### 3. Staging (Focus & Spatial Hierarchy)
32
+ - Direct user attention to one primary animation at a time. Never animate competing layout elements across different regions simultaneously.
33
+
34
+ ### 4. Slow In & Slow Out (Easing Curves)
35
+ - Objects in nature start slow, accelerate, and decelerate gradually. Use strong ease-out curves (`cubic-bezier(0.16, 1, 0.3, 1)`) for UI entrances.
36
+
37
+ ### 5. Arcs (Natural Curvilinear Trajectories)
38
+ - Human arms and physical objects move in curved arcs rather than mechanical straight lines. When moving elements across 2D space, use parabolic bezier curves or `offset-path`.
39
+
40
+ ### 6. Follow Through & Overlapping Action
41
+ - Secondary elements (e.g. badge text inside a sliding card) lag slightly behind the main container (stagger delay 30ms - 50ms), creating organic physical realism.
42
+
43
+ ---
44
+
45
+ ## 🤖 LLM-Specific Traps
46
+
47
+ 1. **Extreme Distortion**: Applying 30% squash and stretch to text buttons, causing distorted unreadable font rendering. Keep UI squash/stretch subtle (max 2% - 4%).
48
+ 2. **Mechanical Linear Motion**: Using `linear` easing for UI elements entering the screen.
49
+
50
+ ---
51
+
52
+ ## 🏛️ Tribunal Integration (Anti-Hallucination)
53
+
54
+ **Active reviewers: `motion-reviewer` · `frontend-reviewer`**
55
+
56
+ ### ✅ Pre-Flight Self-Audit
57
+
58
+ ```
59
+ ✅ Is squash & stretch volume-preserving ($Width \times Height \approx 1$)?
60
+ ✅ Are entrance animations using custom `ease-out` curves?
61
+ ✅ Is motion staged to lead user focus sequentially?
62
+ ```
63
+
64
+ ### 🛑 Verification-Before-Completion (VBC) Protocol
65
+
66
+ **CRITICAL:** You must follow a strict "evidence-based closeout" state machine.
67
+
68
+ - ❌ **Forbidden:** Declaring a task complete because the output "looks correct."
69
+ - ✅ **Required:** You are explicitly forbidden from finalizing any task without providing **concrete evidence** (terminal output, passing tests, compile success, or equivalent proof) that your output works as intended.