@codyswann/lisa 2.210.3 → 2.211.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.
Files changed (52) hide show
  1. package/package.json +1 -1
  2. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  3. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  4. package/plugins/lisa-agy/plugin.json +1 -1
  5. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  6. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  7. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  8. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  9. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  10. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  11. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  12. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  13. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  14. package/plugins/lisa-expo-agy/plugin.json +1 -1
  15. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  16. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  17. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  18. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  19. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  20. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  22. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  24. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  25. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  26. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  27. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  28. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  29. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  30. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  34. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  35. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  37. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  39. package/plugins/lisa-rails-agy/plugin.json +1 -1
  40. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  42. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  44. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  45. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  49. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  50. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  52. package/ui/index.html +354 -40
package/package.json CHANGED
@@ -95,7 +95,7 @@
95
95
  "ws": ">=8.20.1"
96
96
  },
97
97
  "name": "@codyswann/lisa",
98
- "version": "2.210.3",
98
+ "version": "2.211.1",
99
99
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
100
100
  "main": "dist/index.js",
101
101
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "AWS CDK-specific Lisa plugin.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Expo and React Native-specific skills, agents, rules, and MCP servers.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Harper/Fabric-specific Lisa rules for TypeScript component apps.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "NestJS-specific skills and migration write-protection hooks.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Ruby on Rails-specific skills and hooks for RuboCop and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "TypeScript-specific hooks for formatting, linting, and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "Distributable LLM Wiki kernel — ingest, query, lint, and maintain a git-native markdown knowledge base across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.210.3",
3
+ "version": "2.211.1",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
package/ui/index.html CHANGED
@@ -761,6 +761,11 @@
761
761
  padding: 10px 18px 8px;
762
762
  border-bottom: 1px solid var(--line);
763
763
  }
764
+ table.grid th.th-help {
765
+ cursor: help;
766
+ text-decoration: underline dotted;
767
+ text-underline-offset: 3px;
768
+ }
764
769
  table.grid td {
765
770
  padding: 9px 18px;
766
771
  border-bottom: 1px solid var(--line);
@@ -1263,6 +1268,7 @@
1263
1268
  "tracker",
1264
1269
  "prd",
1265
1270
  "deploy",
1271
+ "pipelines",
1266
1272
  "automations",
1267
1273
  "monitor",
1268
1274
  ],
@@ -1271,7 +1277,7 @@
1271
1277
  label: "Quality",
1272
1278
  sections: ["linting", "testing", "hooks", "ci", "qa"],
1273
1279
  },
1274
- { label: "Distribution", sections: ["github", "plugins"] },
1280
+ { label: "Distribution", sections: ["repository", "plugins"] },
1275
1281
  { label: "Advanced", sections: ["advanced"] },
1276
1282
  ],
1277
1283
  sections: {},
@@ -1480,6 +1486,12 @@
1480
1486
  };
1481
1487
 
1482
1488
  /* ---------------------------------- Core workflow ---------------------------------- */
1489
+ // Shared header for the command tables: "Automation" is Lisa jargon, so
1490
+ // the column carries a hover tooltip defining it.
1491
+ const AUTOMATION_COL = {
1492
+ v: "Automation",
1493
+ tip: "The scheduled automation (created by /lisa:setup-automations) that already runs this command on a cadence. — means manual-only; “via intake” / “via implement” means it runs inside that command’s cycle. Invoke the command yourself to force a cycle now.",
1494
+ };
1483
1495
  DATA.sections.workflow = {
1484
1496
  title: "Core workflow",
1485
1497
  desc: "The slash commands that run the delivery loop — what each one does, when to reach for it yourself, and which scheduled automation already runs it for you.",
@@ -1500,9 +1512,9 @@
1500
1512
  },
