strom-research 1.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 (130) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +142 -0
  3. package/assets/lang/cs.json +302 -0
  4. package/assets/lang/de.json +302 -0
  5. package/assets/method/core.md +43 -0
  6. package/assets/method/enrich.md +11 -0
  7. package/assets/method/intake.md +30 -0
  8. package/assets/method/link.md +28 -0
  9. package/assets/method/locate.md +28 -0
  10. package/assets/method/narrate.md +13 -0
  11. package/assets/method/reading.md +62 -0
  12. package/assets/method/recording.md +59 -0
  13. package/assets/method/request.md +10 -0
  14. package/assets/method/verify.md +17 -0
  15. package/assets/plugins/README.md +23 -0
  16. package/assets/plugins/connectors/DISCOVERY.md +159 -0
  17. package/assets/plugins/connectors/README.md +376 -0
  18. package/assets/plugins/connectors/sdk.ts +168 -0
  19. package/assets/plugins/connectors/template.ts +38 -0
  20. package/assets/plugins/gitignore +4 -0
  21. package/dist/agents/files.js +313 -0
  22. package/dist/agents/global.js +257 -0
  23. package/dist/agents/launch.js +36 -0
  24. package/dist/agents/profiles.js +95 -0
  25. package/dist/brief/brief.js +345 -0
  26. package/dist/cli/commit.js +44 -0
  27. package/dist/cli/context.js +311 -0
  28. package/dist/cli/execute.js +154 -0
  29. package/dist/cli/fixes.js +78 -0
  30. package/dist/cli/format.js +53 -0
  31. package/dist/cli/help.js +59 -0
  32. package/dist/cli/main.js +152 -0
  33. package/dist/cli/menu.js +212 -0
  34. package/dist/cli/registry.js +96 -0
  35. package/dist/cli/ui.js +266 -0
  36. package/dist/cli/wizard.js +142 -0
  37. package/dist/cli.js +14 -0
  38. package/dist/commands/analysis.js +622 -0
  39. package/dist/commands/batch.js +181 -0
  40. package/dist/commands/checks.js +153 -0
  41. package/dist/commands/connectors.js +1377 -0
  42. package/dist/commands/guide.js +160 -0
  43. package/dist/commands/index.js +19 -0
  44. package/dist/commands/intake.js +234 -0
  45. package/dist/commands/media.js +406 -0
  46. package/dist/commands/meta.js +195 -0
  47. package/dist/commands/output.js +117 -0
  48. package/dist/commands/people.js +664 -0
  49. package/dist/commands/read.js +199 -0
  50. package/dist/commands/research.js +139 -0
  51. package/dist/commands/session.js +605 -0
  52. package/dist/commands/setup.js +465 -0
  53. package/dist/commands/sources.js +634 -0
  54. package/dist/commands/start.js +383 -0
  55. package/dist/commands/story.js +75 -0
  56. package/dist/commands/tasks.js +436 -0
  57. package/dist/commands/trees.js +128 -0
  58. package/dist/core/actions.js +852 -0
  59. package/dist/core/age.js +95 -0
  60. package/dist/core/apps.js +74 -0
  61. package/dist/core/assets.js +34 -0
  62. package/dist/core/awake.js +33 -0
  63. package/dist/core/browser.js +281 -0
  64. package/dist/core/calibration.js +48 -0
  65. package/dist/core/check.js +112 -0
  66. package/dist/core/chromium.js +88 -0
  67. package/dist/core/config.js +348 -0
  68. package/dist/core/connector.js +811 -0
  69. package/dist/core/deps.js +73 -0
  70. package/dist/core/dialog.js +61 -0
  71. package/dist/core/errors.js +89 -0
  72. package/dist/core/evidence.js +58 -0
  73. package/dist/core/frontier.js +219 -0
  74. package/dist/core/gdate.js +77 -0
  75. package/dist/core/git.js +300 -0
  76. package/dist/core/guard.js +124 -0
  77. package/dist/core/http2.js +76 -0
  78. package/dist/core/import.js +541 -0
  79. package/dist/core/install.js +28 -0
  80. package/dist/core/integrity.js +219 -0
  81. package/dist/core/json.js +87 -0
  82. package/dist/core/lang.js +70 -0
  83. package/dist/core/live.js +244 -0
  84. package/dist/core/lock.js +112 -0
  85. package/dist/core/logins.js +67 -0
  86. package/dist/core/media.js +223 -0
  87. package/dist/core/model.js +101 -0
  88. package/dist/core/net.js +366 -0
  89. package/dist/core/open.js +29 -0
  90. package/dist/core/paths.js +84 -0
  91. package/dist/core/people.js +283 -0
  92. package/dist/core/phrases.js +85 -0
  93. package/dist/core/queue.js +113 -0
  94. package/dist/core/reader.js +76 -0
  95. package/dist/core/records.js +105 -0
  96. package/dist/core/roles.js +30 -0
  97. package/dist/core/schema.js +261 -0
  98. package/dist/core/seal.js +77 -0
  99. package/dist/core/self.js +40 -0
  100. package/dist/core/session.js +155 -0
  101. package/dist/core/shortcut.js +90 -0
  102. package/dist/core/stories.js +61 -0
  103. package/dist/core/stromapp.js +138 -0
  104. package/dist/core/text.js +104 -0
  105. package/dist/core/tree.js +507 -0
  106. package/dist/core/uninstall.js +128 -0
  107. package/dist/core/update.js +193 -0
  108. package/dist/core/validate.js +260 -0
  109. package/dist/core/views.js +164 -0
  110. package/dist/core/which.js +51 -0
  111. package/dist/core/workers.js +42 -0
  112. package/dist/gedcom/export.js +454 -0
  113. package/dist/gedcom/labels.js +103 -0
  114. package/dist/gedcom/lines.js +91 -0
  115. package/dist/gedcom/parse.js +53 -0
  116. package/dist/gedcom/validate.js +183 -0
  117. package/dist/image/image.js +223 -0
  118. package/dist/image/index.js +114 -0
  119. package/dist/image/jpeg-decode.js +552 -0
  120. package/dist/image/jpeg-encode.js +254 -0
  121. package/dist/image/png.js +241 -0
  122. package/dist/runners/antigravity.js +70 -0
  123. package/dist/runners/claude.js +179 -0
  124. package/dist/runners/codex.js +45 -0
  125. package/dist/runners/index.js +13 -0
  126. package/dist/runners/jsonl.js +86 -0
  127. package/dist/runners/opencode.js +50 -0
  128. package/dist/runners/runner.js +63 -0
  129. package/dist/runners/script.js +58 -0
  130. package/package.json +44 -0
