tmux-ide 1.2.1 → 2.0.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.
Files changed (205) hide show
  1. package/bin/cli.js +4 -216
  2. package/bin/cli.ts +536 -0
  3. package/package.json +33 -14
  4. package/src/__tests__/support.ts +186 -0
  5. package/src/{attach.js → attach.ts} +7 -4
  6. package/src/cli.test.ts +314 -0
  7. package/src/command-center/discovery.test.ts +265 -0
  8. package/src/command-center/discovery.ts +296 -0
  9. package/src/command-center/index.ts +31 -0
  10. package/src/command-center/schemas.ts +57 -0
  11. package/src/command-center/server.test.ts +818 -0
  12. package/src/command-center/server.ts +1426 -0
  13. package/src/config-cli.test.ts +86 -0
  14. package/src/config.test.ts +205 -0
  15. package/src/config.ts +313 -0
  16. package/src/detect.test.ts +142 -0
  17. package/src/{detect.js → detect.ts} +31 -15
  18. package/src/dispatch.ts +102 -0
  19. package/src/doctor.test.ts +119 -0
  20. package/src/doctor.ts +167 -0
  21. package/src/init.test.ts +101 -0
  22. package/src/init.ts +144 -0
  23. package/src/inspect.test.ts +67 -0
  24. package/src/{inspect.js → inspect.ts} +95 -10
  25. package/src/integration.test.ts.skip +276 -0
  26. package/src/js-yaml.d.ts +10 -0
  27. package/src/launch.test.ts +222 -0
  28. package/src/launch.ts +494 -0
  29. package/src/lib/auth/auth-service.test.ts +178 -0
  30. package/src/lib/auth/auth-service.ts +227 -0
  31. package/src/lib/auth/middleware.test.ts +119 -0
  32. package/src/lib/auth/middleware.ts +56 -0
  33. package/src/lib/auth/types.ts +13 -0
  34. package/src/lib/authorship.test.ts +242 -0
  35. package/src/lib/authorship.ts +280 -0
  36. package/src/lib/cast/recorder.test.ts +127 -0
  37. package/src/lib/cast/recorder.ts +148 -0
  38. package/src/lib/daemon-watchdog.ts +102 -0
  39. package/src/lib/daemon.ts +417 -0
  40. package/src/lib/dot-path.test.ts +66 -0
  41. package/src/lib/dot-path.ts +17 -0
  42. package/src/lib/errors.ts +44 -0
  43. package/src/lib/event-log.test.ts +189 -0
  44. package/src/lib/event-log.ts +237 -0
  45. package/src/lib/github-pr.ts +182 -0
  46. package/src/lib/hq/client.test.ts +154 -0
  47. package/src/lib/hq/client.ts +142 -0
  48. package/src/lib/hq/mdns.test.ts +54 -0
  49. package/src/lib/hq/mdns.ts +88 -0
  50. package/src/lib/hq/registry.test.ts +237 -0
  51. package/src/lib/hq/registry.ts +145 -0
  52. package/src/lib/hq/types.ts +44 -0
  53. package/src/lib/ipc/socket-protocol.test.ts +126 -0
  54. package/src/lib/ipc/socket-protocol.ts +324 -0
  55. package/src/lib/launch-plan.test.ts +119 -0
  56. package/src/lib/launch-plan.ts +90 -0
  57. package/src/lib/log.test.ts +39 -0
  58. package/src/lib/log.ts +71 -0
  59. package/src/lib/metrics.test.ts +213 -0
  60. package/src/lib/metrics.ts +345 -0
  61. package/src/lib/orchestrator.test.ts +2358 -0
  62. package/src/lib/orchestrator.ts +1792 -0
  63. package/src/lib/{output.js → output.ts} +18 -10
  64. package/src/lib/plan-store.test.ts +148 -0
  65. package/src/lib/plan-store.ts +131 -0
  66. package/src/lib/research.test.ts +208 -0
  67. package/src/lib/research.ts +475 -0
  68. package/src/lib/round-trip.test.ts +341 -0
  69. package/src/lib/session-monitor.test.ts +152 -0
  70. package/src/lib/session-monitor.ts +282 -0
  71. package/src/lib/session-options.test.ts +146 -0
  72. package/src/lib/{session-options.js → session-options.ts} +11 -6
  73. package/src/lib/shell.test.ts +20 -0
  74. package/src/lib/shell.ts +8 -0
  75. package/src/lib/sizes.test.ts +73 -0
  76. package/src/lib/{sizes.js → sizes.ts} +4 -4
  77. package/src/lib/skill-registry.test.ts +134 -0
  78. package/src/lib/skill-registry.ts +86 -0
  79. package/src/lib/slugify.test.ts +35 -0
  80. package/src/lib/slugify.ts +10 -0
  81. package/src/lib/task-store.ts +352 -0
  82. package/src/lib/tmux.test.ts +500 -0
  83. package/src/lib/tmux.ts +372 -0
  84. package/src/lib/token-tracker.test.ts +102 -0
  85. package/src/lib/token-tracker.ts +70 -0
  86. package/src/lib/tunnels/cloudflare.test.ts +73 -0
  87. package/src/lib/tunnels/cloudflare.ts +254 -0
  88. package/src/lib/tunnels/manager.test.ts +63 -0
  89. package/src/lib/tunnels/manager.ts +132 -0
  90. package/src/lib/tunnels/ngrok.test.ts +94 -0
  91. package/src/lib/tunnels/ngrok.ts +261 -0
  92. package/src/lib/tunnels/tailscale.test.ts +103 -0
  93. package/src/lib/tunnels/tailscale.ts +1048 -0
  94. package/src/lib/tunnels/types.ts +44 -0
  95. package/src/lib/validation.test.ts +289 -0
  96. package/src/lib/validation.ts +123 -0
  97. package/src/lib/webhook.ts +51 -0
  98. package/src/lib/workflow-store.ts +209 -0
  99. package/src/lib/ws-v3/protocol.test.ts +127 -0
  100. package/src/lib/ws-v3/protocol.ts +160 -0
  101. package/src/lib/yaml-io.test.ts +125 -0
  102. package/src/lib/{yaml-io.js → yaml-io.ts} +5 -4
  103. package/src/ls.test.ts +76 -0
  104. package/src/{ls.js → ls.ts} +4 -4
  105. package/src/metrics-cli.ts +177 -0
  106. package/src/notify.ts +85 -0
  107. package/src/orchestrator-status.ts +228 -0
  108. package/src/plan.ts +117 -0
  109. package/src/postinstall.test.ts +79 -0
  110. package/src/remote.test.ts +115 -0
  111. package/src/remote.ts +148 -0
  112. package/src/restart.ts +24 -0
  113. package/src/schemas/domain.ts +422 -0
  114. package/src/schemas/ide-config.ts +148 -0
  115. package/src/schemas/index.ts +53 -0
  116. package/src/send.test.ts +70 -0
  117. package/src/send.ts +181 -0
  118. package/src/skill.test.ts +114 -0
  119. package/src/skill.ts +138 -0
  120. package/src/status.ts +66 -0
  121. package/src/stop.test.ts +176 -0
  122. package/src/stop.ts +47 -0
  123. package/src/task.test.ts +1466 -0
  124. package/src/task.ts +1143 -0
  125. package/src/tunnel.test.ts +80 -0
  126. package/src/tunnel.ts +133 -0
  127. package/src/types.ts +15 -0
  128. package/src/ui/index.ts +32 -0
  129. package/src/ui/terminal/index.ts +9 -0
  130. package/src/ui/types.ts +91 -0
  131. package/src/ui/web/base.css +80 -0
  132. package/src/ui/web/components/Box.tsx +59 -0
  133. package/src/ui/web/components/Input.tsx +32 -0
  134. package/src/ui/web/components/ScrollBox.tsx +60 -0
  135. package/src/ui/web/components/Text.tsx +28 -0
  136. package/src/ui/web/hooks.ts +106 -0
  137. package/src/ui/web/index.ts +27 -0
  138. package/src/ui/web/render.ts +77 -0
  139. package/src/ui/web/utils/color.test.ts +93 -0
  140. package/src/ui/web/utils/color.ts +27 -0
  141. package/src/validate.test.ts +385 -0
  142. package/src/validate.ts +217 -0
  143. package/src/widgets/changes/index.tsx +576 -0
  144. package/src/widgets/config/index.tsx +440 -0
  145. package/src/widgets/costs/index.tsx +216 -0
  146. package/src/widgets/explorer/breadcrumbs.tsx +77 -0
  147. package/src/widgets/explorer/footer.tsx +20 -0
  148. package/src/widgets/explorer/header.tsx +23 -0
  149. package/src/widgets/explorer/index.tsx +408 -0
  150. package/src/widgets/explorer/tree-model.test.ts +214 -0
  151. package/src/widgets/explorer/tree-model.ts +103 -0
  152. package/src/widgets/explorer/tree.tsx +156 -0
  153. package/src/widgets/lib/config-model.ts +116 -0
  154. package/src/widgets/lib/files.test.ts +103 -0
  155. package/src/widgets/lib/files.ts +88 -0
  156. package/src/widgets/lib/git.test.ts +151 -0
  157. package/src/widgets/lib/git.ts +88 -0
  158. package/src/widgets/lib/pane-comms.test.ts +178 -0
  159. package/src/widgets/lib/pane-comms.ts +192 -0
  160. package/src/widgets/lib/theme.ts +151 -0
  161. package/src/widgets/lib/watcher.ts +50 -0
  162. package/src/widgets/mission-control/activity-feed.tsx +59 -0
  163. package/src/widgets/mission-control/agent-panel.tsx +132 -0
  164. package/src/widgets/mission-control/command-bar.tsx +63 -0
  165. package/src/widgets/mission-control/index.tsx +751 -0
  166. package/src/widgets/mission-control/task-panel.tsx +238 -0
  167. package/src/widgets/preview/index.tsx +415 -0
  168. package/src/widgets/resolve.ts +40 -0
  169. package/src/widgets/setup/agent-naming.tsx +112 -0
  170. package/src/widgets/setup/config-tree.tsx +238 -0
  171. package/src/widgets/setup/detect-panel.tsx +72 -0
  172. package/src/widgets/setup/field-editor.tsx +265 -0
  173. package/src/widgets/setup/footer.tsx +107 -0
  174. package/src/widgets/setup/index.tsx +340 -0
  175. package/src/widgets/setup/layout-picker.tsx +96 -0
  176. package/src/widgets/setup/orchestrator-panel.tsx +200 -0
  177. package/src/widgets/setup/review-panel.tsx +140 -0
  178. package/src/widgets/setup/setup-model.test.ts +303 -0
  179. package/src/widgets/setup/setup-model.ts +188 -0
  180. package/src/widgets/tasks/index.tsx +129 -0
  181. package/src/widgets/tasks/task-detail.tsx +309 -0
  182. package/src/widgets/tasks/task-form.tsx +193 -0
  183. package/src/widgets/tasks/task-list.tsx +205 -0
  184. package/src/widgets/tasks/task-model.test.ts +473 -0
  185. package/src/widgets/tasks/task-model.ts +157 -0
  186. package/templates/AGENTS.md +20 -0
  187. package/templates/missions.yml +41 -0
  188. package/templates/skills/backend.md +30 -0
  189. package/templates/skills/frontend.md +30 -0
  190. package/templates/skills/general-worker.md +30 -0
  191. package/templates/skills/researcher.md +69 -0
  192. package/templates/skills/reviewer.md +30 -0
  193. package/src/config.js +0 -341
  194. package/src/doctor.js +0 -91
  195. package/src/init.js +0 -73
  196. package/src/launch.js +0 -245
  197. package/src/lib/dot-path.js +0 -16
  198. package/src/lib/errors.js +0 -35
  199. package/src/lib/launch-plan.js +0 -49
  200. package/src/lib/session-monitor.js +0 -179
  201. package/src/lib/tmux.js +0 -237
  202. package/src/restart.js +0 -16
  203. package/src/status.js +0 -35
  204. package/src/stop.js +0 -25
  205. package/src/validate.js +0 -154