1501
1513
  {
1502
1514
  type: "table",
1503
- card: "Core commands",
1515
+ card: "Delivery loop",
1504
1516
  note: "Commands marked with an automation run on a schedule — invoke them manually to force a cycle",
1505
- cols: ["Command", "What it does", "When to use it", "Automation"],
1517
+ cols: ["Command", "What it does", "When to use it", AUTOMATION_COL],
1506
1518
  rows: [
1507
1519
  [
1508
1520
  { t: "mono", v: "/lisa:intake" },
@@ -1570,6 +1582,13 @@
1570
1582
  { t: "text", v: "Close the loop on a shipped PRD" },
1571
1583
  { t: "mono", v: "via intake" },
1572
1584
  ],
1585
+ ],
1586
+ },
1587
+ {
1588
+ type: "table",
1589
+ card: "Commit & ship",
1590
+ cols: ["Command", "What it does", "When to use it", AUTOMATION_COL],
1591
+ rows: [
1573
1592
  [
1574
1593
  { t: "mono", v: "/lisa:git:commit" },
1575
1594
  {
@@ -1588,6 +1607,14 @@
1588
1607
  { t: "text", v: "When a branch is ready to ship" },
1589
1608
  { t: "mono", v: "—" },
1590
1609
  ],
1610
+ ],
1611
+ },
1612
+ {
1613
+ type: "table",
1614
+ card: "Feeder loops",
1615
+ note: "The three scheduled loops that keep the pipeline fed — exploratory bugs, ideated PRDs, and observability regressions",
1616
+ cols: ["Command", "What it does", "When to use it", AUTOMATION_COL],
1617
+ rows: [
1591
1618
  [
1592
1619
  { t: "mono", v: "/lisa:exploratory-qa" },
1593
1620
  {
@@ -1618,24 +1645,34 @@
1618
1645
  { t: "text", v: "On demand between scheduled runs" },
1619
1646
  { t: "mono", v: "monitor" },
1620
1647
  ],
1648
+ ],
1649
+ },
1650
+ {
1651
+ type: "table",
1652
+ card: "Onboarding & upkeep",
1653
+ cols: ["Command", "What it does", "When to use it", AUTOMATION_COL],
1654
+ rows: [
1621
1655
  [
1622
- { t: "mono", v: "/lisa:debrief" },
1656
+ { t: "mono", v: "/lisa:agent-ready" },
1623
1657
  {
1624
1658
  t: "text",
1625
- v: "Mines a shipped initiative tickets, PRs, review threads for learnings to triage",
1659
+ v: "Brownfield onboarding: builds the knowledge wiki from every reachable source and writes the human-answerable gaps file; absorbs answers on re-runs until zero gaps remain",
1660
+ },
1661
+ {
1662
+ t: "text",
1663
+ v: "Once per brownfield adoption — re-run in a fresh session after answering gaps, until it reports agent-ready",
1626
1664
  },
1627
- { t: "text", v: "After an initiative ships" },
1628
1665
  { t: "mono", v: "—" },
1629
1666
  ],
1630
1667
  [
1631
- { t: "mono", v: "/lisa:agent-ready" },
1668
+ { t: "mono", v: "/lisa:generate-claude-remote-build-script" },
1632
1669
  {
1633
1670
  t: "text",
1634
- v: "Brownfield onboarding: builds the knowledge wiki from every reachable source and writes the human-answerable gaps file; absorbs answers on re-runs until zero gaps remain",
1671
+ v: "Prepares the repo to run in a remote agentic VM (Claude Code remote): inventories what the environment needs via /lisa:analyze-claude-remote, then writes the idempotent setup script, an env-var template (names only, never secrets), and the network allowlist to paste into the routine environment",
1635
1672
  },
1636
1673
  {
1637
1674
  t: "text",
1638
- v: "Once per brownfield adoption re-run in a fresh session after answering gaps, until it reports agent-ready",
1675
+ v: "Once when wiring the project into a cloud environment; re-run when tooling or required secrets change",
1639
1676
  },
1640
1677
  { t: "mono", v: "—" },
1641
1678
  ],
@@ -1651,6 +1688,15 @@
1651
1688
  },
1652
1689
  { t: "mono", v: "—" },
1653
1690
  ],
1691
+ [
1692
+ { t: "mono", v: "/lisa:debrief" },
1693
+ {
1694
+ t: "text",
1695
+ v: "Mines a shipped initiative — tickets, PRs, review threads — for learnings to triage",
1696
+ },
1697
+ { t: "text", v: "After an initiative ships" },
1698
+ { t: "mono", v: "—" },
1699
+ ],
1654
1700
  ],
1655
1701
  },
1656
1702
  {
@@ -3049,19 +3095,192 @@
3049
3095
  ],
3050
3096
  };
3051
3097
 