@@ -0,0 +1,254 @@
1
+ // Baseline JPEG encoder (the standard tables of ITU T.81 Annex K): the views
2
+ // strom makes of scans are written with it. 4:4:4 for colour — script and
3
+ // thin strokes keep their colour edges — or one grey channel.
4
+ const ZIGZAG = [
5
+ 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22,
6
+ 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
7
+ ];
8
+ const LUMA_Q = [
9
+ 16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55, 14, 13, 16, 24, 40, 57, 69, 56, 14, 17, 22, 29, 51, 87, 80, 62, 18, 22, 37, 56, 68, 109, 103, 77, 24,
10
+ 35, 55, 64, 81, 104, 113, 92, 49, 64, 78, 87, 103, 121, 120, 101, 72, 92, 95, 98, 112, 100, 103, 99,
11
+ ];
12
+ const CHROMA_Q = [
13
+ 17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, 99, 99, 99, 99, 24, 26, 56, 99, 99, 99, 99, 99, 47, 66, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
14
+ 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
15
+ ];
16
+ // Annex K.3 Huffman tables: counts of codes per length 1..16, then the values.
17
+ const DC_LUMA = { counts: [0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], values: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] };
18
+ const DC_CHROMA = { counts: [0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], values: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] };
19
+ const AC_LUMA = {
20
+ counts: [0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d],
21
+ values: [
22
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42,
23
+ 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35,
24
+ 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67,
25
+ 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
26
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
27
+ 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4,
28
+ 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
29
+ ],
30
+ };
31
+ const AC_CHROMA = {
32
+ counts: [0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77],
33
+ values: [
34
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1,
35
+ 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a,
36
+ 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66,
37
+ 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
38
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
39
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
40
+ 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
41
+ ],
42
+ };
43
+ function codes(spec) {
44
+ const code = new Int32Array(256);
45
+ const size = new Int32Array(256);
46
+ let c = 0;
47
+ let k = 0;
48
+ for (let len = 1; len <= 16; len++) {
49
+ for (let i = 0; i < spec.counts[len - 1]; i++, k++, c++) {
50
+ code[spec.values[k]] = c;
51
+ size[spec.values[k]] = len;
52
+ }
53
+ c <<= 1;
54
+ }
55
+ return { code, size };
56
+ }
57
+ const TABLES = { dcL: codes(DC_LUMA), acL: codes(AC_LUMA), dcC: codes(DC_CHROMA), acC: codes(AC_CHROMA) };
58
+ function scaledTable(base, quality) {
59
+ const q = Math.max(1, Math.min(100, quality));
60
+ const scale = q < 50 ? 5000 / q : 200 - q * 2;
61
+ return base.map((v) => Math.max(1, Math.min(255, Math.floor((v * scale + 50) / 100))));
62
+ }
63
+ class Writer {
64
+ chunks = [];
65
+ buf = 0;
66
+ bits = 0;
67
+ byte(b) {
68
+ this.chunks.push(b & 0xff);
69
+ }
70
+ word(w) {
71
+ this.byte(w >> 8);
72
+ this.byte(w);
73
+ }
74
+ put(code, size) {
75
+ for (let i = size - 1; i >= 0; i--) {
76
+ this.buf = (this.buf << 1) | ((code >> i) & 1);
77
+ if (++this.bits === 8) {
78
+ this.byte(this.buf);
79
+ if (this.buf === 0xff)
80
+ this.byte(0); // stuffing
81
+ this.buf = 0;
82
+ this.bits = 0;
83
+ }
84
+ }
85
+ }
86
+ flush() {
87
+ if (this.bits > 0)
88
+ this.put((1 << (8 - this.bits)) - 1, 8 - this.bits); // pad with ones
89
+ }
90
+ bytes() {
91
+ return Uint8Array.from(this.chunks);
92
+ }
93
+ }
94
+ /** Forward DCT factor table: C(u) cos((2x+1)uπ/16) / 2. */
95
+ const FCOS = (() => {
96
+ const t = new Float64Array(64);
97
+ for (let u = 0; u < 8; u++)
98
+ for (let x = 0; x < 8; x++)
99
+ t[u * 8 + x] = ((u === 0 ? Math.SQRT1_2 : 1) * Math.cos(((2 * x + 1) * u * Math.PI) / 16)) / 2;
100
+ return t;
101
+ })();
102
+ function fdct(block, tmp, out) {
103
+ for (let y = 0; y < 8; y++)
104
+ for (let u = 0; u < 8; u++) {
105
+ let s = 0;
106
+ for (let x = 0; x < 8; x++)
107
+ s += FCOS[u * 8 + x] * block[y * 8 + x];
108
+ tmp[y * 8 + u] = s;
109
+ }
110
+ for (let u = 0; u < 8; u++)
111
+ for (let v = 0; v < 8; v++) {
112
+ let s = 0;
113
+ for (let y = 0; y < 8; y++)
114
+ s += FCOS[v * 8 + y] * tmp[y * 8 + u];
115
+ out[v * 8 + u] = s;
116
+ }
117
+ }
118
+ function magnitude(v) {
119
+ const a = Math.abs(v);
120
+ let size = 0;
121
+ while (a >> size)
122
+ size++;
123
+ return { size, bits: v < 0 ? v + (1 << size) - 1 : v };
124
+ }
125
+ export function encodeJpeg(img, quality = 90) {
126
+ const { width, height, channels } = img;
127
+ const w = new Writer();
128
+ const qL = scaledTable(LUMA_Q, quality);
129
+ const qC = scaledTable(CHROMA_Q, quality);
130
+ // SOI + JFIF
131
+ w.word(0xffd8);
132
+ w.word(0xffe0);
133
+ w.word(16);
134
+ for (const c of [0x4a, 0x46, 0x49, 0x46, 0])
135
+ w.byte(c);
136
+ w.word(0x0101);
137
+ w.byte(0);
138
+ w.word(1);
139
+ w.word(1);
140
+ w.byte(0);
141
+ w.byte(0);
142
+ // DQT
143
+ const tables = channels === 3 ? [qL, qC] : [qL];
144
+ tables.forEach((t, i) => {
145
+ w.word(0xffdb);
146
+ w.word(67);
147
+ w.byte(i);
148
+ for (let k = 0; k < 64; k++)
149
+ w.byte(t[ZIGZAG[k]]);
150
+ });
151
+ // SOF0
152
+ w.word(0xffc0);
153
+ w.word(8 + 3 * channels);
154
+ w.byte(8);
155
+ w.word(height);
156
+ w.word(width);
157
+ w.byte(channels);
158
+ for (let c = 0; c < channels; c++) {
159
+ w.byte(c + 1);
160
+ w.byte(0x11);
161
+ w.byte(c === 0 ? 0 : 1);
162
+ }
163
+ // DHT
164
+ const dht = (cls, id, spec) => {
165
+ w.word(0xffc4);
166
+ w.word(3 + 16 + spec.values.length);
167
+ w.byte((cls << 4) | id);
168
+ for (const n of spec.counts)
169
+ w.byte(n);
170
+ for (const v of spec.values)
171
+ w.byte(v);
172
+ };
173
+ dht(0, 0, DC_LUMA);
174
+ dht(1, 0, AC_LUMA);
175
+ if (channels === 3) {
176
+ dht(0, 1, DC_CHROMA);
177
+ dht(1, 1, AC_CHROMA);
178
+ }
179
+ // SOS
180
+ w.word(0xffda);
181
+ w.word(6 + 2 * channels);
182
+ w.byte(channels);
183
+ for (let c = 0; c < channels; c++) {
184
+ w.byte(c + 1);
185
+ w.byte(c === 0 ? 0x00 : 0x11);
186
+ }
187
+ w.byte(0);
188
+ w.byte(63);
189
+ w.byte(0);
190
+ const block = new Float64Array(64);
191
+ const tmp = new Float64Array(64);
192
+ const coef = new Float64Array(64);
193
+ const pred = [0, 0, 0];
194
+ const encodeBlock = (comp) => {
195
+ fdct(block, tmp, coef);
196
+ const q = comp === 0 ? qL : qC;
197
+ const dc = comp === 0 ? TABLES.dcL : TABLES.dcC;
198
+ const ac = comp === 0 ? TABLES.acL : TABLES.acC;
199
+ const zz = new Int32Array(64);
200
+ for (let k = 0; k < 64; k++)
201
+ zz[k] = Math.round(coef[ZIGZAG[k]] / q[ZIGZAG[k]]);
202
+ const diff = zz[0] - pred[comp];
203
+ pred[comp] = zz[0];
204
+ const m = magnitude(diff);
205
+ w.put(dc.code[m.size], dc.size[m.size]);
206
+ if (m.size)
207
+ w.put(m.bits, m.size);
208
+ let run = 0;
209
+ for (let k = 1; k < 64; k++) {
210
+ const v = zz[k];
211
+ if (v === 0) {
212
+ run++;
213
+ continue;
214
+ }
215
+ while (run > 15) {
216
+ w.put(ac.code[0xf0], ac.size[0xf0]);
217
+ run -= 16;
218
+ }
219
+ const mm = magnitude(v);
220
+ const sym = (run << 4) | mm.size;
221
+ w.put(ac.code[sym], ac.size[sym]);
222
+ w.put(mm.bits, mm.size);
223
+ run = 0;
224
+ }
225
+ if (run > 0)
226
+ w.put(ac.code[0], ac.size[0]); // EOB
227
+ };
228
+ const data = img.data;
229
+ for (let by = 0; by < height; by += 8)
230
+ for (let bx = 0; bx < width; bx += 8)
231
+ for (let comp = 0; comp < channels; comp++) {
232
+ for (let y = 0; y < 8; y++)
233
+ for (let x = 0; x < 8; x++) {
234
+ // edge blocks repeat the last row/column
235
+ const sx = Math.min(width - 1, bx + x);
236
+ const sy = Math.min(height - 1, by + y);
237
+ const p = (sy * width + sx) * channels;
238
+ let v;
239
+ if (channels === 1)
240
+ v = data[p];
241
+ else {
242
+ const r = data[p];
243
+ const g = data[p + 1];
244
+ const b = data[p + 2];
245
+ v = comp === 0 ? 0.299 * r + 0.587 * g + 0.114 * b : comp === 1 ? -0.168736 * r - 0.331264 * g + 0.5 * b + 128 : 0.5 * r - 0.418688 * g - 0.081312 * b + 128;
246
+ }
247
+ block[y * 8 + x] = v - 128;
248
+ }
249
+ encodeBlock(comp);
250
+ }
251
+ w.flush();
252
+ w.word(0xffd9);
253
+ return w.bytes();
254
+ }
@@ -0,0 +1,241 @@
1
+ // PNG decoder and encoder over node:zlib: every colour type and bit depth,
2
+ // interlaced or not, transparency flattened onto white (a document on paper).
3
+ import zlib from "node:zlib";
4
+ export class PngError extends Error {
5
+ }
6
+ const SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
7
+ const CRC_TABLE = (() => {
8
+ const t = new Uint32Array(256);
9
+ for (let n = 0; n < 256; n++) {
10
+ let c = n;
11
+ for (let k = 0; k < 8; k++)
12
+ c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
13
+ t[n] = c >>> 0;
14
+ }
15
+ return t;
16
+ })();
17
+ function crc32(bytes) {
18
+ let c = 0xffffffff;
19
+ for (let i = 0; i < bytes.length; i++)
20
+ c = CRC_TABLE[(c ^ bytes[i]) & 0xff] ^ (c >>> 8);
21
+ return (c ^ 0xffffffff) >>> 0;
22
+ }
23
+ function paeth(a, b, c) {
24
+ const p = a + b - c;
25
+ const pa = Math.abs(p - a);
26
+ const pb = Math.abs(p - b);
27
+ const pc = Math.abs(p - c);
28
+ return pa <= pb && pa <= pc ? a : pb <= pc ? b : c;
29
+ }
30
+ /** Undo the per-row filters of one (sub)image in place; returns the raw rows. */
31
+ function unfilter(data, start, width, height, bpp, bitsPerPixel) {
32
+ const stride = Math.ceil((width * bitsPerPixel) / 8);
33
+ const rows = new Uint8Array(stride * height);
34
+ let p = start;
35
+ for (let y = 0; y < height; y++) {
36
+ const type = data[p++];
37
+ const row = y * stride;
38
+ const prev = row - stride;
39
+ for (let x = 0; x < stride; x++) {
40
+ const raw = data[p++];
41
+ const a = x >= bpp ? rows[row + x - bpp] : 0;
42
+ const b = y > 0 ? rows[prev + x] : 0;
43
+ const c = y > 0 && x >= bpp ? rows[prev + x - bpp] : 0;
44
+ let v;
45
+ switch (type) {
46
+ case 0:
47
+ v = raw;
48
+ break;
49
+ case 1:
50
+ v = raw + a;
51
+ break;
52
+ case 2:
53
+ v = raw + b;
54
+ break;
55
+ case 3:
56
+ v = raw + ((a + b) >> 1);
57
+ break;
58
+ case 4:
59
+ v = raw + paeth(a, b, c);
60
+ break;
61
+ default:
62
+ throw new PngError(`unknown PNG filter ${type}`);
63
+ }
64
+ rows[row + x] = v & 0xff;
65
+ }
66
+ }
67
+ return { rows, used: p - start };
68
+ }
69
+ export function decodePng(bytes) {
70
+ for (let i = 0; i < 8; i++)
71
+ if (bytes[i] !== SIGNATURE[i])
72
+ throw new PngError("not a PNG file");
73
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
74
+ let pos = 8;
75
+ let width = 0;
76
+ let height = 0;
77
+ let depth = 8;
78
+ let colour = 0;
79
+ let interlace = 0;
80
+ let palette;
81
+ let trns;
82
+ const idat = [];
83
+ while (pos + 8 <= bytes.length) {
84
+ const len = view.getUint32(pos);
85
+ const type = String.fromCharCode(...bytes.subarray(pos + 4, pos + 8));
86
+ const body = bytes.subarray(pos + 8, pos + 8 + len);
87
+ if (type === "IHDR") {
88
+ width = view.getUint32(pos + 8);
89
+ height = view.getUint32(pos + 12);
90
+ depth = body[8];
91
+ colour = body[9];
92
+ interlace = body[12];
93
+ }
94
+ else if (type === "PLTE")
95
+ palette = body;
96
+ else if (type === "tRNS")
97
+ trns = body;
98
+ else if (type === "IDAT")
99
+ idat.push(body);
100
+ else if (type === "IEND")
101
+ break;
102
+ pos += 12 + len;
103
+ }
104
+ if (!width || !height)
105
+ throw new PngError("PNG without IHDR");
106
+ const samples = colour === 0 ? 1 : colour === 2 ? 3 : colour === 3 ? 1 : colour === 4 ? 2 : colour === 6 ? 4 : 0;
107
+ if (!samples)
108
+ throw new PngError(`unknown PNG colour type ${colour}`);
109
+ const bitsPerPixel = samples * depth;
110
+ const bpp = Math.max(1, bitsPerPixel >> 3);
111
+ const inflated = new Uint8Array(zlib.inflateSync(Buffer.concat(idat)));
112
+ const grey = colour === 0 || colour === 4;
113
+ const out = { width, height, channels: grey ? 1 : 3, data: new Uint8Array(width * height * (grey ? 1 : 3)) };
114
+ const maxv = (1 << depth) - 1;
115
+ const read = (rows, stride, x, y, s) => {
116
+ if (depth === 8)
117
+ return rows[y * stride + x * samples + s];
118
+ if (depth === 16) {
119
+ const p = y * stride + (x * samples + s) * 2;
120
+ return rows[p]; // high byte
121
+ }
122
+ const bit = (x * samples + s) * depth;
123
+ const byte = rows[y * stride + (bit >> 3)];
124
+ return (byte >> (8 - depth - (bit & 7))) & maxv;
125
+ };
126
+ const scale = (v) => (depth === 8 || depth === 16 ? v : Math.round((v * 255) / maxv));
127
+ const place = (rows, w, h, x0, y0, dx, dy) => {
128
+ const stride = Math.ceil((w * bitsPerPixel) / 8);
129
+ for (let y = 0; y < h; y++)
130
+ for (let x = 0; x < w; x++) {
131
+ const tx = x0 + x * dx;
132
+ const ty = y0 + y * dy;
133
+ const o = (ty * width + tx) * out.channels;
134
+ let r;
135
+ let g;
136
+ let b;
137
+ let alpha = 255;
138
+ if (colour === 3) {
139
+ const idx = read(rows, stride, x, y, 0);
140
+ r = palette?.[idx * 3] ?? 0;
141
+ g = palette?.[idx * 3 + 1] ?? 0;
142
+ b = palette?.[idx * 3 + 2] ?? 0;
143
+ if (trns && idx < trns.length)
144
+ alpha = trns[idx];
145
+ }
146
+ else if (grey) {
147
+ r = g = b = scale(read(rows, stride, x, y, 0));
148
+ if (colour === 4)
149
+ alpha = scale(read(rows, stride, x, y, 1));
150
+ }
151
+ else {
152
+ r = scale(read(rows, stride, x, y, 0));
153
+ g = scale(read(rows, stride, x, y, 1));
154
+ b = scale(read(rows, stride, x, y, 2));
155
+ if (colour === 6)
156
+ alpha = scale(read(rows, stride, x, y, 3));
157
+ }
158
+ // flatten transparency onto white paper
159
+ const f = (v) => Math.round((v * alpha + 255 * (255 - alpha)) / 255);
160
+ if (out.channels === 1)
161
+ out.data[o] = f(r);
162
+ else {
163
+ out.data[o] = f(r);
164
+ out.data[o + 1] = f(g);
165
+ out.data[o + 2] = f(b);
166
+ }
167
+ }
168
+ };
169
+ if (interlace === 0) {
170
+ place(unfilter(inflated, 0, width, height, bpp, bitsPerPixel).rows, width, height, 0, 0, 1, 1);
171
+ }
172
+ else {
173
+ // Adam7: seven passes, each a small filtered image
174
+ const passes = [
175
+ [0, 0, 8, 8],
176
+ [4, 0, 8, 8],
177
+ [0, 4, 4, 8],
178
+ [2, 0, 4, 4],
179
+ [0, 2, 2, 4],
180
+ [1, 0, 2, 2],
181
+ [0, 1, 1, 2],
182
+ ];
183
+ let p = 0;
184
+ for (const [x0, y0, dx, dy] of passes) {
185
+ const w = Math.ceil((width - x0) / dx);
186
+ const h = Math.ceil((height - y0) / dy);
187
+ if (w <= 0 || h <= 0)
188
+ continue;
189
+ const { rows, used } = unfilter(inflated, p, w, h, bpp, bitsPerPixel);
190
+ place(rows, w, h, x0, y0, dx, dy);
191
+ p += used;
192
+ }
193
+ }
194
+ return out;
195
+ }
196
+ function chunk(type, body) {
197
+ const head = Buffer.alloc(8);
198
+ head.writeUInt32BE(body.length, 0);
199
+ head.write(type, 4, "latin1");
200
+ const crc = Buffer.alloc(4);
201
+ crc.writeUInt32BE(crc32(Buffer.concat([head.subarray(4), body])), 0);
202
+ return Buffer.concat([head, body, crc]);
203
+ }
204
+ /** Encode 8-bit grey or RGB; each row gets the filter that compresses it best (minimum sum). */
205
+ export function encodePng(img) {
206
+ const { width, height, channels } = img;
207
+ const stride = width * channels;
208
+ const raw = new Uint8Array((stride + 1) * height);
209
+ const candidate = new Uint8Array(stride);
210
+ for (let y = 0; y < height; y++) {
211
+ const row = y * stride;
212
+ let best = 0;
213
+ let bestSum = Infinity;
214
+ let bestRow = new Uint8Array(stride);
215
+ for (let type = 0; type <= 4; type++) {
216
+ let sum = 0;
217
+ for (let x = 0; x < stride; x++) {
218
+ const v = img.data[row + x];
219
+ const a = x >= channels ? img.data[row + x - channels] : 0;
220
+ const b = y > 0 ? img.data[row - stride + x] : 0;
221
+ const c = y > 0 && x >= channels ? img.data[row - stride + x - channels] : 0;
222
+ const f = type === 0 ? v : type === 1 ? v - a : type === 2 ? v - b : type === 3 ? v - ((a + b) >> 1) : v - paeth(a, b, c);
223
+ candidate[x] = f & 0xff;
224
+ sum += Math.abs((f << 24) >> 24);
225
+ }
226
+ if (sum < bestSum) {
227
+ bestSum = sum;
228
+ best = type;
229
+ bestRow = candidate.slice();
230
+ }
231
+ }
232
+ raw[y * (stride + 1)] = best;
233
+ raw.set(bestRow, y * (stride + 1) + 1);
234
+ }
235
+ const ihdr = Buffer.alloc(13);
236
+ ihdr.writeUInt32BE(width, 0);
237
+ ihdr.writeUInt32BE(height, 4);
238
+ ihdr[8] = 8;
239
+ ihdr[9] = channels === 1 ? 0 : 2;
240
+ return new Uint8Array(Buffer.concat([Buffer.from(SIGNATURE), chunk("IHDR", ihdr), chunk("IDAT", zlib.deflateSync(raw, { level: 6 })), chunk("IEND", new Uint8Array(0))]));
241
+ }
@@ -0,0 +1,70 @@
1
+ // Antigravity CLI runner (`agy`, Google's agent CLI after Gemini CLI).
2
+ // Headless: `agy -p "<run strom brief …>" --output-format stream-json` in the
3
+ // tree folder — the agent reads its brief with `strom brief` (how agy takes
4
+ // stdin in print mode is not settled); events are {"event": …} lines, the last one the result
5
+ // with status, response, turns and usage. Its permissions are rules in the
6
+ // user's settings (strom agents install adds `command(strom)` there); under
7
+ // ask and auto a headless run gets nothing else (what would ask is refused, or
8
+ // stalls — strom's time limit ends it); full skips the permissions.
9
+ // Interactive conversations are started by strom chat (agents/launch.ts).
10
+ import { runJsonLines } from "./jsonl.js";
11
+ /** Command-line arguments of a headless run (exported for tests). */
12
+ export function antigravityArgs(opts) {
13
+ return [
14
+ "--print",
15
+ opts.kickoff,
16
+ "--output-format",
17
+ "stream-json",
18
+ ...(opts.permissions === "full" ? ["--dangerously-skip-permissions"] : []),
19
+ ...(opts.shared ? ["--add-dir", opts.shared] : []),
20
+ ...(opts.model ? ["--model", opts.model] : []),
21
+ ...(opts.timeoutMs ? ["--print-timeout", `${Math.round(opts.timeoutMs / 1000)}s`] : []),
22
+ ...(opts.extraArgs ?? []),
23
+ ];
24
+ }
25
+ export const antigravityRunner = {
26
+ id: "antigravity",
27
+ command: "agy",
28
+ run(opts) {
29
+ return runJsonLines("agy", antigravityArgs(opts), opts.env, opts, (msg, heard) => {
30
+ const kind = String(msg.event ?? msg.type ?? "");
31
+ if (kind === "result") {
32
+ const r = (msg.result ?? {});
33
+ if (r.response)
34
+ heard.text = r.response;
35
+ if (r.status && r.status !== "SUCCESS" && r.status !== "OK") {
36
+ heard.isError = true;
37
+ if (r.error)
38
+ heard.text = r.error;
39
+ }
40
+ const u = r.usage ?? {};
41
+ const m = heard.metrics;
42
+ if (typeof u.input_tokens === "number")
43
+ m.inputTokens = u.input_tokens;
44
+ if (typeof u.output_tokens === "number")
45
+ m.outputTokens = u.output_tokens + (u.thinking_tokens ?? 0);
46
+ if (typeof u.cache_read_tokens === "number")
47
+ m.cacheReadTokens = u.cache_read_tokens;
48
+ if (typeof r.num_turns === "number")
49
+ m.turns = r.num_turns;
50
+ if (typeof r.duration_seconds === "number")
51
+ m.durationMs = r.duration_seconds * 1000;
52
+ return;
53
+ }
54
+ // Other events: a line of progress from whatever names a tool, a command or a text.
55
+ const body = (msg[kind] ?? msg);
56
+ const command = body.command ?? body.input?.command ?? body.args?.command;
57
+ if (typeof command === "string")
58
+ opts.onProgress?.(`$ ${command.split("\n")[0].slice(0, 140)}`);
59
+ else if (/tool/i.test(kind) && typeof (body.name ?? body.tool) === "string")
60
+ opts.onProgress?.(String(body.name ?? body.tool));
61
+ else if (/message|text|response/i.test(kind) && typeof (body.text ?? body.content) === "string") {
62
+ const text = String(body.text ?? body.content).trim();
63
+ if (text)
64
+ opts.onProgress?.(text.split("\n")[0].slice(0, 160));
65
+ }
66
+ if (/denied|permission/i.test(kind))
67
+ heard.denied.push(`tool: ${JSON.stringify(body).slice(0, 120)}`);
68
+ });
69
+ },
70
+ };