@@ -0,0 +1,106 @@
1
+ import { createSignal, onMount, onCleanup } from "solid-js";
2
+
3
+ /** Synthetic key event passed to handlers (mirrors OpenTUI naming). */
4
+ export interface UiKeyEvent {
5
+ name: string;
6
+ ctrl: boolean;
7
+ shift: boolean;
8
+ alt: boolean;
9
+ meta: boolean;
10
+ preventDefault: () => void;
11
+ stopPropagation: () => void;
12
+ }
13
+
14
+ export function useKeyboard(handler: (evt: UiKeyEvent) => void): void {
15
+ onMount(() => {
16
+ const listener = (e: KeyboardEvent) => {
17
+ const evt = {
18
+ name: mapKeyName(e),
19
+ ctrl: e.ctrlKey,
20
+ shift: e.shiftKey,
21
+ alt: e.altKey,
22
+ meta: e.metaKey,
23
+ preventDefault: () => e.preventDefault(),
24
+ stopPropagation: () => e.stopPropagation(),
25
+ };
26
+ handler(evt);
27
+ };
28
+ document.addEventListener("keydown", listener);
29
+ onCleanup(() => document.removeEventListener("keydown", listener));
30
+ });
31
+ }
32
+
33
+ function mapKeyName(e: KeyboardEvent): string {
34
+ switch (e.key) {
35
+ case "ArrowUp":
36
+ return "up";
37
+ case "ArrowDown":
38
+ return "down";
39
+ case "ArrowLeft":
40
+ return "left";
41
+ case "ArrowRight":
42
+ return "right";
43
+ case "Enter":
44
+ return "return";
45
+ case "Escape":
46
+ return "escape";
47
+ case "Backspace":
48
+ return "backspace";
49
+ case "Tab":
50
+ return "tab";
51
+ case "Delete":
52
+ return "delete";
53
+ case " ":
54
+ return "space";
55
+ case "Home":
56
+ return "home";
57
+ case "End":
58
+ return "end";
59
+ case "PageUp":
60
+ return "pageup";
61
+ case "PageDown":
62
+ return "pagedown";
63
+ case "Insert":
64
+ return "insert";
65
+ default:
66
+ // @opentui convention: single-char keys are always lowercase, with shift as a modifier.
67
+ // Browser gives uppercase e.key for Shift+letter (e.g. "G"), so normalize to lowercase.
68
+ if (e.key.length === 1) return e.key.toLowerCase();
69
+ return e.key;
70
+ }
71
+ }
72
+
73
+ export function useTerminalDimensions() {
74
+ const [dims, setDims] = createSignal({ width: 80, height: 24 });
75
+
76
+ onMount(() => {
77
+ const update = () => {
78
+ // Measure a ch unit by using a temporary element
79
+ const measure = document.createElement("span");
80
+ measure.style.position = "absolute";
81
+ measure.style.visibility = "hidden";
82
+ measure.style.fontFamily = "var(--font-family, 'IBM Plex Mono', ui-monospace, monospace)";
83
+ measure.style.fontSize = "var(--font-size, 13px)";
84
+ measure.textContent = "0";
85
+ document.body.appendChild(measure);
86
+ const chWidth = measure.getBoundingClientRect().width;
87
+ document.body.removeChild(measure);
88
+
89
+ const lh = parseFloat(getComputedStyle(document.documentElement).lineHeight);
90
+
91
+ const effectiveCh = chWidth > 0 ? chWidth : 7.8; // fallback
92
+ const effectiveLh = lh > 0 ? lh : 18.2; // fallback
93
+
94
+ setDims({
95
+ width: Math.floor(window.innerWidth / effectiveCh),
96
+ height: Math.floor(window.innerHeight / effectiveLh),
97
+ });
98
+ };
99
+
100
+ update();
101
+ window.addEventListener("resize", update);
102
+ onCleanup(() => window.removeEventListener("resize", update));
103
+ });
104
+
105
+ return dims;
106
+ }
@@ -0,0 +1,27 @@
1
+ // Web mirror components — lowercase exports match @opentui JSX element names
2
+ export { Box as box } from "./components/Box.tsx";
3
+ export { Text as text } from "./components/Text.tsx";
4
+ export { ScrollBox as scrollbox } from "./components/ScrollBox.tsx";
5
+ export { Input as input } from "./components/Input.tsx";
6
+
7
+ // Render and hooks
8
+ export { render } from "./render.ts";
9
+ export { useKeyboard, useTerminalDimensions } from "./hooks.ts";
10
+
11
+ // Re-export Solid.js primitives
12
+ export {
13
+ Show,
14
+ For,
15
+ Switch,
16
+ Match,
17
+ createSignal,
18
+ createMemo,
19
+ createEffect,
20
+ onMount,
21
+ onCleanup,
22
+ batch,
23
+ } from "solid-js";
24
+
25
+ // Re-export shared types
26
+ export { RGBA, TextAttributes } from "../types.ts";
27
+ export type { BoxProps, TextProps, ScrollBoxProps, InputProps } from "../types.ts";
@@ -0,0 +1,77 @@
1
+ import type { JSX } from "solid-js";
2
+ import { render as solidRender } from "solid-js/web";
3
+
4
+ const BASE_CSS = `
5
+ :root {
6
+ --line-height: 1.4em;
7
+ --font-family: 'IBM Plex Mono', ui-monospace, monospace;
8
+ --font-size: 13px;
9
+ }
10
+
11
+ body, #root {
12
+ font-family: var(--font-family);
13
+ font-size: var(--font-size);
14
+ line-height: var(--line-height);
15
+ background: rgb(19, 16, 16);
16
+ color: rgb(232, 228, 228);
17
+ margin: 0;
18
+ padding: 0;
19
+ -webkit-font-smoothing: antialiased;
20
+ }
21
+
22
+ * {
23
+ box-sizing: border-box;
24
+ }
25
+
26
+ div {
27
+ display: flex;
28
+ flex-direction: column;
29
+ min-width: 0;
30
+ min-height: 0;
31
+ }
32
+
33
+ span {
34
+ font-family: inherit;
35
+ font-size: inherit;
36
+ line-height: inherit;
37
+ }
38
+
39
+ input {
40
+ font-family: inherit;
41
+ font-size: inherit;
42
+ line-height: inherit;
43
+ }
44
+
45
+ ::-webkit-scrollbar {
46
+ width: 8px;
47
+ }
48
+
49
+ ::-webkit-scrollbar-track {
50
+ background: rgb(25, 25, 35);
51
+ }
52
+
53
+ ::-webkit-scrollbar-thumb {
54
+ background: rgb(60, 60, 80);
55
+ border-radius: 4px;
56
+ }
57
+
58
+ ::-webkit-scrollbar-thumb:hover {
59
+ background: rgb(80, 80, 100);
60
+ }
61
+ `;
62
+
63
+ let stylesInjected = false;
64
+
65
+ function injectBaseStyles(): void {
66
+ if (stylesInjected) return;
67
+ const style = document.createElement("style");
68
+ style.textContent = BASE_CSS;
69
+ document.head.appendChild(style);
70
+ stylesInjected = true;
71
+ }
72
+
73
+ export function render(component: () => JSX.Element, _options?: unknown): void {
74
+ injectBaseStyles();
75
+ const root = document.getElementById("root") ?? document.body;
76
+ solidRender(component, root);
77
+ }
@@ -0,0 +1,93 @@
1
+ import { describe, it, expect } from "bun:test";
2
+ import { rgbaToCSS, attributesToStyle } from "./color.ts";
3
+ import { rgbaFromInts, TextAttributes } from "../../types.ts";
4
+
5
+ describe("rgbaToCSS", () => {
6
+ it("converts opaque color to rgb()", () => {
7
+ expect(rgbaToCSS({ r: 255, g: 128, b: 0, a: 255 })).toBe("rgb(255,128,0)");
8
+ });
9
+
10
+ it("converts transparent (a=0) to 'transparent'", () => {
11
+ expect(rgbaToCSS({ r: 100, g: 100, b: 100, a: 0 })).toBe("transparent");
12
+ });
13
+
14
+ it("converts semi-transparent color to rgba()", () => {
15
+ expect(rgbaToCSS({ r: 10, g: 20, b: 30, a: 128 })).toBe("rgba(10,20,30,0.50)");
16
+ });
17
+
18
+ it("handles rgbaFromInts()", () => {
19
+ const color = rgbaFromInts(75, 0, 130);
20
+ expect(rgbaToCSS(color)).toBe("rgb(75,0,130)");
21
+ });
22
+
23
+ it("rgbaFromInts defaults a to 255", () => {
24
+ const color = rgbaFromInts(1, 2, 3);
25
+ expect(color.a).toBe(255);
26
+ });
27
+
28
+ it("rgbaFromInts accepts explicit alpha", () => {
29
+ const color = rgbaFromInts(1, 2, 3, 100);
30
+ expect(color.a).toBe(100);
31
+ expect(rgbaToCSS(color)).toBe("rgba(1,2,3,0.39)");
32
+ });
33
+ });
34
+
35
+ describe("attributesToStyle", () => {
36
+ it("returns empty object for NONE", () => {
37
+ expect(attributesToStyle(TextAttributes.NONE)).toEqual({});
38
+ });
39
+
40
+ it("maps BOLD to font-weight", () => {
41
+ const style = attributesToStyle(TextAttributes.BOLD);
42
+ expect(style["font-weight"]).toBe("bold");
43
+ });
44
+
45
+ it("maps DIM to opacity", () => {
46
+ const style = attributesToStyle(TextAttributes.DIM);
47
+ expect(style.opacity).toBe("0.6");
48
+ });
49
+
50
+ it("maps ITALIC to font-style", () => {
51
+ const style = attributesToStyle(TextAttributes.ITALIC);
52
+ expect(style["font-style"]).toBe("italic");
53
+ });
54
+
55
+ it("maps UNDERLINE to text-decoration", () => {
56
+ const style = attributesToStyle(TextAttributes.UNDERLINE);
57
+ expect(style["text-decoration"]).toBe("underline");
58
+ });
59
+
60
+ it("maps STRIKETHROUGH to text-decoration", () => {
61
+ const style = attributesToStyle(TextAttributes.STRIKETHROUGH);
62
+ expect(style["text-decoration"]).toBe("line-through");
63
+ });
64
+
65
+ it("composes UNDERLINE + STRIKETHROUGH", () => {
66
+ const style = attributesToStyle(TextAttributes.UNDERLINE | TextAttributes.STRIKETHROUGH);
67
+ expect(style["text-decoration"]).toBe("underline line-through");
68
+ });
69
+
70
+ it("maps BLINK to animation", () => {
71
+ const style = attributesToStyle(TextAttributes.BLINK);
72
+ expect(style.animation?.includes("blink")).toBeTruthy();
73
+ });
74
+
75
+ it("maps INVERSE to filter invert", () => {
76
+ const style = attributesToStyle(TextAttributes.INVERSE);
77
+ expect(style.filter).toBe("invert(1)");
78
+ });
79
+
80
+ it("maps HIDDEN to visibility hidden", () => {
81
+ const style = attributesToStyle(TextAttributes.HIDDEN);
82
+ expect(style.visibility).toBe("hidden");
83
+ });
84
+
85
+ it("composes multiple attributes", () => {
86
+ const style = attributesToStyle(
87
+ TextAttributes.BOLD | TextAttributes.ITALIC | TextAttributes.UNDERLINE,
88
+ );
89
+ expect(style["font-weight"]).toBe("bold");
90
+ expect(style["font-style"]).toBe("italic");
91
+ expect(style["text-decoration"]).toBe("underline");
92
+ });
93
+ });
@@ -0,0 +1,27 @@
1
+ import type { RGBA } from "../../types.ts";
2
+
3
+ export function rgbaToCSS(color: RGBA): string {
4
+ if (color.a === 0) return "transparent";
5
+ if (color.a === 255 || color.a === undefined) {
6
+ return `rgb(${color.r},${color.g},${color.b})`;
7
+ }
8
+ return `rgba(${color.r},${color.g},${color.b},${(color.a / 255).toFixed(2)})`;
9
+ }
10
+
11
+ export function attributesToStyle(attrs: number): Record<string, string> {
12
+ const style: Record<string, string> = {};
13
+ if (attrs & 1) style["font-weight"] = "bold"; // BOLD
14
+ if (attrs & 2) style.opacity = "0.6"; // DIM
15
+ if (attrs & 4) style["font-style"] = "italic"; // ITALIC
16
+
17
+ // Compose text-decoration: underline and line-through can coexist
18
+ const decorations: string[] = [];
19
+ if (attrs & 8) decorations.push("underline"); // UNDERLINE
20
+ if (attrs & 128) decorations.push("line-through"); // STRIKETHROUGH
21
+ if (decorations.length > 0) style["text-decoration"] = decorations.join(" ");
22
+
23
+ if (attrs & 16) style.animation = "blink 1s step-end infinite"; // BLINK
24
+ if (attrs & 32) style.filter = "invert(1)"; // INVERSE
25
+ if (attrs & 64) style.visibility = "hidden"; // HIDDEN
26
+ return style;
27
+ }