3052
- /* ---------------------------------- Automations ---------------------------------- */
3098
+ /* ---------------------------------- Pipelines ---------------------------------- */
3099
+ DATA.sections.pipelines = {
3100
+ title: "Pipelines",
3101
+ desc: "Every pipeline Lisa seeds into the repository, what triggers it, and which section owns its configuration. Lisa always seeds a thin project-owned caller that invokes a versioned reusable pipeline, so the project can customize the caller without losing upstream fixes.",
3102
+ src: "<stack>/create-only/.github/workflows/ · reusable pipelines on @main",
3103
+ blocks: [
3104
+ {
3105
+ card: "Host",
3106
+ note: "Where pipelines run. Pipeline files are generated per host from the same role definitions below.",
3107
+ rows: [
3108
+ {
3109
+ key: "",
3110
+ label: "Pipeline host",
3111
+ desc: "GitHub Actions is the only host implemented today. GitLab CI and Bitbucket Pipelines are the intended next targets — the role inventory below is host-neutral, only the emitted file format changes.",
3112
+ control: sel("GitHub Actions", [
3113
+ "GitHub Actions",
3114
+ "GitLab CI",
3115
+ "Bitbucket Pipelines",
3116
+ ]),
3117
+ },
3118
+ {
3119
+ key: "",
3120
+ label: "Delivery model",
3121
+ desc: "Callers are create-only: seeded once, then owned by the project and never overwritten. The reusable pipelines they call are versioned upstream, so fixes land without touching the caller.",
3122
+ control: stat("create-only caller → reusable @main", "mono"),
3123
+ },
3124
+ ],
3125
+ },
3126
+ {
3127
+ type: "table",
3128
+ card: "Pipeline inventory",
3129
+ note: "Renaming a caller is safe; renaming the jobs inside it is not — job names are the status checks branch protection requires (see Quality gates)",
3130
+ cols: ["Pipeline", "Role", "Trigger", "Configured in"],
3131
+ rows: [
3132
+ [
3133
+ { t: "mono", v: "ci.yml → quality.yml" },
3134
+ { t: "text", v: "Quality — runs the full gate job matrix" },
3135
+ { t: "mono", v: "pull_request" },
3136
+ { t: "text", v: "Quality gates" },
3137
+ ],
3138
+ [
3139
+ { t: "mono", v: "deploy.yml → release.yml" },
3140
+ {
3141
+ t: "text",
3142
+ v: "Release — versions, promotes and deploys per environment",
3143
+ },
3144
+ { t: "mono", v: "push" },
3145
+ { t: "text", v: "Deploy & environments" },
3146
+ ],
3147
+ [
3148
+ { t: "mono", v: "maestro-e2e.yml → maestro-native-e2e.yml" },
3149
+ {
3150
+ t: "text",
3151
+ v: "Quality (Expo) — native iOS + Android Maestro suite; too heavy to gate PRs, so it runs nightly and on demand. Skips with a warning until the dev-e2e EAS profile, EXPO_TOKEN and flows exist.",
3152
+ },
3153
+ { t: "mono", v: "schedule (09:00 daily) · workflow_dispatch" },
3154
+ { t: "text", v: "Testing & coverage" },
3155
+ ],
3156
+ [
3157
+ { t: "mono", v: "claude-nightly-test-coverage.yml" },
3158
+ { t: "text", v: "Agent — raises test coverage overnight" },
3159
+ { t: "mono", v: "schedule (03:00 Mon–Fri)" },
3160
+ { t: "text", v: "Agent automations" },
3161
+ ],
3162
+ [
3163
+ { t: "mono", v: "claude-nightly-test-improvement.yml" },
3164
+ {
3165
+ t: "text",
3166
+ v: "Agent — strengthens weak assertions overnight",
3167
+ },
3168
+ { t: "mono", v: "schedule (04:00 Mon–Fri)" },
3169
+ { t: "text", v: "Agent automations" },
3170
+ ],
3171
+ [
3172
+ { t: "mono", v: "claude-nightly-code-complexity.yml" },
3173
+ {
3174
+ t: "text",
3175
+ v: "Agent — reduces complexity hotspots overnight",
3176
+ },
3177
+ { t: "mono", v: "schedule (05:00 Mon–Fri)" },
3178
+ { t: "text", v: "Agent automations" },
3179
+ ],
3180
+ [
3181
+ { t: "mono", v: "claude-ci-auto-fix.yml" },
3182
+ {
3183
+ t: "text",
3184
+ v: "Agent — investigates a failed quality run and pushes a fix",
3185
+ },
3186
+ { t: "mono", v: "workflow_run (on failure)" },
3187
+ { t: "text", v: "—" },
3188
+ ],
3189
+ [
3190
+ { t: "mono", v: "claude-deploy-auto-fix.yml" },
3191
+ {
3192
+ t: "text",
3193
+ v: "Agent — investigates a failed deploy and opens a fix PR",
3194
+ },
3195
+ { t: "mono", v: "workflow_run (on failure)" },
3196
+ { t: "text", v: "Deploy & environments" },
3197
+ ],
3198
+ [
3199
+ { t: "mono", v: "claude-code-review-response.yml" },
3200
+ {
3201
+ t: "text",
3202
+ v: "Agent — answers review feedback and pushes the accepted changes",
3203
+ },
3204
+ { t: "mono", v: "pull_request_review" },
3205
+ { t: "text", v: "—" },
3206
+ ],
3207
+ [
3208
+ { t: "mono", v: "claude.yml" },
3209
+ {
3210
+ t: "text",
3211
+ v: "Agent — responds when a human @-mentions the agent on an issue or PR",
3212
+ },
3213
+ { t: "mono", v: "issue_comment · review_comment" },
3214
+ { t: "text", v: "—" },
3215
+ ],
3216
+ [
3217
+ { t: "mono", v: "claude-sync-down-branches.yml" },
3218
+ {
3219
+ t: "text",
3220
+ v: "Upkeep — propagates a merge back down the environment chain",
3221
+ },
3222
+ { t: "mono", v: "pull_request" },
3223
+ { t: "text", v: "Deploy & environments" },
3224
+ ],
3225
+ [
3226
+ { t: "mono", v: "auto-update-pr-branches.yml" },
3227
+ {
3228
+ t: "text",
3229
+ v: "Upkeep — keeps open PRs rebased on their base",
3230
+ },
3231
+ { t: "mono", v: "push · pull_request" },
3232
+ { t: "text", v: "—" },
3233
+ ],
3234
+ [
3235
+ { t: "mono", v: "auto-update-pr-branches-dispatch.yml" },
3236
+ {
3237
+ t: "text",
3238
+ v: "Upkeep — on-demand handler for the same rebase, via repository dispatch",
3239
+ },
3240
+ { t: "mono", v: "repository_dispatch" },
3241
+ { t: "text", v: "—" },
3242
+ ],
3243
+ [
3244
+ { t: "mono", v: "zap-baseline.yml" },
3245
+ {
3246
+ t: "text",
3247
+ v: "Security — DAST baseline scan against a running app",
3248
+ },
3249
+ { t: "mono", v: "pull_request" },
3250
+ { t: "text", v: "Repository & protection" },
3251
+ ],
3252
+ [
3253
+ { t: "mono", v: "publish-to-npm.yml" },
3254
+ {
3255
+ t: "text",
3256
+ v: "Publish — OIDC trusted publish; called by the release pipeline, never directly",
3257
+ },
3258
+ { t: "mono", v: "workflow_call" },
3259
+ { t: "text", v: "Project types (npm-package)" },
3260
+ ],
3261
+ ],
3262
+ },
3263
+ {
3264
+ type: "callout",
3265
+ text: "Not every stack gets every pipeline. The quality and release callers are seeded for all stacks; the agent and upkeep pipelines come from the TypeScript stack and are inherited by everything built on it; <b>zap-baseline.yml</b> is Harper Fabric and <b>publish-to-npm.yml</b> is npm-package. Rails swaps the quality caller for <b>quality-rails.yml</b>.",
3266
+ },
3267
+ ],
3268
+ };
3269
+
3270
+ /* ---------------------------------- Agent automations ---------------------------------- */
3053
3271
  DATA.sections.automations = {
3054
- title: "Automations",
3055
- desc: "The scheduled fleet that runs the factories: pipeline movers (intake, repair) and the three feeding loops (QA, Product Planning, Monitoring), on the harness\u2019s native scheduler. Names carry a stable lisa-auto-<project>- prefix so teardown is precise.",
3056
- src: "plugins/src/base/skills/lisa-setup-automations",
3272
+ title: "Agent automations",
3273
+ desc: "All agent work that runs on a schedule, whichever machine fires it: the fleet that runs the factories \u2014 pipeline movers (intake, repair) and the three feeding loops (QA, Product Planning, Monitoring) \u2014 on the harness\u2019s native scheduler, plus the nightly improvement agents that run on the pipeline host. Harness names carry a stable lisa-auto-<project>- prefix so teardown is precise.",
3274
+ src: "plugins/src/base/skills/lisa-setup-automations \u00b7 claude-nightly-*.yml",
3057
3275
  blocks: [
3058
3276
  {
3059
3277
  type: "table",
3060
3278
  card: "Scheduled jobs",
3061
- note: "Status and next run are mocked \u2014 live wiring is LCW-1 (#1544)",
3279
+ note: "Status and next run are mocked \u2014 live wiring is LCW-1 (#1544). Runs on = which scheduler fires the job; the nightly agents are pipeline files, inventoried under Pipelines.",
3062
3280
  cols: [
3063
3281
  "Automation",
3064
3282
  "What it does",
3283
+ "Runs on",
3065
3284
  "Cadence",
3066
3285
  "Last run",
3067
3286
  "Next run",
@@ -3074,6 +3293,7 @@
3074
3293
  t: "text",
3075
3294
  v: "Claims the next build-ready ticket and runs the full build flow on it \u2014 one item per cycle",
3076
3295
  },
3296
+ { t: "badge", v: "harness", cls: "default" },
3077
3297
  {
3078
3298
  t: "select",
3079
3299
  v: "every 10 min",
@@ -3094,6 +3314,7 @@
3094
3314
  t: "text",
3095
3315
  v: "Validates the next ready PRD at the gate and either creates its work units or blocks it with clarifying questions",
3096
3316
  },
3317
+ { t: "badge", v: "harness", cls: "default" },
3097
3318
  {
3098
3319
  t: "select",
3099
3320
  v: "every 60 min",
@@ -3114,6 +3335,7 @@
3114
3335
  t: "text",
3115
3336
  v: "Finds stuck work \u2014 stalled builds, half-closed items, unreconciled rollups \u2014 and repairs each one",
3116
3337
  },
3338
+ { t: "badge", v: "harness", cls: "default" },
3117
3339
  {
3118
3340
  t: "select",
3119
3341
  v: "every 60 min",
@@ -3134,6 +3356,7 @@
3134
3356
  t: "text",
3135
3357
  v: "QA loop: explores the product like a first-time user (respecting the mutation policy) and files bugs build-ready",
3136
3358
  },
3359
+ { t: "badge", v: "harness", cls: "default" },
3137
3360
  { t: "select", v: "daily", options: ["daily", "weekly"] },
3138
3361
  {
3139
3362
  t: "run",
@@ -3150,6 +3373,7 @@
3150
3373
  t: "text",
3151
3374
  v: "Product Planning loop: ideates improvements and writes PRDs prd-ready",
3152
3375
  },
3376
+ { t: "badge", v: "harness", cls: "default" },
3153
3377
  { t: "select", v: "daily", options: ["daily", "weekly"] },
3154
3378
  {
3155
3379
  t: "run",
@@ -3166,6 +3390,7 @@
3166
3390
  t: "text",
3167
3391
  v: "Monitoring loop: audits the connected observability providers against the alert thresholds and files regression tickets",
3168
3392
  },
3393
+ { t: "badge", v: "harness", cls: "default" },
3169
3394
  { t: "select", v: "daily", options: ["daily", "weekly"] },
3170
3395
  {
3171
3396
  t: "run",
@@ -3176,6 +3401,57 @@
3176
3401
  { t: "mono", v: "tomorrow 05:00" },
3177
3402
  { t: "toggle", v: true },
3178
3403
  ],
3404
+ [
3405
+ { t: "mono", v: "nightly-test-coverage" },
3406
+ {
3407
+ t: "text",
3408
+ v: "Raises test coverage toward the thresholds and opens a PR \u2014 one module per run",
3409
+ },
3410
+ { t: "badge", v: "pipeline host", cls: "default" },
3411
+ { t: "mono", v: "03:00 Mon\u2013Fri" },
3412
+ {
3413
+ t: "run",
3414
+ ok: true,
3415
+ v: "03:00",
3416
+ reason: "ok \u2014 PR opened",
3417
+ },
3418
+ { t: "mono", v: "tomorrow 03:00" },
3419
+ { t: "toggle", v: true },
3420
+ ],
3421
+ [
3422
+ { t: "mono", v: "nightly-test-improvement" },
3423
+ {
3424
+ t: "text",
3425
+ v: "Strengthens weak assertions in existing tests and opens a PR",
3426
+ },
3427
+ { t: "badge", v: "pipeline host", cls: "default" },
3428
+ { t: "mono", v: "04:00 Mon\u2013Fri" },
3429
+ {
3430
+ t: "run",
3431
+ ok: true,
3432
+ v: "04:00",
3433
+ reason: "ok \u2014 PR opened",
3434
+ },
3435
+ { t: "mono", v: "tomorrow 04:00" },
3436
+ { t: "toggle", v: true },
3437
+ ],
3438
+ [
3439
+ { t: "mono", v: "nightly-code-complexity" },
3440
+ {
3441
+ t: "text",
3442
+ v: "Refactors a complexity hotspot without changing behavior and opens a PR",
3443
+ },
3444
+ { t: "badge", v: "pipeline host", cls: "default" },
3445
+ { t: "mono", v: "05:00 Mon\u2013Fri" },
3446
+ {
3447
+ t: "run",
3448
+ ok: true,
3449
+ v: "05:00",
3450
+ reason: "ok \u2014 no hotspot over budget",
3451
+ },
3452
+ { t: "mono", v: "tomorrow 05:00" },
3453
+ { t: "toggle", v: true },
3454
+ ],
3179
3455
  ],
3180
3456
  },
3181
3457
  {
@@ -3831,6 +4107,24 @@
3831
4107
  },
3832
4108
  ],
