gienah 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +60 -0
- data/Rakefile +8 -0
- data/docs/adr/000-template.md +17 -0
- data/docs/adr/README.md +3 -0
- data/index.html +62 -0
- data/lib/gienah/future.rb +89 -0
- data/lib/gienah/host.rb +395 -0
- data/lib/gienah/manifest.rb +134 -0
- data/lib/gienah/plugin.rb +140 -0
- data/lib/gienah/protocol.rb +104 -0
- data/lib/gienah/sandbox.rb +56 -0
- data/lib/gienah/testing/fake_plugin.rb +80 -0
- data/lib/gienah/transport.rb +149 -0
- data/lib/gienah/version.rb +5 -0
- data/lib/gienah.rb +47 -0
- data/sig/gienah.rbs +117 -0
- data/site.css +247 -0
- metadata +78 -0
data/lib/gienah.rb
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "open3"
|
|
5
|
+
require "rbconfig"
|
|
6
|
+
require "pathname"
|
|
7
|
+
|
|
8
|
+
require_relative "gienah/version"
|
|
9
|
+
|
|
10
|
+
module Gienah
|
|
11
|
+
Value = if defined?(Data)
|
|
12
|
+
Module.new do
|
|
13
|
+
module_function
|
|
14
|
+
def define(*members) = Data.define(*members)
|
|
15
|
+
end
|
|
16
|
+
else
|
|
17
|
+
Module.new do
|
|
18
|
+
module_function
|
|
19
|
+
def define(*members)
|
|
20
|
+
Struct.new(*members) do
|
|
21
|
+
define_method(:initialize) do |*values, **keywords|
|
|
22
|
+
values = members.map { |member| keywords.fetch(member) } if values.empty? && !keywords.empty?
|
|
23
|
+
super(*values)
|
|
24
|
+
freeze
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
require_relative "gienah/protocol"
|
|
33
|
+
require_relative "gienah/future"
|
|
34
|
+
require_relative "gienah/manifest"
|
|
35
|
+
require_relative "gienah/sandbox"
|
|
36
|
+
require_relative "gienah/transport"
|
|
37
|
+
require_relative "gienah/host"
|
|
38
|
+
require_relative "gienah/plugin"
|
|
39
|
+
require_relative "gienah/testing/fake_plugin"
|
|
40
|
+
|
|
41
|
+
module Gienah
|
|
42
|
+
class Error < StandardError; end
|
|
43
|
+
class CapabilityDenied < Error; end
|
|
44
|
+
class Timeout < Error; end
|
|
45
|
+
class ProtocolError < Error; end
|
|
46
|
+
class LifecycleError < Error; end
|
|
47
|
+
end
|
data/sig/gienah.rbs
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
module Gienah
|
|
2
|
+
VERSION: String
|
|
3
|
+
|
|
4
|
+
type json = nil | bool | Integer | Float | String | Array[json] | Hash[String, json]
|
|
5
|
+
|
|
6
|
+
class Error < StandardError
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class CapabilityDenied < Error
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class Timeout < Error
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class ProtocolError < Error
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class LifecycleError < Error
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class Manifest
|
|
22
|
+
attr_reader id: String
|
|
23
|
+
attr_reader name: String
|
|
24
|
+
attr_reader version: String
|
|
25
|
+
attr_reader api_version: Integer
|
|
26
|
+
attr_reader entry: String
|
|
27
|
+
attr_reader activation: Array[String]
|
|
28
|
+
attr_reader capabilities: Array[String]
|
|
29
|
+
attr_reader contributes: Hash[String, json]
|
|
30
|
+
attr_reader limits: Hash[String, Numeric]
|
|
31
|
+
attr_reader root: String
|
|
32
|
+
def self.load: (String path) -> Manifest
|
|
33
|
+
def self.from_hash: (Hash[String, untyped] value, ?root: String) -> Manifest
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
module Protocol
|
|
37
|
+
MAX_MESSAGE: Integer
|
|
38
|
+
MAX_HEADER: Integer
|
|
39
|
+
def self.frame: (Hash[String, untyped] message, ?max_size: Integer) -> String
|
|
40
|
+
def self.read: (IO io, ?max_size: Integer) -> Hash[String, untyped]?
|
|
41
|
+
def self.validate_message: (Hash[String, untyped] message) -> Hash[String, untyped]
|
|
42
|
+
def self.request: (Integer id, String method, ?json params) -> Hash[String, untyped]
|
|
43
|
+
def self.notification: (String method, ?json params) -> Hash[String, untyped]
|
|
44
|
+
def self.response: (Integer id, ?result: json, ?error: Hash[String, json]) -> Hash[String, untyped]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class Future
|
|
48
|
+
attr_reader id: Integer
|
|
49
|
+
def initialize: (Integer id, ?on_cancel: ^(Integer) -> untyped) -> void
|
|
50
|
+
def fulfill: (?untyped value, ?error: Exception?) -> Future
|
|
51
|
+
def await: (?timeout: Numeric?) -> untyped
|
|
52
|
+
def then: () { (untyped, Exception?) -> untyped } -> Future
|
|
53
|
+
def cancel: () -> bool
|
|
54
|
+
def done?: () -> bool
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
module Sandbox
|
|
58
|
+
def self.dangerous?: (Array[String] capabilities) -> bool
|
|
59
|
+
def self.policy_for: (Array[String] capabilities, root: String) -> untyped
|
|
60
|
+
def self.available?: () -> bool
|
|
61
|
+
def self.ensure_safe!: (Array[String] capabilities) -> void
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
class Transport
|
|
65
|
+
attr_reader pid: Integer
|
|
66
|
+
def self.open: (Array[String] command, ?cwd: String?, ?env: Hash[String, String], ?policy: untyped) { (Hash[String, untyped]?, Exception?) -> untyped } -> Transport
|
|
67
|
+
def write: (Hash[String, untyped] message, ?max_size: Integer) -> nil
|
|
68
|
+
def alive?: () -> bool
|
|
69
|
+
def close: (?grace: Numeric) -> bool
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
class Host
|
|
73
|
+
attr_reader api_version: Integer
|
|
74
|
+
def initialize: (api_version: Integer, ?dispatch: ^(Instance, String, json) -> untyped, ?sandbox: bool, ?restart: Hash[Symbol, untyped], ?limits: Hash[Symbol, Numeric], ?transport_factory: ^(Manifest) { (Manifest) -> Transport }) -> void
|
|
75
|
+
def expose: (String method, ?capability: String?) { (Instance, json) -> untyped } -> Host
|
|
76
|
+
def discover: (Array[String] directories) -> Array[Manifest]
|
|
77
|
+
def add: (Manifest manifest) -> Manifest
|
|
78
|
+
def activate: (String id, reason: String) -> Instance?
|
|
79
|
+
def deactivate: (String id) -> untyped
|
|
80
|
+
def instances: () -> Array[Instance]
|
|
81
|
+
def disabled?: (String id) -> bool
|
|
82
|
+
def on_contribution: () { (String, Hash[String, json]) -> untyped } -> Host
|
|
83
|
+
def on_error: () { (Exception, Instance?) -> untyped } -> Host
|
|
84
|
+
def shutdown: () -> untyped
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
class Instance
|
|
88
|
+
attr_reader id: String
|
|
89
|
+
attr_reader manifest: Manifest
|
|
90
|
+
attr_reader state: Symbol
|
|
91
|
+
def start: () -> Instance
|
|
92
|
+
def call: (String method, ?json params, ?timeout: Numeric?) -> Future
|
|
93
|
+
def notify: (String method, ?json params) -> nil
|
|
94
|
+
def granted?: (String capability) -> bool
|
|
95
|
+
def kill: () -> nil
|
|
96
|
+
def shutdown: () -> untyped
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
module Plugin
|
|
100
|
+
def self.export: (String name) { (json) -> untyped } -> nil
|
|
101
|
+
def self.on: (String event) { (json) -> untyped } -> nil
|
|
102
|
+
def self.call: (String method, ?json params) -> untyped
|
|
103
|
+
def self.notify: (String method, ?json params) -> nil
|
|
104
|
+
def self.capability?: (String name) -> bool
|
|
105
|
+
def self.run: (?input: IO, ?output: IO) -> nil
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
module Testing
|
|
109
|
+
class FakePlugin
|
|
110
|
+
attr_reader capabilities: Array[String]
|
|
111
|
+
def initialize: (?capabilities: Array[String]) -> void
|
|
112
|
+
def export: (String method) { (json) -> untyped } -> FakePlugin
|
|
113
|
+
def on_notification: () { (String, json) -> untyped } -> FakePlugin
|
|
114
|
+
def transport: (Manifest) { (Hash[String, untyped]?, Exception?) -> untyped } -> Transport
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
data/site.css
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
color-scheme: dark;
|
|
3
|
+
--night: #060a13;
|
|
4
|
+
--deep: #0a1120;
|
|
5
|
+
--surface: #101a2d;
|
|
6
|
+
--surface-2: #152239;
|
|
7
|
+
--line: #283752;
|
|
8
|
+
--ink: #edf4ff;
|
|
9
|
+
--muted: #9aabc5;
|
|
10
|
+
--accent: #70dfc3;
|
|
11
|
+
--display: "Avenir Next Condensed", "Avenir Next", Avenir, "Segoe UI", sans-serif;
|
|
12
|
+
--body: "Avenir Next", Avenir, "Segoe UI", sans-serif;
|
|
13
|
+
--mono: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
* { box-sizing: border-box; }
|
|
17
|
+
html { scroll-behavior: smooth; }
|
|
18
|
+
body {
|
|
19
|
+
margin: 0;
|
|
20
|
+
background: var(--night);
|
|
21
|
+
color: var(--ink);
|
|
22
|
+
font-family: var(--body);
|
|
23
|
+
line-height: 1.6;
|
|
24
|
+
-webkit-font-smoothing: antialiased;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
a { color: inherit; }
|
|
28
|
+
.skip-link {
|
|
29
|
+
position: fixed;
|
|
30
|
+
top: 0.75rem;
|
|
31
|
+
left: 0.75rem;
|
|
32
|
+
z-index: 10;
|
|
33
|
+
padding: 0.65rem 0.9rem;
|
|
34
|
+
background: var(--ink);
|
|
35
|
+
color: var(--night);
|
|
36
|
+
transform: translateY(-150%);
|
|
37
|
+
}
|
|
38
|
+
.skip-link:focus { transform: translateY(0); }
|
|
39
|
+
:focus-visible { outline: 3px solid var(--accent); outline-offset: 4px; }
|
|
40
|
+
|
|
41
|
+
.site-header,
|
|
42
|
+
main,
|
|
43
|
+
footer {
|
|
44
|
+
width: min(100% - 3rem, 76rem);
|
|
45
|
+
margin-inline: auto;
|
|
46
|
+
}
|
|
47
|
+
.site-header {
|
|
48
|
+
display: flex;
|
|
49
|
+
align-items: center;
|
|
50
|
+
justify-content: space-between;
|
|
51
|
+
min-height: 5rem;
|
|
52
|
+
border-bottom: 1px solid var(--line);
|
|
53
|
+
}
|
|
54
|
+
.brand {
|
|
55
|
+
display: inline-flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
gap: 0.7rem;
|
|
58
|
+
font-family: var(--display);
|
|
59
|
+
font-size: 1.05rem;
|
|
60
|
+
font-weight: 700;
|
|
61
|
+
text-decoration: none;
|
|
62
|
+
}
|
|
63
|
+
.star-mark {
|
|
64
|
+
width: 0.7rem;
|
|
65
|
+
aspect-ratio: 1;
|
|
66
|
+
background: var(--accent);
|
|
67
|
+
border-radius: 50%;
|
|
68
|
+
}
|
|
69
|
+
nav { display: flex; gap: clamp(1rem, 3vw, 2rem); }
|
|
70
|
+
nav a, footer a { color: var(--muted); font-size: 0.875rem; text-decoration: none; }
|
|
71
|
+
nav a:hover, footer a:hover { color: var(--ink); }
|
|
72
|
+
|
|
73
|
+
.hero {
|
|
74
|
+
display: grid;
|
|
75
|
+
grid-template-columns: minmax(0, 1fr) minmax(23rem, 0.9fr);
|
|
76
|
+
gap: clamp(3rem, 8vw, 7rem);
|
|
77
|
+
align-items: center;
|
|
78
|
+
min-height: calc(100svh - 5rem);
|
|
79
|
+
padding-block: 5rem;
|
|
80
|
+
}
|
|
81
|
+
.constellation {
|
|
82
|
+
margin: 0 0 1.4rem;
|
|
83
|
+
color: var(--accent);
|
|
84
|
+
font-size: 0.9rem;
|
|
85
|
+
font-weight: 650;
|
|
86
|
+
}
|
|
87
|
+
h1, h2, h3, p { margin-top: 0; }
|
|
88
|
+
h1, h2 { font-family: var(--display); text-wrap: balance; }
|
|
89
|
+
p { text-wrap: pretty; }
|
|
90
|
+
h1 {
|
|
91
|
+
max-width: 9ch;
|
|
92
|
+
margin-bottom: 1.5rem;
|
|
93
|
+
font-size: clamp(4.8rem, 11vw, 8.5rem);
|
|
94
|
+
font-weight: 650;
|
|
95
|
+
line-height: 0.82;
|
|
96
|
+
}
|
|
97
|
+
.lede {
|
|
98
|
+
max-width: 38rem;
|
|
99
|
+
margin-bottom: 2rem;
|
|
100
|
+
color: #c3cfe2;
|
|
101
|
+
font-size: clamp(1.05rem, 2vw, 1.28rem);
|
|
102
|
+
line-height: 1.65;
|
|
103
|
+
}
|
|
104
|
+
.actions { display: flex; flex-wrap: wrap; gap: 0.75rem; }
|
|
105
|
+
.button {
|
|
106
|
+
display: inline-flex;
|
|
107
|
+
align-items: center;
|
|
108
|
+
min-height: 3rem;
|
|
109
|
+
padding: 0.65rem 1.1rem;
|
|
110
|
+
border: 1px solid var(--line);
|
|
111
|
+
color: var(--ink);
|
|
112
|
+
font-size: 0.9rem;
|
|
113
|
+
font-weight: 650;
|
|
114
|
+
text-decoration: none;
|
|
115
|
+
}
|
|
116
|
+
.button.primary { border-color: var(--accent); background: var(--accent); color: var(--night); }
|
|
117
|
+
.button:hover { border-color: var(--accent); }
|
|
118
|
+
.button.primary:hover { background: color-mix(in srgb, var(--accent) 80%, white); }
|
|
119
|
+
.facts {
|
|
120
|
+
display: flex;
|
|
121
|
+
flex-wrap: wrap;
|
|
122
|
+
gap: 1.5rem;
|
|
123
|
+
margin: 2.25rem 0 0;
|
|
124
|
+
padding: 0;
|
|
125
|
+
color: var(--muted);
|
|
126
|
+
font-size: 0.8rem;
|
|
127
|
+
list-style: none;
|
|
128
|
+
}
|
|
129
|
+
.facts strong { color: var(--ink); font-weight: 650; }
|
|
130
|
+
|
|
131
|
+
.instrument {
|
|
132
|
+
position: relative;
|
|
133
|
+
min-width: 0;
|
|
134
|
+
overflow: hidden;
|
|
135
|
+
border: 1px solid var(--line);
|
|
136
|
+
background: var(--surface);
|
|
137
|
+
box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
|
138
|
+
}
|
|
139
|
+
.instrument-head {
|
|
140
|
+
position: relative;
|
|
141
|
+
display: flex;
|
|
142
|
+
align-items: center;
|
|
143
|
+
justify-content: space-between;
|
|
144
|
+
min-height: 3rem;
|
|
145
|
+
padding-inline: 1rem;
|
|
146
|
+
border-bottom: 1px solid var(--line);
|
|
147
|
+
color: var(--muted);
|
|
148
|
+
font: 0.72rem var(--mono);
|
|
149
|
+
}
|
|
150
|
+
.signal { display: inline-flex; align-items: center; gap: 0.55rem; color: var(--accent); }
|
|
151
|
+
.signal::before { width: 0.45rem; aspect-ratio: 1; border-radius: 50%; background: currentColor; box-shadow: 0 0 0.8rem currentColor; content: ""; }
|
|
152
|
+
.instrument-body { position: relative; min-height: 25rem; padding: 1.5rem; font-family: var(--mono); font-variant-numeric: tabular-nums; }
|
|
153
|
+
.command { margin-bottom: 1.5rem; color: var(--muted); font-size: 0.78rem; }
|
|
154
|
+
.command b { color: var(--accent); font-weight: 500; }
|
|
155
|
+
.rows { border: 1px solid var(--line); background: rgb(6 10 19 / 0.58); }
|
|
156
|
+
.row {
|
|
157
|
+
display: grid;
|
|
158
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
159
|
+
gap: 1rem;
|
|
160
|
+
align-items: center;
|
|
161
|
+
min-height: 3.25rem;
|
|
162
|
+
padding: 0.65rem 0.8rem;
|
|
163
|
+
color: #cbd7e8;
|
|
164
|
+
font-size: 0.74rem;
|
|
165
|
+
}
|
|
166
|
+
.row + .row { border-top: 1px solid var(--line); }
|
|
167
|
+
.row strong { color: var(--ink); font-weight: 550; }
|
|
168
|
+
.row small { color: var(--muted); font-size: 0.68rem; }
|
|
169
|
+
.path { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
170
|
+
.hit { color: var(--night); background: var(--accent); }
|
|
171
|
+
.tag { padding: 0.18rem 0.4rem; border: 1px solid var(--line); color: var(--accent); font-size: 0.66rem; white-space: nowrap; }
|
|
172
|
+
.stream { display: grid; gap: 0.75rem; }
|
|
173
|
+
.message { max-width: 88%; padding: 0.8rem 0.9rem; border-left: 2px solid var(--accent); background: rgb(6 10 19 / 0.66); color: #ccd8e9; font-size: 0.74rem; }
|
|
174
|
+
.message:nth-child(even) { justify-self: end; border-color: var(--accent); }
|
|
175
|
+
.message small { display: block; margin-bottom: 0.3rem; color: var(--muted); }
|
|
176
|
+
.meter { display: grid; grid-template-columns: 5.5rem 1fr auto; gap: 0.75rem; align-items: center; color: var(--muted); font-size: 0.68rem; }
|
|
177
|
+
.meter + .meter { margin-top: 1rem; }
|
|
178
|
+
.track { height: 0.28rem; background: var(--line); }
|
|
179
|
+
.track i { display: block; width: var(--value); height: 100%; background: var(--accent); }
|
|
180
|
+
.diagram { position: relative; min-height: 20rem; }
|
|
181
|
+
.node { position: absolute; width: 7.5rem; padding: 0.7rem; border: 1px solid var(--line); background: var(--deep); color: var(--muted); font-size: 0.68rem; }
|
|
182
|
+
.node strong { display: block; margin-bottom: 0.25rem; color: var(--ink); font-size: 0.75rem; }
|
|
183
|
+
.node.core { inset: 38% auto auto 37%; border-color: var(--accent); }
|
|
184
|
+
.node.nw { inset: 4% auto auto 2%; }
|
|
185
|
+
.node.ne { inset: 2% 1% auto auto; }
|
|
186
|
+
.node.sw { inset: auto auto 3% 5%; }
|
|
187
|
+
.node.se { inset: auto 2% 5% auto; }
|
|
188
|
+
.orbit { position: absolute; inset: 19% 13%; border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent); border-radius: 50%; transform: rotate(-9deg); }
|
|
189
|
+
.code {
|
|
190
|
+
min-height: 12rem;
|
|
191
|
+
margin: 0;
|
|
192
|
+
overflow-x: auto;
|
|
193
|
+
color: #cbd7e8;
|
|
194
|
+
font: 0.76rem/1.85 var(--mono);
|
|
195
|
+
white-space: pre;
|
|
196
|
+
}
|
|
197
|
+
.code .key { color: var(--accent); }
|
|
198
|
+
.code .value { color: var(--accent); }
|
|
199
|
+
.code .dim { color: var(--muted); }
|
|
200
|
+
|
|
201
|
+
.features { padding-block: 7rem; border-block: 1px solid var(--line); }
|
|
202
|
+
.section-heading { display: grid; grid-template-columns: 0.9fr 1.1fr; gap: 4rem; align-items: end; }
|
|
203
|
+
h2 { margin-bottom: 0; font-size: clamp(2.6rem, 6vw, 5rem); line-height: 0.98; }
|
|
204
|
+
.section-heading p, .install-copy p { margin-bottom: 0; color: var(--muted); }
|
|
205
|
+
.feature-grid { display: grid; grid-template-columns: repeat(3, 1fr); margin-top: 4rem; border-top: 1px solid var(--line); }
|
|
206
|
+
.feature-grid article { padding: 2rem 2rem 0 0; }
|
|
207
|
+
.feature-grid article + article { padding-left: 2rem; border-left: 1px solid var(--line); }
|
|
208
|
+
h3 { margin-bottom: 0.8rem; font-size: 1.05rem; }
|
|
209
|
+
.feature-grid p { margin-bottom: 0; color: var(--muted); font-size: 0.9rem; }
|
|
210
|
+
|
|
211
|
+
.install { display: grid; grid-template-columns: 0.8fr 1.2fr; gap: 5rem; align-items: center; padding-block: 7rem; }
|
|
212
|
+
.install h2 { margin-bottom: 1.5rem; }
|
|
213
|
+
.terminal { min-width: 0; border: 1px solid var(--line); background: var(--deep); }
|
|
214
|
+
.terminal-bar { padding: 0.7rem 1rem; border-bottom: 1px solid var(--line); color: var(--muted); font: 0.68rem var(--mono); }
|
|
215
|
+
.terminal pre { margin: 0; padding: 1.3rem; overflow-x: auto; color: #d5deeb; font: 0.77rem/1.8 var(--mono); }
|
|
216
|
+
.terminal .prompt { color: var(--accent); }
|
|
217
|
+
|
|
218
|
+
footer { display: flex; justify-content: space-between; gap: 2rem; padding-block: 2rem; color: var(--muted); font-size: 0.8rem; }
|
|
219
|
+
footer p { margin: 0; }
|
|
220
|
+
footer div { display: flex; gap: 1.5rem; }
|
|
221
|
+
|
|
222
|
+
@media (max-width: 880px) {
|
|
223
|
+
.hero, .section-heading, .install { grid-template-columns: 1fr; }
|
|
224
|
+
.hero { min-height: auto; }
|
|
225
|
+
.instrument { max-width: 38rem; }
|
|
226
|
+
.section-heading, .install { gap: 2.5rem; }
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
@media (max-width: 620px) {
|
|
230
|
+
.site-header, main, footer { width: min(100% - 2rem, 76rem); }
|
|
231
|
+
.site-header { min-height: 4.25rem; }
|
|
232
|
+
nav a:not(:last-child) { display: none; }
|
|
233
|
+
.hero { padding-block: 3.5rem 4.5rem; }
|
|
234
|
+
h1 { font-size: clamp(4.1rem, 23vw, 6.25rem); }
|
|
235
|
+
.instrument { margin-inline: -1rem; }
|
|
236
|
+
.instrument-body { min-height: 22rem; padding: 1rem; }
|
|
237
|
+
.facts { gap: 0.75rem 1rem; }
|
|
238
|
+
.features, .install { padding-block: 4.5rem; }
|
|
239
|
+
.feature-grid { grid-template-columns: 1fr; margin-top: 2.5rem; }
|
|
240
|
+
.feature-grid article { padding: 1.5rem 0; }
|
|
241
|
+
.feature-grid article + article { padding-left: 0; border-top: 1px solid var(--line); border-left: 0; }
|
|
242
|
+
footer { flex-direction: column; }
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
@media (prefers-reduced-motion: reduce) {
|
|
246
|
+
html { scroll-behavior: auto; }
|
|
247
|
+
}
|
metadata
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: gienah
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Yudai Takada
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: saiph
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: 0.1.0
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: 0.1.0
|
|
26
|
+
description: Content-Length RPC, capability gates, lifecycle management, and a small
|
|
27
|
+
plugin SDK.
|
|
28
|
+
email:
|
|
29
|
+
- t.yudai92@gmail.com
|
|
30
|
+
executables: []
|
|
31
|
+
extensions: []
|
|
32
|
+
extra_rdoc_files: []
|
|
33
|
+
files:
|
|
34
|
+
- CHANGELOG.md
|
|
35
|
+
- LICENSE.txt
|
|
36
|
+
- README.md
|
|
37
|
+
- Rakefile
|
|
38
|
+
- docs/adr/000-template.md
|
|
39
|
+
- docs/adr/README.md
|
|
40
|
+
- index.html
|
|
41
|
+
- lib/gienah.rb
|
|
42
|
+
- lib/gienah/future.rb
|
|
43
|
+
- lib/gienah/host.rb
|
|
44
|
+
- lib/gienah/manifest.rb
|
|
45
|
+
- lib/gienah/plugin.rb
|
|
46
|
+
- lib/gienah/protocol.rb
|
|
47
|
+
- lib/gienah/sandbox.rb
|
|
48
|
+
- lib/gienah/testing/fake_plugin.rb
|
|
49
|
+
- lib/gienah/transport.rb
|
|
50
|
+
- lib/gienah/version.rb
|
|
51
|
+
- sig/gienah.rbs
|
|
52
|
+
- site.css
|
|
53
|
+
homepage: https://github.com/noxdea/gienah
|
|
54
|
+
licenses:
|
|
55
|
+
- MIT
|
|
56
|
+
metadata:
|
|
57
|
+
allowed_push_host: https://rubygems.org
|
|
58
|
+
source_code_uri: https://github.com/noxdea/gienah
|
|
59
|
+
changelog_uri: https://github.com/noxdea/gienah/blob/main/CHANGELOG.md
|
|
60
|
+
rubygems_mfa_required: 'true'
|
|
61
|
+
rdoc_options: []
|
|
62
|
+
require_paths:
|
|
63
|
+
- lib
|
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: 3.1.0
|
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
70
|
+
requirements:
|
|
71
|
+
- - ">="
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
version: '0'
|
|
74
|
+
requirements: []
|
|
75
|
+
rubygems_version: 4.0.16
|
|
76
|
+
specification_version: 4
|
|
77
|
+
summary: Out-of-process Ruby plugin host
|
|
78
|
+
test_files: []
|