3833
4109
  },
4110
+ {
4111
+ card: "E2E route coverage floors",
4112
+ note: "e2e.thresholds.json — Expo projects; enforced statically by the E2E Route Coverage quality job on every PR",
4113
+ rows: [
4114
+ {
4115
+ key: "quality.e2eCoverage.playwright.routes",
4116
+ label: "Playwright routes",
4117
+ desc: "% of expo-router routes reached by at least one Playwright spec (page.goto or an e2e-route annotation). 0 disables that runner’s gate.",
4118
+ control: num(80, "%"),
4119
+ },
4120
+ {
4121
+ key: "quality.e2eCoverage.maestro.routes",
4122
+ label: "Maestro routes",
4123
+ desc: "% of expo-router routes reached by at least one Maestro flow (openLink or an e2e-route annotation). 0 disables that runner’s gate.",
4124
+ control: num(80, "%"),
4125
+ },
4126
+ ],
4127
+ },
3834
4128
  {
3835
4129
  card: "Mutation testing",
3836
4130
  note: "StrykerJS for JS/TS, mutant for Rails — both opt-in and diff-only",
@@ -3980,30 +4274,13 @@
3980
4274
 
3981
4275
  /* ---------------------------------- CI ---------------------------------- */
3982
4276
  DATA.sections.ci = {
3983
- title: "CI quality gates",
3984
- desc: "Every project’s ci.yml is a thin caller of Lisa’s reusable quality workflow. Each job below reports a status check on the PR; branch rulesets require the critical ones to pass before merge.",
3985
- src: ".github/workflows/quality.yml · <stack>/create-only/.github/workflows/ci.yml",
4277
+ title: "Quality gates",
4278
+ desc: "The merge contract: what must be true before a pull request can land. Each job below reports a status check, and branch protection requires the critical ones to pass. Which pipeline runs these jobs, and on what host, is configured under Pipelines.",
4279
+ src: "quality.yml (reusable) · called by the project’s quality pipeline",
3986
4280
  blocks: [
3987
4281
  {
3988
- card: "Pipeline",
3989
- note: "create-only ci.yml calling Lisa’s reusable quality workflow",
3990
- rows: [
3991
- {
3992
- key: "",
3993
- label: "CI provider",
3994
- desc: "Where quality checks run. GitHub Actions is the only supported runner today; the template model leaves room for more.",
3995
- control: sel("GitHub Actions", ["GitHub Actions"]),
3996
- },
3997
- {
3998
- key: "",
3999
- label: "Workflows",
4000
- desc: "ci.yml is seeded once and project-owned; it calls Lisa’s reusable quality workflow on every pull request.",
4001
- control: stat("ci.yml → quality.yml@main", "mono"),
4002
- },
4003
- ],
4004
- },
4005
- {
4006
- card: "Workflow inputs",
4282
+ card: "Gate inputs",
4283
+ note: "Inputs the project’s quality pipeline passes to Lisa’s reusable quality workflow",
4007
4284
  rows: [
4008
4285
  {
4009
4286
  key: "node_version",
@@ -4123,6 +4400,14 @@
4123
4400
  },
4124
4401
  { t: "status", v: true },
4125
4402
  ],
4403
+ [
4404
+ { t: "mono", v: "🧭 E2E Route Coverage" },
4405
+ {
4406
+ t: "text",
4407
+ v: "Static gate: % of expo-router routes reached by Playwright specs and Maestro flows, against the floors in e2e.thresholds.json — auto-enabled on Expo projects, a no-op elsewhere",
4408
+ },
4409
+ { t: "status", v: true },
4410
+ ],
4126
4411
  [
4127
4412
  { t: "mono", v: "🧬 Mutation Testing Gate" },
4128
4413
  {
@@ -4345,11 +4630,22 @@
4345
4630
  };
4346
4631
 
4347
4632
  /* ---------------------------------- GitHub repo ---------------------------------- */
4348
- DATA.sections.github = {
4349
- title: "GitHub repository",
4350
- desc: "Repo-level governance provisioned by lisa-github-repo-setup: merge policy, rulesets with required checks, lifecycle labels, deploy key and expected secrets.",
4633
+ DATA.sections.repository = {
4634
+ title: "Repository & protection",
4635
+ desc: "Repo-level governance on the git host: merge policy, branch protection with required status checks, lifecycle labels, deploy key and expected secrets. The controls below are those of the configured host — GitHub is the only one implemented today, so they are GitHub’s rulesets and settings.",
4351
4636
  src: "scripts/lisa-github-repo-setup.sh · all/github-rulesets/",
4352
4637
  blocks: [
4638
+ {
4639
+ card: "Host",
4640
+ rows: [
4641
+ {
4642
+ key: "",
4643
+ label: "Git host",
4644
+ desc: "Which host this repository lives on. GitHub is the only host Lisa provisions today; GitLab and Bitbucket would map the same governance onto their own primitives (protected branches instead of rulesets). Note this is separate from the tracker — a project can host code on one and track work on another.",
4645
+ control: sel("GitHub", ["GitHub", "GitLab", "Bitbucket"]),
4646
+ },
4647
+ ],
4648
+ },
4353
4649
  {
4354
4650
  card: "Repository settings",
4355
4651
  note: "github.settings.* overrides the baseline per key",
@@ -4589,6 +4885,14 @@
4589
4885
  { t: "text", v: "Maestro Cloud mobile E2E" },
4590
4886
  { t: "badge", v: "set", cls: "on" },
4591
4887
  ],
4888
+ [
4889
+ { t: "mono", v: "MAESTRO_SECRET_ENV" },
4890
+ {
4891
+ t: "text",
4892
+ v: "Native Maestro e2e — newline-separated KEY=VALUE secrets forwarded to flows (test-account passwords)",
4893
+ },
4894
+ { t: "badge", v: "missing", cls: "off" },
4895
+ ],
4592
4896
  ],
4593
4897
  },
4594
4898
  ],
@@ -5076,7 +5380,17 @@
5076
5380
  const table = el("table", "grid");
5077
5381
  const thead = el("thead");
5078
5382
  const trh = el("tr");
5079
- block.cols.forEach(c => trh.appendChild(el("th", "", esc(c))));
5383
+ block.cols.forEach(c => {
5384
+ // Cols accept either a plain string or {v, tip} — tip renders as a
5385
+ // hover tooltip on the header for jargon that needs a definition.
5386
+ if (typeof c === "string") {
5387
+ trh.appendChild(el("th", "", esc(c)));
5388
+ return;
5389
+ }
5390
+ const th = el("th", c.tip ? "th-help" : "", esc(c.v));
5391
+ if (c.tip) th.title = c.tip;
5392
+ trh.appendChild(th);
5393
+ });
5080
5394
  thead.appendChild(trh);
5081
5395
  table.appendChild(thead);
5082
5396
  const tbody = el("tbody");