@floomhq/skills 0.2.0 → 0.2.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 (82) hide show
  1. package/dist/index.d.ts +0 -1
  2. package/dist/index.js +3638 -87
  3. package/dist/index.js.map +7 -1
  4. package/dist/version.d.ts +1 -1
  5. package/dist/version.js +1 -2
  6. package/package.json +17 -6
  7. package/dist/api-client.d.ts +0 -9
  8. package/dist/api-client.js +0 -61
  9. package/dist/api-client.js.map +0 -1
  10. package/dist/commands/info.d.ts +0 -1
  11. package/dist/commands/info.js +0 -24
  12. package/dist/commands/info.js.map +0 -1
  13. package/dist/commands/init.d.ts +0 -1
  14. package/dist/commands/init.js +0 -108
  15. package/dist/commands/init.js.map +0 -1
  16. package/dist/commands/install.d.ts +0 -8
  17. package/dist/commands/install.js +0 -136
  18. package/dist/commands/install.js.map +0 -1
  19. package/dist/commands/installed.d.ts +0 -4
  20. package/dist/commands/installed.js +0 -22
  21. package/dist/commands/installed.js.map +0 -1
  22. package/dist/commands/library.d.ts +0 -4
  23. package/dist/commands/library.js +0 -29
  24. package/dist/commands/library.js.map +0 -1
  25. package/dist/commands/list.d.ts +0 -7
  26. package/dist/commands/list.js +0 -32
  27. package/dist/commands/list.js.map +0 -1
  28. package/dist/commands/login.d.ts +0 -1
  29. package/dist/commands/login.js +0 -57
  30. package/dist/commands/login.js.map +0 -1
  31. package/dist/commands/logout.d.ts +0 -1
  32. package/dist/commands/logout.js +0 -19
  33. package/dist/commands/logout.js.map +0 -1
  34. package/dist/commands/outdated.d.ts +0 -1
  35. package/dist/commands/outdated.js +0 -50
  36. package/dist/commands/outdated.js.map +0 -1
  37. package/dist/commands/publish.d.ts +0 -4
  38. package/dist/commands/publish.js +0 -84
  39. package/dist/commands/publish.js.map +0 -1
  40. package/dist/commands/share.d.ts +0 -5
  41. package/dist/commands/share.js +0 -34
  42. package/dist/commands/share.js.map +0 -1
  43. package/dist/commands/update.d.ts +0 -4
  44. package/dist/commands/update.js +0 -92
  45. package/dist/commands/update.js.map +0 -1
  46. package/dist/commands/validate.d.ts +0 -32
  47. package/dist/commands/validate.js +0 -108
  48. package/dist/commands/validate.js.map +0 -1
  49. package/dist/commands/whoami.d.ts +0 -1
  50. package/dist/commands/whoami.js +0 -14
  51. package/dist/commands/whoami.js.map +0 -1
  52. package/dist/config.d.ts +0 -11
  53. package/dist/config.js +0 -39
  54. package/dist/config.js.map +0 -1
  55. package/dist/lib/floom-lock.d.ts +0 -22
  56. package/dist/lib/floom-lock.js +0 -66
  57. package/dist/lib/floom-lock.js.map +0 -1
  58. package/dist/lib/output.d.ts +0 -11
  59. package/dist/lib/output.js +0 -17
  60. package/dist/lib/output.js.map +0 -1
  61. package/dist/version.js.map +0 -1
  62. package/src/api-client.ts +0 -80
  63. package/src/commands/info.ts +0 -36
  64. package/src/commands/init.ts +0 -109
  65. package/src/commands/install.ts +0 -176
  66. package/src/commands/installed.ts +0 -29
  67. package/src/commands/library.ts +0 -41
  68. package/src/commands/list.ts +0 -59
  69. package/src/commands/login.ts +0 -77
  70. package/src/commands/logout.ts +0 -18
  71. package/src/commands/outdated.ts +0 -57
  72. package/src/commands/publish.ts +0 -111
  73. package/src/commands/share.ts +0 -41
  74. package/src/commands/update.ts +0 -116
  75. package/src/commands/validate.ts +0 -132
  76. package/src/commands/whoami.ts +0 -14
  77. package/src/config.ts +0 -44
  78. package/src/index.ts +0 -109
  79. package/src/lib/floom-lock.ts +0 -81
  80. package/src/lib/output.ts +0 -17
  81. package/src/version.ts +0 -1
  82. package/tsconfig.json +0 -9
package/dist/index.js CHANGED
@@ -1,99 +1,3650 @@
1
1
  #!/usr/bin/env node
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
9
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
10
+ }) : x)(function(x) {
11
+ if (typeof require !== "undefined") return require.apply(this, arguments);
12
+ throw Error('Dynamic require of "' + x + '" is not supported');
13
+ });
14
+ var __commonJS = (cb, mod) => function __require2() {
15
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
16
+ };
17
+ var __copyProps = (to, from, except, desc) => {
18
+ if (from && typeof from === "object" || typeof from === "function") {
19
+ for (let key of __getOwnPropNames(from))
20
+ if (!__hasOwnProp.call(to, key) && key !== except)
21
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
22
+ }
23
+ return to;
24
+ };
25
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
26
+ // If the importer is in node compatibility mode or this is not an ESM
27
+ // file that has been converted to a CommonJS file using a Babel-
28
+ // compatible transform (i.e. "__esModule" has not been set), then set
29
+ // "default" to the CommonJS "module.exports" for node compatibility.
30
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
31
+ mod
32
+ ));
33
+
34
+ // ../../node_modules/.pnpm/bcryptjs@2.4.3/node_modules/bcryptjs/dist/bcrypt.js
35
+ var require_bcrypt = __commonJS({
36
+ "../../node_modules/.pnpm/bcryptjs@2.4.3/node_modules/bcryptjs/dist/bcrypt.js"(exports, module) {
37
+ (function(global, factory) {
38
+ if (typeof define === "function" && define["amd"])
39
+ define([], factory);
40
+ else if (typeof __require === "function" && typeof module === "object" && module && module["exports"])
41
+ module["exports"] = factory();
42
+ else
43
+ (global["dcodeIO"] = global["dcodeIO"] || {})["bcrypt"] = factory();
44
+ })(exports, function() {
45
+ "use strict";
46
+ var bcrypt2 = {};
47
+ var randomFallback = null;
48
+ function random(len) {
49
+ if (typeof module !== "undefined" && module && module["exports"])
50
+ try {
51
+ return __require("crypto")["randomBytes"](len);
52
+ } catch (e) {
53
+ }
54
+ try {
55
+ var a;
56
+ (self["crypto"] || self["msCrypto"])["getRandomValues"](a = new Uint32Array(len));
57
+ return Array.prototype.slice.call(a);
58
+ } catch (e) {
59
+ }
60
+ if (!randomFallback)
61
+ throw Error("Neither WebCryptoAPI nor a crypto module is available. Use bcrypt.setRandomFallback to set an alternative");
62
+ return randomFallback(len);
63
+ }
64
+ var randomAvailable = false;
65
+ try {
66
+ random(1);
67
+ randomAvailable = true;
68
+ } catch (e) {
69
+ }
70
+ randomFallback = null;
71
+ bcrypt2.setRandomFallback = function(random2) {
72
+ randomFallback = random2;
73
+ };
74
+ bcrypt2.genSaltSync = function(rounds, seed_length) {
75
+ rounds = rounds || GENSALT_DEFAULT_LOG2_ROUNDS;
76
+ if (typeof rounds !== "number")
77
+ throw Error("Illegal arguments: " + typeof rounds + ", " + typeof seed_length);
78
+ if (rounds < 4)
79
+ rounds = 4;
80
+ else if (rounds > 31)
81
+ rounds = 31;
82
+ var salt = [];
83
+ salt.push("$2a$");
84
+ if (rounds < 10)
85
+ salt.push("0");
86
+ salt.push(rounds.toString());
87
+ salt.push("$");
88
+ salt.push(base64_encode(random(BCRYPT_SALT_LEN), BCRYPT_SALT_LEN));
89
+ return salt.join("");
90
+ };
91
+ bcrypt2.genSalt = function(rounds, seed_length, callback) {
92
+ if (typeof seed_length === "function")
93
+ callback = seed_length, seed_length = void 0;
94
+ if (typeof rounds === "function")
95
+ callback = rounds, rounds = void 0;
96
+ if (typeof rounds === "undefined")
97
+ rounds = GENSALT_DEFAULT_LOG2_ROUNDS;
98
+ else if (typeof rounds !== "number")
99
+ throw Error("illegal arguments: " + typeof rounds);
100
+ function _async(callback2) {
101
+ nextTick(function() {
102
+ try {
103
+ callback2(null, bcrypt2.genSaltSync(rounds));
104
+ } catch (err) {
105
+ callback2(err);
106
+ }
107
+ });
108
+ }
109
+ if (callback) {
110
+ if (typeof callback !== "function")
111
+ throw Error("Illegal callback: " + typeof callback);
112
+ _async(callback);
113
+ } else
114
+ return new Promise(function(resolve3, reject) {
115
+ _async(function(err, res) {
116
+ if (err) {
117
+ reject(err);
118
+ return;
119
+ }
120
+ resolve3(res);
121
+ });
122
+ });
123
+ };
124
+ bcrypt2.hashSync = function(s, salt) {
125
+ if (typeof salt === "undefined")
126
+ salt = GENSALT_DEFAULT_LOG2_ROUNDS;
127
+ if (typeof salt === "number")
128
+ salt = bcrypt2.genSaltSync(salt);
129
+ if (typeof s !== "string" || typeof salt !== "string")
130
+ throw Error("Illegal arguments: " + typeof s + ", " + typeof salt);
131
+ return _hash(s, salt);
132
+ };
133
+ bcrypt2.hash = function(s, salt, callback, progressCallback) {
134
+ function _async(callback2) {
135
+ if (typeof s === "string" && typeof salt === "number")
136
+ bcrypt2.genSalt(salt, function(err, salt2) {
137
+ _hash(s, salt2, callback2, progressCallback);
138
+ });
139
+ else if (typeof s === "string" && typeof salt === "string")
140
+ _hash(s, salt, callback2, progressCallback);
141
+ else
142
+ nextTick(callback2.bind(this, Error("Illegal arguments: " + typeof s + ", " + typeof salt)));
143
+ }
144
+ if (callback) {
145
+ if (typeof callback !== "function")
146
+ throw Error("Illegal callback: " + typeof callback);
147
+ _async(callback);
148
+ } else
149
+ return new Promise(function(resolve3, reject) {
150
+ _async(function(err, res) {
151
+ if (err) {
152
+ reject(err);
153
+ return;
154
+ }
155
+ resolve3(res);
156
+ });
157
+ });
158
+ };
159
+ function safeStringCompare(known, unknown) {
160
+ var right = 0, wrong = 0;
161
+ for (var i = 0, k = known.length; i < k; ++i) {
162
+ if (known.charCodeAt(i) === unknown.charCodeAt(i))
163
+ ++right;
164
+ else
165
+ ++wrong;
166
+ }
167
+ if (right < 0)
168
+ return false;
169
+ return wrong === 0;
170
+ }
171
+ bcrypt2.compareSync = function(s, hash) {
172
+ if (typeof s !== "string" || typeof hash !== "string")
173
+ throw Error("Illegal arguments: " + typeof s + ", " + typeof hash);
174
+ if (hash.length !== 60)
175
+ return false;
176
+ return safeStringCompare(bcrypt2.hashSync(s, hash.substr(0, hash.length - 31)), hash);
177
+ };
178
+ bcrypt2.compare = function(s, hash, callback, progressCallback) {
179
+ function _async(callback2) {
180
+ if (typeof s !== "string" || typeof hash !== "string") {
181
+ nextTick(callback2.bind(this, Error("Illegal arguments: " + typeof s + ", " + typeof hash)));
182
+ return;
183
+ }
184
+ if (hash.length !== 60) {
185
+ nextTick(callback2.bind(this, null, false));
186
+ return;
187
+ }
188
+ bcrypt2.hash(s, hash.substr(0, 29), function(err, comp) {
189
+ if (err)
190
+ callback2(err);
191
+ else
192
+ callback2(null, safeStringCompare(comp, hash));
193
+ }, progressCallback);
194
+ }
195
+ if (callback) {
196
+ if (typeof callback !== "function")
197
+ throw Error("Illegal callback: " + typeof callback);
198
+ _async(callback);
199
+ } else
200
+ return new Promise(function(resolve3, reject) {
201
+ _async(function(err, res) {
202
+ if (err) {
203
+ reject(err);
204
+ return;
205
+ }
206
+ resolve3(res);
207
+ });
208
+ });
209
+ };
210
+ bcrypt2.getRounds = function(hash) {
211
+ if (typeof hash !== "string")
212
+ throw Error("Illegal arguments: " + typeof hash);
213
+ return parseInt(hash.split("$")[2], 10);
214
+ };
215
+ bcrypt2.getSalt = function(hash) {
216
+ if (typeof hash !== "string")
217
+ throw Error("Illegal arguments: " + typeof hash);
218
+ if (hash.length !== 60)
219
+ throw Error("Illegal hash length: " + hash.length + " != 60");
220
+ return hash.substring(0, 29);
221
+ };
222
+ var nextTick = typeof process !== "undefined" && process && typeof process.nextTick === "function" ? typeof setImmediate === "function" ? setImmediate : process.nextTick : setTimeout;
223
+ function stringToBytes(str) {
224
+ var out = [], i = 0;
225
+ utfx.encodeUTF16toUTF8(function() {
226
+ if (i >= str.length) return null;
227
+ return str.charCodeAt(i++);
228
+ }, function(b) {
229
+ out.push(b);
230
+ });
231
+ return out;
232
+ }
233
+ var BASE64_CODE = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".split("");
234
+ var BASE64_INDEX = [
235
+ -1,
236
+ -1,
237
+ -1,
238
+ -1,
239
+ -1,
240
+ -1,
241
+ -1,
242
+ -1,
243
+ -1,
244
+ -1,
245
+ -1,
246
+ -1,
247
+ -1,
248
+ -1,
249
+ -1,
250
+ -1,
251
+ -1,
252
+ -1,
253
+ -1,
254
+ -1,
255
+ -1,
256
+ -1,
257
+ -1,
258
+ -1,
259
+ -1,
260
+ -1,
261
+ -1,
262
+ -1,
263
+ -1,
264
+ -1,
265
+ -1,
266
+ -1,
267
+ -1,
268
+ -1,
269
+ -1,
270
+ -1,
271
+ -1,
272
+ -1,
273
+ -1,
274
+ -1,
275
+ -1,
276
+ -1,
277
+ -1,
278
+ -1,
279
+ -1,
280
+ -1,
281
+ 0,
282
+ 1,
283
+ 54,
284
+ 55,
285
+ 56,
286
+ 57,
287
+ 58,
288
+ 59,
289
+ 60,
290
+ 61,
291
+ 62,
292
+ 63,
293
+ -1,
294
+ -1,
295
+ -1,
296
+ -1,
297
+ -1,
298
+ -1,
299
+ -1,
300
+ 2,
301
+ 3,
302
+ 4,
303
+ 5,
304
+ 6,
305
+ 7,
306
+ 8,
307
+ 9,
308
+ 10,
309
+ 11,
310
+ 12,
311
+ 13,
312
+ 14,
313
+ 15,
314
+ 16,
315
+ 17,
316
+ 18,
317
+ 19,
318
+ 20,
319
+ 21,
320
+ 22,
321
+ 23,
322
+ 24,
323
+ 25,
324
+ 26,
325
+ 27,
326
+ -1,
327
+ -1,
328
+ -1,
329
+ -1,
330
+ -1,
331
+ -1,
332
+ 28,
333
+ 29,
334
+ 30,
335
+ 31,
336
+ 32,
337
+ 33,
338
+ 34,
339
+ 35,
340
+ 36,
341
+ 37,
342
+ 38,
343
+ 39,
344
+ 40,
345
+ 41,
346
+ 42,
347
+ 43,
348
+ 44,
349
+ 45,
350
+ 46,
351
+ 47,
352
+ 48,
353
+ 49,
354
+ 50,
355
+ 51,
356
+ 52,
357
+ 53,
358
+ -1,
359
+ -1,
360
+ -1,
361
+ -1,
362
+ -1
363
+ ];
364
+ var stringFromCharCode = String.fromCharCode;
365
+ function base64_encode(b, len) {
366
+ var off = 0, rs = [], c1, c2;
367
+ if (len <= 0 || len > b.length)
368
+ throw Error("Illegal len: " + len);
369
+ while (off < len) {
370
+ c1 = b[off++] & 255;
371
+ rs.push(BASE64_CODE[c1 >> 2 & 63]);
372
+ c1 = (c1 & 3) << 4;
373
+ if (off >= len) {
374
+ rs.push(BASE64_CODE[c1 & 63]);
375
+ break;
376
+ }
377
+ c2 = b[off++] & 255;
378
+ c1 |= c2 >> 4 & 15;
379
+ rs.push(BASE64_CODE[c1 & 63]);
380
+ c1 = (c2 & 15) << 2;
381
+ if (off >= len) {
382
+ rs.push(BASE64_CODE[c1 & 63]);
383
+ break;
384
+ }
385
+ c2 = b[off++] & 255;
386
+ c1 |= c2 >> 6 & 3;
387
+ rs.push(BASE64_CODE[c1 & 63]);
388
+ rs.push(BASE64_CODE[c2 & 63]);
389
+ }
390
+ return rs.join("");
391
+ }
392
+ function base64_decode(s, len) {
393
+ var off = 0, slen = s.length, olen = 0, rs = [], c1, c2, c3, c4, o, code;
394
+ if (len <= 0)
395
+ throw Error("Illegal len: " + len);
396
+ while (off < slen - 1 && olen < len) {
397
+ code = s.charCodeAt(off++);
398
+ c1 = code < BASE64_INDEX.length ? BASE64_INDEX[code] : -1;
399
+ code = s.charCodeAt(off++);
400
+ c2 = code < BASE64_INDEX.length ? BASE64_INDEX[code] : -1;
401
+ if (c1 == -1 || c2 == -1)
402
+ break;
403
+ o = c1 << 2 >>> 0;
404
+ o |= (c2 & 48) >> 4;
405
+ rs.push(stringFromCharCode(o));
406
+ if (++olen >= len || off >= slen)
407
+ break;
408
+ code = s.charCodeAt(off++);
409
+ c3 = code < BASE64_INDEX.length ? BASE64_INDEX[code] : -1;
410
+ if (c3 == -1)
411
+ break;
412
+ o = (c2 & 15) << 4 >>> 0;
413
+ o |= (c3 & 60) >> 2;
414
+ rs.push(stringFromCharCode(o));
415
+ if (++olen >= len || off >= slen)
416
+ break;
417
+ code = s.charCodeAt(off++);
418
+ c4 = code < BASE64_INDEX.length ? BASE64_INDEX[code] : -1;
419
+ o = (c3 & 3) << 6 >>> 0;
420
+ o |= c4;
421
+ rs.push(stringFromCharCode(o));
422
+ ++olen;
423
+ }
424
+ var res = [];
425
+ for (off = 0; off < olen; off++)
426
+ res.push(rs[off].charCodeAt(0));
427
+ return res;
428
+ }
429
+ var utfx = (function() {
430
+ "use strict";
431
+ var utfx2 = {};
432
+ utfx2.MAX_CODEPOINT = 1114111;
433
+ utfx2.encodeUTF8 = function(src, dst) {
434
+ var cp = null;
435
+ if (typeof src === "number")
436
+ cp = src, src = function() {
437
+ return null;
438
+ };
439
+ while (cp !== null || (cp = src()) !== null) {
440
+ if (cp < 128)
441
+ dst(cp & 127);
442
+ else if (cp < 2048)
443
+ dst(cp >> 6 & 31 | 192), dst(cp & 63 | 128);
444
+ else if (cp < 65536)
445
+ dst(cp >> 12 & 15 | 224), dst(cp >> 6 & 63 | 128), dst(cp & 63 | 128);
446
+ else
447
+ dst(cp >> 18 & 7 | 240), dst(cp >> 12 & 63 | 128), dst(cp >> 6 & 63 | 128), dst(cp & 63 | 128);
448
+ cp = null;
449
+ }
450
+ };
451
+ utfx2.decodeUTF8 = function(src, dst) {
452
+ var a, b, c, d, fail2 = function(b2) {
453
+ b2 = b2.slice(0, b2.indexOf(null));
454
+ var err = Error(b2.toString());
455
+ err.name = "TruncatedError";
456
+ err["bytes"] = b2;
457
+ throw err;
458
+ };
459
+ while ((a = src()) !== null) {
460
+ if ((a & 128) === 0)
461
+ dst(a);
462
+ else if ((a & 224) === 192)
463
+ (b = src()) === null && fail2([a, b]), dst((a & 31) << 6 | b & 63);
464
+ else if ((a & 240) === 224)
465
+ ((b = src()) === null || (c = src()) === null) && fail2([a, b, c]), dst((a & 15) << 12 | (b & 63) << 6 | c & 63);
466
+ else if ((a & 248) === 240)
467
+ ((b = src()) === null || (c = src()) === null || (d = src()) === null) && fail2([a, b, c, d]), dst((a & 7) << 18 | (b & 63) << 12 | (c & 63) << 6 | d & 63);
468
+ else throw RangeError("Illegal starting byte: " + a);
469
+ }
470
+ };
471
+ utfx2.UTF16toUTF8 = function(src, dst) {
472
+ var c1, c2 = null;
473
+ while (true) {
474
+ if ((c1 = c2 !== null ? c2 : src()) === null)
475
+ break;
476
+ if (c1 >= 55296 && c1 <= 57343) {
477
+ if ((c2 = src()) !== null) {
478
+ if (c2 >= 56320 && c2 <= 57343) {
479
+ dst((c1 - 55296) * 1024 + c2 - 56320 + 65536);
480
+ c2 = null;
481
+ continue;
482
+ }
483
+ }
484
+ }
485
+ dst(c1);
486
+ }
487
+ if (c2 !== null) dst(c2);
488
+ };
489
+ utfx2.UTF8toUTF16 = function(src, dst) {
490
+ var cp = null;
491
+ if (typeof src === "number")
492
+ cp = src, src = function() {
493
+ return null;
494
+ };
495
+ while (cp !== null || (cp = src()) !== null) {
496
+ if (cp <= 65535)
497
+ dst(cp);
498
+ else
499
+ cp -= 65536, dst((cp >> 10) + 55296), dst(cp % 1024 + 56320);
500
+ cp = null;
501
+ }
502
+ };
503
+ utfx2.encodeUTF16toUTF8 = function(src, dst) {
504
+ utfx2.UTF16toUTF8(src, function(cp) {
505
+ utfx2.encodeUTF8(cp, dst);
506
+ });
507
+ };
508
+ utfx2.decodeUTF8toUTF16 = function(src, dst) {
509
+ utfx2.decodeUTF8(src, function(cp) {
510
+ utfx2.UTF8toUTF16(cp, dst);
511
+ });
512
+ };
513
+ utfx2.calculateCodePoint = function(cp) {
514
+ return cp < 128 ? 1 : cp < 2048 ? 2 : cp < 65536 ? 3 : 4;
515
+ };
516
+ utfx2.calculateUTF8 = function(src) {
517
+ var cp, l = 0;
518
+ while ((cp = src()) !== null)
519
+ l += utfx2.calculateCodePoint(cp);
520
+ return l;
521
+ };
522
+ utfx2.calculateUTF16asUTF8 = function(src) {
523
+ var n = 0, l = 0;
524
+ utfx2.UTF16toUTF8(src, function(cp) {
525
+ ++n;
526
+ l += utfx2.calculateCodePoint(cp);
527
+ });
528
+ return [n, l];
529
+ };
530
+ return utfx2;
531
+ })();
532
+ Date.now = Date.now || function() {
533
+ return +/* @__PURE__ */ new Date();
534
+ };
535
+ var BCRYPT_SALT_LEN = 16;
536
+ var GENSALT_DEFAULT_LOG2_ROUNDS = 10;
537
+ var BLOWFISH_NUM_ROUNDS = 16;
538
+ var MAX_EXECUTION_TIME = 100;
539
+ var P_ORIG = [
540
+ 608135816,
541
+ 2242054355,
542
+ 320440878,
543
+ 57701188,
544
+ 2752067618,
545
+ 698298832,
546
+ 137296536,
547
+ 3964562569,
548
+ 1160258022,
549
+ 953160567,
550
+ 3193202383,
551
+ 887688300,
552
+ 3232508343,
553
+ 3380367581,
554
+ 1065670069,
555
+ 3041331479,
556
+ 2450970073,
557
+ 2306472731
558
+ ];
559
+ var S_ORIG = [
560
+ 3509652390,
561
+ 2564797868,
562
+ 805139163,
563
+ 3491422135,
564
+ 3101798381,
565
+ 1780907670,
566
+ 3128725573,
567
+ 4046225305,
568
+ 614570311,
569
+ 3012652279,
570
+ 134345442,
571
+ 2240740374,
572
+ 1667834072,
573
+ 1901547113,
574
+ 2757295779,
575
+ 4103290238,
576
+ 227898511,
577
+ 1921955416,
578
+ 1904987480,
579
+ 2182433518,
580
+ 2069144605,
581
+ 3260701109,
582
+ 2620446009,
583
+ 720527379,
584
+ 3318853667,
585
+ 677414384,
586
+ 3393288472,
587
+ 3101374703,
588
+ 2390351024,
589
+ 1614419982,
590
+ 1822297739,
591
+ 2954791486,
592
+ 3608508353,
593
+ 3174124327,
594
+ 2024746970,
595
+ 1432378464,
596
+ 3864339955,
597
+ 2857741204,
598
+ 1464375394,
599
+ 1676153920,
600
+ 1439316330,
601
+ 715854006,
602
+ 3033291828,
603
+ 289532110,
604
+ 2706671279,
605
+ 2087905683,
606
+ 3018724369,
607
+ 1668267050,
608
+ 732546397,
609
+ 1947742710,
610
+ 3462151702,
611
+ 2609353502,
612
+ 2950085171,
613
+ 1814351708,
614
+ 2050118529,
615
+ 680887927,
616
+ 999245976,
617
+ 1800124847,
618
+ 3300911131,
619
+ 1713906067,
620
+ 1641548236,
621
+ 4213287313,
622
+ 1216130144,
623
+ 1575780402,
624
+ 4018429277,
625
+ 3917837745,
626
+ 3693486850,
627
+ 3949271944,
628
+ 596196993,
629
+ 3549867205,
630
+ 258830323,
631
+ 2213823033,
632
+ 772490370,
633
+ 2760122372,
634
+ 1774776394,
635
+ 2652871518,
636
+ 566650946,
637
+ 4142492826,
638
+ 1728879713,
639
+ 2882767088,
640
+ 1783734482,
641
+ 3629395816,
642
+ 2517608232,
643
+ 2874225571,
644
+ 1861159788,
645
+ 326777828,
646
+ 3124490320,
647
+ 2130389656,
648
+ 2716951837,
649
+ 967770486,
650
+ 1724537150,
651
+ 2185432712,
652
+ 2364442137,
653
+ 1164943284,
654
+ 2105845187,
655
+ 998989502,
656
+ 3765401048,
657
+ 2244026483,
658
+ 1075463327,
659
+ 1455516326,
660
+ 1322494562,
661
+ 910128902,
662
+ 469688178,
663
+ 1117454909,
664
+ 936433444,
665
+ 3490320968,
666
+ 3675253459,
667
+ 1240580251,
668
+ 122909385,
669
+ 2157517691,
670
+ 634681816,
671
+ 4142456567,
672
+ 3825094682,
673
+ 3061402683,
674
+ 2540495037,
675
+ 79693498,
676
+ 3249098678,
677
+ 1084186820,
678
+ 1583128258,
679
+ 426386531,
680
+ 1761308591,
681
+ 1047286709,
682
+ 322548459,
683
+ 995290223,
684
+ 1845252383,
685
+ 2603652396,
686
+ 3431023940,
687
+ 2942221577,
688
+ 3202600964,
689
+ 3727903485,
690
+ 1712269319,
691
+ 422464435,
692
+ 3234572375,
693
+ 1170764815,
694
+ 3523960633,
695
+ 3117677531,
696
+ 1434042557,
697
+ 442511882,
698
+ 3600875718,
699
+ 1076654713,
700
+ 1738483198,
701
+ 4213154764,
702
+ 2393238008,
703
+ 3677496056,
704
+ 1014306527,
705
+ 4251020053,
706
+ 793779912,
707
+ 2902807211,
708
+ 842905082,
709
+ 4246964064,
710
+ 1395751752,
711
+ 1040244610,
712
+ 2656851899,
713
+ 3396308128,
714
+ 445077038,
715
+ 3742853595,
716
+ 3577915638,
717
+ 679411651,
718
+ 2892444358,
719
+ 2354009459,
720
+ 1767581616,
721
+ 3150600392,
722
+ 3791627101,
723
+ 3102740896,
724
+ 284835224,
725
+ 4246832056,
726
+ 1258075500,
727
+ 768725851,
728
+ 2589189241,
729
+ 3069724005,
730
+ 3532540348,
731
+ 1274779536,
732
+ 3789419226,
733
+ 2764799539,
734
+ 1660621633,
735
+ 3471099624,
736
+ 4011903706,
737
+ 913787905,
738
+ 3497959166,
739
+ 737222580,
740
+ 2514213453,
741
+ 2928710040,
742
+ 3937242737,
743
+ 1804850592,
744
+ 3499020752,
745
+ 2949064160,
746
+ 2386320175,
747
+ 2390070455,
748
+ 2415321851,
749
+ 4061277028,
750
+ 2290661394,
751
+ 2416832540,
752
+ 1336762016,
753
+ 1754252060,
754
+ 3520065937,
755
+ 3014181293,
756
+ 791618072,
757
+ 3188594551,
758
+ 3933548030,
759
+ 2332172193,
760
+ 3852520463,
761
+ 3043980520,
762
+ 413987798,
763
+ 3465142937,
764
+ 3030929376,
765
+ 4245938359,
766
+ 2093235073,
767
+ 3534596313,
768
+ 375366246,
769
+ 2157278981,
770
+ 2479649556,
771
+ 555357303,
772
+ 3870105701,
773
+ 2008414854,
774
+ 3344188149,
775
+ 4221384143,
776
+ 3956125452,
777
+ 2067696032,
778
+ 3594591187,
779
+ 2921233993,
780
+ 2428461,
781
+ 544322398,
782
+ 577241275,
783
+ 1471733935,
784
+ 610547355,
785
+ 4027169054,
786
+ 1432588573,
787
+ 1507829418,
788
+ 2025931657,
789
+ 3646575487,
790
+ 545086370,
791
+ 48609733,
792
+ 2200306550,
793
+ 1653985193,
794
+ 298326376,
795
+ 1316178497,
796
+ 3007786442,
797
+ 2064951626,
798
+ 458293330,
799
+ 2589141269,
800
+ 3591329599,
801
+ 3164325604,
802
+ 727753846,
803
+ 2179363840,
804
+ 146436021,
805
+ 1461446943,
806
+ 4069977195,
807
+ 705550613,
808
+ 3059967265,
809
+ 3887724982,
810
+ 4281599278,
811
+ 3313849956,
812
+ 1404054877,
813
+ 2845806497,
814
+ 146425753,
815
+ 1854211946,
816
+ 1266315497,
817
+ 3048417604,
818
+ 3681880366,
819
+ 3289982499,
820
+ 290971e4,
821
+ 1235738493,
822
+ 2632868024,
823
+ 2414719590,
824
+ 3970600049,
825
+ 1771706367,
826
+ 1449415276,
827
+ 3266420449,
828
+ 422970021,
829
+ 1963543593,
830
+ 2690192192,
831
+ 3826793022,
832
+ 1062508698,
833
+ 1531092325,
834
+ 1804592342,
835
+ 2583117782,
836
+ 2714934279,
837
+ 4024971509,
838
+ 1294809318,
839
+ 4028980673,
840
+ 1289560198,
841
+ 2221992742,
842
+ 1669523910,
843
+ 35572830,
844
+ 157838143,
845
+ 1052438473,
846
+ 1016535060,
847
+ 1802137761,
848
+ 1753167236,
849
+ 1386275462,
850
+ 3080475397,
851
+ 2857371447,
852
+ 1040679964,
853
+ 2145300060,
854
+ 2390574316,
855
+ 1461121720,
856
+ 2956646967,
857
+ 4031777805,
858
+ 4028374788,
859
+ 33600511,
860
+ 2920084762,
861
+ 1018524850,
862
+ 629373528,
863
+ 3691585981,
864
+ 3515945977,
865
+ 2091462646,
866
+ 2486323059,
867
+ 586499841,
868
+ 988145025,
869
+ 935516892,
870
+ 3367335476,
871
+ 2599673255,
872
+ 2839830854,
873
+ 265290510,
874
+ 3972581182,
875
+ 2759138881,
876
+ 3795373465,
877
+ 1005194799,
878
+ 847297441,
879
+ 406762289,
880
+ 1314163512,
881
+ 1332590856,
882
+ 1866599683,
883
+ 4127851711,
884
+ 750260880,
885
+ 613907577,
886
+ 1450815602,
887
+ 3165620655,
888
+ 3734664991,
889
+ 3650291728,
890
+ 3012275730,
891
+ 3704569646,
892
+ 1427272223,
893
+ 778793252,
894
+ 1343938022,
895
+ 2676280711,
896
+ 2052605720,
897
+ 1946737175,
898
+ 3164576444,
899
+ 3914038668,
900
+ 3967478842,
901
+ 3682934266,
902
+ 1661551462,
903
+ 3294938066,
904
+ 4011595847,
905
+ 840292616,
906
+ 3712170807,
907
+ 616741398,
908
+ 312560963,
909
+ 711312465,
910
+ 1351876610,
911
+ 322626781,
912
+ 1910503582,
913
+ 271666773,
914
+ 2175563734,
915
+ 1594956187,
916
+ 70604529,
917
+ 3617834859,
918
+ 1007753275,
919
+ 1495573769,
920
+ 4069517037,
921
+ 2549218298,
922
+ 2663038764,
923
+ 504708206,
924
+ 2263041392,
925
+ 3941167025,
926
+ 2249088522,
927
+ 1514023603,
928
+ 1998579484,
929
+ 1312622330,
930
+ 694541497,
931
+ 2582060303,
932
+ 2151582166,
933
+ 1382467621,
934
+ 776784248,
935
+ 2618340202,
936
+ 3323268794,
937
+ 2497899128,
938
+ 2784771155,
939
+ 503983604,
940
+ 4076293799,
941
+ 907881277,
942
+ 423175695,
943
+ 432175456,
944
+ 1378068232,
945
+ 4145222326,
946
+ 3954048622,
947
+ 3938656102,
948
+ 3820766613,
949
+ 2793130115,
950
+ 2977904593,
951
+ 26017576,
952
+ 3274890735,
953
+ 3194772133,
954
+ 1700274565,
955
+ 1756076034,
956
+ 4006520079,
957
+ 3677328699,
958
+ 720338349,
959
+ 1533947780,
960
+ 354530856,
961
+ 688349552,
962
+ 3973924725,
963
+ 1637815568,
964
+ 332179504,
965
+ 3949051286,
966
+ 53804574,
967
+ 2852348879,
968
+ 3044236432,
969
+ 1282449977,
970
+ 3583942155,
971
+ 3416972820,
972
+ 4006381244,
973
+ 1617046695,
974
+ 2628476075,
975
+ 3002303598,
976
+ 1686838959,
977
+ 431878346,
978
+ 2686675385,
979
+ 1700445008,
980
+ 1080580658,
981
+ 1009431731,
982
+ 832498133,
983
+ 3223435511,
984
+ 2605976345,
985
+ 2271191193,
986
+ 2516031870,
987
+ 1648197032,
988
+ 4164389018,
989
+ 2548247927,
990
+ 300782431,
991
+ 375919233,
992
+ 238389289,
993
+ 3353747414,
994
+ 2531188641,
995
+ 2019080857,
996
+ 1475708069,
997
+ 455242339,
998
+ 2609103871,
999
+ 448939670,
1000
+ 3451063019,
1001
+ 1395535956,
1002
+ 2413381860,
1003
+ 1841049896,
1004
+ 1491858159,
1005
+ 885456874,
1006
+ 4264095073,
1007
+ 4001119347,
1008
+ 1565136089,
1009
+ 3898914787,
1010
+ 1108368660,
1011
+ 540939232,
1012
+ 1173283510,
1013
+ 2745871338,
1014
+ 3681308437,
1015
+ 4207628240,
1016
+ 3343053890,
1017
+ 4016749493,
1018
+ 1699691293,
1019
+ 1103962373,
1020
+ 3625875870,
1021
+ 2256883143,
1022
+ 3830138730,
1023
+ 1031889488,
1024
+ 3479347698,
1025
+ 1535977030,
1026
+ 4236805024,
1027
+ 3251091107,
1028
+ 2132092099,
1029
+ 1774941330,
1030
+ 1199868427,
1031
+ 1452454533,
1032
+ 157007616,
1033
+ 2904115357,
1034
+ 342012276,
1035
+ 595725824,
1036
+ 1480756522,
1037
+ 206960106,
1038
+ 497939518,
1039
+ 591360097,
1040
+ 863170706,
1041
+ 2375253569,
1042
+ 3596610801,
1043
+ 1814182875,
1044
+ 2094937945,
1045
+ 3421402208,
1046
+ 1082520231,
1047
+ 3463918190,
1048
+ 2785509508,
1049
+ 435703966,
1050
+ 3908032597,
1051
+ 1641649973,
1052
+ 2842273706,
1053
+ 3305899714,
1054
+ 1510255612,
1055
+ 2148256476,
1056
+ 2655287854,
1057
+ 3276092548,
1058
+ 4258621189,
1059
+ 236887753,
1060
+ 3681803219,
1061
+ 274041037,
1062
+ 1734335097,
1063
+ 3815195456,
1064
+ 3317970021,
1065
+ 1899903192,
1066
+ 1026095262,
1067
+ 4050517792,
1068
+ 356393447,
1069
+ 2410691914,
1070
+ 3873677099,
1071
+ 3682840055,
1072
+ 3913112168,
1073
+ 2491498743,
1074
+ 4132185628,
1075
+ 2489919796,
1076
+ 1091903735,
1077
+ 1979897079,
1078
+ 3170134830,
1079
+ 3567386728,
1080
+ 3557303409,
1081
+ 857797738,
1082
+ 1136121015,
1083
+ 1342202287,
1084
+ 507115054,
1085
+ 2535736646,
1086
+ 337727348,
1087
+ 3213592640,
1088
+ 1301675037,
1089
+ 2528481711,
1090
+ 1895095763,
1091
+ 1721773893,
1092
+ 3216771564,
1093
+ 62756741,
1094
+ 2142006736,
1095
+ 835421444,
1096
+ 2531993523,
1097
+ 1442658625,
1098
+ 3659876326,
1099
+ 2882144922,
1100
+ 676362277,
1101
+ 1392781812,
1102
+ 170690266,
1103
+ 3921047035,
1104
+ 1759253602,
1105
+ 3611846912,
1106
+ 1745797284,
1107
+ 664899054,
1108
+ 1329594018,
1109
+ 3901205900,
1110
+ 3045908486,
1111
+ 2062866102,
1112
+ 2865634940,
1113
+ 3543621612,
1114
+ 3464012697,
1115
+ 1080764994,
1116
+ 553557557,
1117
+ 3656615353,
1118
+ 3996768171,
1119
+ 991055499,
1120
+ 499776247,
1121
+ 1265440854,
1122
+ 648242737,
1123
+ 3940784050,
1124
+ 980351604,
1125
+ 3713745714,
1126
+ 1749149687,
1127
+ 3396870395,
1128
+ 4211799374,
1129
+ 3640570775,
1130
+ 1161844396,
1131
+ 3125318951,
1132
+ 1431517754,
1133
+ 545492359,
1134
+ 4268468663,
1135
+ 3499529547,
1136
+ 1437099964,
1137
+ 2702547544,
1138
+ 3433638243,
1139
+ 2581715763,
1140
+ 2787789398,
1141
+ 1060185593,
1142
+ 1593081372,
1143
+ 2418618748,
1144
+ 4260947970,
1145
+ 69676912,
1146
+ 2159744348,
1147
+ 86519011,
1148
+ 2512459080,
1149
+ 3838209314,
1150
+ 1220612927,
1151
+ 3339683548,
1152
+ 133810670,
1153
+ 1090789135,
1154
+ 1078426020,
1155
+ 1569222167,
1156
+ 845107691,
1157
+ 3583754449,
1158
+ 4072456591,
1159
+ 1091646820,
1160
+ 628848692,
1161
+ 1613405280,
1162
+ 3757631651,
1163
+ 526609435,
1164
+ 236106946,
1165
+ 48312990,
1166
+ 2942717905,
1167
+ 3402727701,
1168
+ 1797494240,
1169
+ 859738849,
1170
+ 992217954,
1171
+ 4005476642,
1172
+ 2243076622,
1173
+ 3870952857,
1174
+ 3732016268,
1175
+ 765654824,
1176
+ 3490871365,
1177
+ 2511836413,
1178
+ 1685915746,
1179
+ 3888969200,
1180
+ 1414112111,
1181
+ 2273134842,
1182
+ 3281911079,
1183
+ 4080962846,
1184
+ 172450625,
1185
+ 2569994100,
1186
+ 980381355,
1187
+ 4109958455,
1188
+ 2819808352,
1189
+ 2716589560,
1190
+ 2568741196,
1191
+ 3681446669,
1192
+ 3329971472,
1193
+ 1835478071,
1194
+ 660984891,
1195
+ 3704678404,
1196
+ 4045999559,
1197
+ 3422617507,
1198
+ 3040415634,
1199
+ 1762651403,
1200
+ 1719377915,
1201
+ 3470491036,
1202
+ 2693910283,
1203
+ 3642056355,
1204
+ 3138596744,
1205
+ 1364962596,
1206
+ 2073328063,
1207
+ 1983633131,
1208
+ 926494387,
1209
+ 3423689081,
1210
+ 2150032023,
1211
+ 4096667949,
1212
+ 1749200295,
1213
+ 3328846651,
1214
+ 309677260,
1215
+ 2016342300,
1216
+ 1779581495,
1217
+ 3079819751,
1218
+ 111262694,
1219
+ 1274766160,
1220
+ 443224088,
1221
+ 298511866,
1222
+ 1025883608,
1223
+ 3806446537,
1224
+ 1145181785,
1225
+ 168956806,
1226
+ 3641502830,
1227
+ 3584813610,
1228
+ 1689216846,
1229
+ 3666258015,
1230
+ 3200248200,
1231
+ 1692713982,
1232
+ 2646376535,
1233
+ 4042768518,
1234
+ 1618508792,
1235
+ 1610833997,
1236
+ 3523052358,
1237
+ 4130873264,
1238
+ 2001055236,
1239
+ 3610705100,
1240
+ 2202168115,
1241
+ 4028541809,
1242
+ 2961195399,
1243
+ 1006657119,
1244
+ 2006996926,
1245
+ 3186142756,
1246
+ 1430667929,
1247
+ 3210227297,
1248
+ 1314452623,
1249
+ 4074634658,
1250
+ 4101304120,
1251
+ 2273951170,
1252
+ 1399257539,
1253
+ 3367210612,
1254
+ 3027628629,
1255
+ 1190975929,
1256
+ 2062231137,
1257
+ 2333990788,
1258
+ 2221543033,
1259
+ 2438960610,
1260
+ 1181637006,
1261
+ 548689776,
1262
+ 2362791313,
1263
+ 3372408396,
1264
+ 3104550113,
1265
+ 3145860560,
1266
+ 296247880,
1267
+ 1970579870,
1268
+ 3078560182,
1269
+ 3769228297,
1270
+ 1714227617,
1271
+ 3291629107,
1272
+ 3898220290,
1273
+ 166772364,
1274
+ 1251581989,
1275
+ 493813264,
1276
+ 448347421,
1277
+ 195405023,
1278
+ 2709975567,
1279
+ 677966185,
1280
+ 3703036547,
1281
+ 1463355134,
1282
+ 2715995803,
1283
+ 1338867538,
1284
+ 1343315457,
1285
+ 2802222074,
1286
+ 2684532164,
1287
+ 233230375,
1288
+ 2599980071,
1289
+ 2000651841,
1290
+ 3277868038,
1291
+ 1638401717,
1292
+ 4028070440,
1293
+ 3237316320,
1294
+ 6314154,
1295
+ 819756386,
1296
+ 300326615,
1297
+ 590932579,
1298
+ 1405279636,
1299
+ 3267499572,
1300
+ 3150704214,
1301
+ 2428286686,
1302
+ 3959192993,
1303
+ 3461946742,
1304
+ 1862657033,
1305
+ 1266418056,
1306
+ 963775037,
1307
+ 2089974820,
1308
+ 2263052895,
1309
+ 1917689273,
1310
+ 448879540,
1311
+ 3550394620,
1312
+ 3981727096,
1313
+ 150775221,
1314
+ 3627908307,
1315
+ 1303187396,
1316
+ 508620638,
1317
+ 2975983352,
1318
+ 2726630617,
1319
+ 1817252668,
1320
+ 1876281319,
1321
+ 1457606340,
1322
+ 908771278,
1323
+ 3720792119,
1324
+ 3617206836,
1325
+ 2455994898,
1326
+ 1729034894,
1327
+ 1080033504,
1328
+ 976866871,
1329
+ 3556439503,
1330
+ 2881648439,
1331
+ 1522871579,
1332
+ 1555064734,
1333
+ 1336096578,
1334
+ 3548522304,
1335
+ 2579274686,
1336
+ 3574697629,
1337
+ 3205460757,
1338
+ 3593280638,
1339
+ 3338716283,
1340
+ 3079412587,
1341
+ 564236357,
1342
+ 2993598910,
1343
+ 1781952180,
1344
+ 1464380207,
1345
+ 3163844217,
1346
+ 3332601554,
1347
+ 1699332808,
1348
+ 1393555694,
1349
+ 1183702653,
1350
+ 3581086237,
1351
+ 1288719814,
1352
+ 691649499,
1353
+ 2847557200,
1354
+ 2895455976,
1355
+ 3193889540,
1356
+ 2717570544,
1357
+ 1781354906,
1358
+ 1676643554,
1359
+ 2592534050,
1360
+ 3230253752,
1361
+ 1126444790,
1362
+ 2770207658,
1363
+ 2633158820,
1364
+ 2210423226,
1365
+ 2615765581,
1366
+ 2414155088,
1367
+ 3127139286,
1368
+ 673620729,
1369
+ 2805611233,
1370
+ 1269405062,
1371
+ 4015350505,
1372
+ 3341807571,
1373
+ 4149409754,
1374
+ 1057255273,
1375
+ 2012875353,
1376
+ 2162469141,
1377
+ 2276492801,
1378
+ 2601117357,
1379
+ 993977747,
1380
+ 3918593370,
1381
+ 2654263191,
1382
+ 753973209,
1383
+ 36408145,
1384
+ 2530585658,
1385
+ 25011837,
1386
+ 3520020182,
1387
+ 2088578344,
1388
+ 530523599,
1389
+ 2918365339,
1390
+ 1524020338,
1391
+ 1518925132,
1392
+ 3760827505,
1393
+ 3759777254,
1394
+ 1202760957,
1395
+ 3985898139,
1396
+ 3906192525,
1397
+ 674977740,
1398
+ 4174734889,
1399
+ 2031300136,
1400
+ 2019492241,
1401
+ 3983892565,
1402
+ 4153806404,
1403
+ 3822280332,
1404
+ 352677332,
1405
+ 2297720250,
1406
+ 60907813,
1407
+ 90501309,
1408
+ 3286998549,
1409
+ 1016092578,
1410
+ 2535922412,
1411
+ 2839152426,
1412
+ 457141659,
1413
+ 509813237,
1414
+ 4120667899,
1415
+ 652014361,
1416
+ 1966332200,
1417
+ 2975202805,
1418
+ 55981186,
1419
+ 2327461051,
1420
+ 676427537,
1421
+ 3255491064,
1422
+ 2882294119,
1423
+ 3433927263,
1424
+ 1307055953,
1425
+ 942726286,
1426
+ 933058658,
1427
+ 2468411793,
1428
+ 3933900994,
1429
+ 4215176142,
1430
+ 1361170020,
1431
+ 2001714738,
1432
+ 2830558078,
1433
+ 3274259782,
1434
+ 1222529897,
1435
+ 1679025792,
1436
+ 2729314320,
1437
+ 3714953764,
1438
+ 1770335741,
1439
+ 151462246,
1440
+ 3013232138,
1441
+ 1682292957,
1442
+ 1483529935,
1443
+ 471910574,
1444
+ 1539241949,
1445
+ 458788160,
1446
+ 3436315007,
1447
+ 1807016891,
1448
+ 3718408830,
1449
+ 978976581,
1450
+ 1043663428,
1451
+ 3165965781,
1452
+ 1927990952,
1453
+ 4200891579,
1454
+ 2372276910,
1455
+ 3208408903,
1456
+ 3533431907,
1457
+ 1412390302,
1458
+ 2931980059,
1459
+ 4132332400,
1460
+ 1947078029,
1461
+ 3881505623,
1462
+ 4168226417,
1463
+ 2941484381,
1464
+ 1077988104,
1465
+ 1320477388,
1466
+ 886195818,
1467
+ 18198404,
1468
+ 3786409e3,
1469
+ 2509781533,
1470
+ 112762804,
1471
+ 3463356488,
1472
+ 1866414978,
1473
+ 891333506,
1474
+ 18488651,
1475
+ 661792760,
1476
+ 1628790961,
1477
+ 3885187036,
1478
+ 3141171499,
1479
+ 876946877,
1480
+ 2693282273,
1481
+ 1372485963,
1482
+ 791857591,
1483
+ 2686433993,
1484
+ 3759982718,
1485
+ 3167212022,
1486
+ 3472953795,
1487
+ 2716379847,
1488
+ 445679433,
1489
+ 3561995674,
1490
+ 3504004811,
1491
+ 3574258232,
1492
+ 54117162,
1493
+ 3331405415,
1494
+ 2381918588,
1495
+ 3769707343,
1496
+ 4154350007,
1497
+ 1140177722,
1498
+ 4074052095,
1499
+ 668550556,
1500
+ 3214352940,
1501
+ 367459370,
1502
+ 261225585,
1503
+ 2610173221,
1504
+ 4209349473,
1505
+ 3468074219,
1506
+ 3265815641,
1507
+ 314222801,
1508
+ 3066103646,
1509
+ 3808782860,
1510
+ 282218597,
1511
+ 3406013506,
1512
+ 3773591054,
1513
+ 379116347,
1514
+ 1285071038,
1515
+ 846784868,
1516
+ 2669647154,
1517
+ 3771962079,
1518
+ 3550491691,
1519
+ 2305946142,
1520
+ 453669953,
1521
+ 1268987020,
1522
+ 3317592352,
1523
+ 3279303384,
1524
+ 3744833421,
1525
+ 2610507566,
1526
+ 3859509063,
1527
+ 266596637,
1528
+ 3847019092,
1529
+ 517658769,
1530
+ 3462560207,
1531
+ 3443424879,
1532
+ 370717030,
1533
+ 4247526661,
1534
+ 2224018117,
1535
+ 4143653529,
1536
+ 4112773975,
1537
+ 2788324899,
1538
+ 2477274417,
1539
+ 1456262402,
1540
+ 2901442914,
1541
+ 1517677493,
1542
+ 1846949527,
1543
+ 2295493580,
1544
+ 3734397586,
1545
+ 2176403920,
1546
+ 1280348187,
1547
+ 1908823572,
1548
+ 3871786941,
1549
+ 846861322,
1550
+ 1172426758,
1551
+ 3287448474,
1552
+ 3383383037,
1553
+ 1655181056,
1554
+ 3139813346,
1555
+ 901632758,
1556
+ 1897031941,
1557
+ 2986607138,
1558
+ 3066810236,
1559
+ 3447102507,
1560
+ 1393639104,
1561
+ 373351379,
1562
+ 950779232,
1563
+ 625454576,
1564
+ 3124240540,
1565
+ 4148612726,
1566
+ 2007998917,
1567
+ 544563296,
1568
+ 2244738638,
1569
+ 2330496472,
1570
+ 2058025392,
1571
+ 1291430526,
1572
+ 424198748,
1573
+ 50039436,
1574
+ 29584100,
1575
+ 3605783033,
1576
+ 2429876329,
1577
+ 2791104160,
1578
+ 1057563949,
1579
+ 3255363231,
1580
+ 3075367218,
1581
+ 3463963227,
1582
+ 1469046755,
1583
+ 985887462
1584
+ ];
1585
+ var C_ORIG = [
1586
+ 1332899944,
1587
+ 1700884034,
1588
+ 1701343084,
1589
+ 1684370003,
1590
+ 1668446532,
1591
+ 1869963892
1592
+ ];
1593
+ function _encipher(lr, off, P, S) {
1594
+ var n, l = lr[off], r = lr[off + 1];
1595
+ l ^= P[0];
1596
+ n = S[l >>> 24];
1597
+ n += S[256 | l >> 16 & 255];
1598
+ n ^= S[512 | l >> 8 & 255];
1599
+ n += S[768 | l & 255];
1600
+ r ^= n ^ P[1];
1601
+ n = S[r >>> 24];
1602
+ n += S[256 | r >> 16 & 255];
1603
+ n ^= S[512 | r >> 8 & 255];
1604
+ n += S[768 | r & 255];
1605
+ l ^= n ^ P[2];
1606
+ n = S[l >>> 24];
1607
+ n += S[256 | l >> 16 & 255];
1608
+ n ^= S[512 | l >> 8 & 255];
1609
+ n += S[768 | l & 255];
1610
+ r ^= n ^ P[3];
1611
+ n = S[r >>> 24];
1612
+ n += S[256 | r >> 16 & 255];
1613
+ n ^= S[512 | r >> 8 & 255];
1614
+ n += S[768 | r & 255];
1615
+ l ^= n ^ P[4];
1616
+ n = S[l >>> 24];
1617
+ n += S[256 | l >> 16 & 255];
1618
+ n ^= S[512 | l >> 8 & 255];
1619
+ n += S[768 | l & 255];
1620
+ r ^= n ^ P[5];
1621
+ n = S[r >>> 24];
1622
+ n += S[256 | r >> 16 & 255];
1623
+ n ^= S[512 | r >> 8 & 255];
1624
+ n += S[768 | r & 255];
1625
+ l ^= n ^ P[6];
1626
+ n = S[l >>> 24];
1627
+ n += S[256 | l >> 16 & 255];
1628
+ n ^= S[512 | l >> 8 & 255];
1629
+ n += S[768 | l & 255];
1630
+ r ^= n ^ P[7];
1631
+ n = S[r >>> 24];
1632
+ n += S[256 | r >> 16 & 255];
1633
+ n ^= S[512 | r >> 8 & 255];
1634
+ n += S[768 | r & 255];
1635
+ l ^= n ^ P[8];
1636
+ n = S[l >>> 24];
1637
+ n += S[256 | l >> 16 & 255];
1638
+ n ^= S[512 | l >> 8 & 255];
1639
+ n += S[768 | l & 255];
1640
+ r ^= n ^ P[9];
1641
+ n = S[r >>> 24];
1642
+ n += S[256 | r >> 16 & 255];
1643
+ n ^= S[512 | r >> 8 & 255];
1644
+ n += S[768 | r & 255];
1645
+ l ^= n ^ P[10];
1646
+ n = S[l >>> 24];
1647
+ n += S[256 | l >> 16 & 255];
1648
+ n ^= S[512 | l >> 8 & 255];
1649
+ n += S[768 | l & 255];
1650
+ r ^= n ^ P[11];
1651
+ n = S[r >>> 24];
1652
+ n += S[256 | r >> 16 & 255];
1653
+ n ^= S[512 | r >> 8 & 255];
1654
+ n += S[768 | r & 255];
1655
+ l ^= n ^ P[12];
1656
+ n = S[l >>> 24];
1657
+ n += S[256 | l >> 16 & 255];
1658
+ n ^= S[512 | l >> 8 & 255];
1659
+ n += S[768 | l & 255];
1660
+ r ^= n ^ P[13];
1661
+ n = S[r >>> 24];
1662
+ n += S[256 | r >> 16 & 255];
1663
+ n ^= S[512 | r >> 8 & 255];
1664
+ n += S[768 | r & 255];
1665
+ l ^= n ^ P[14];
1666
+ n = S[l >>> 24];
1667
+ n += S[256 | l >> 16 & 255];
1668
+ n ^= S[512 | l >> 8 & 255];
1669
+ n += S[768 | l & 255];
1670
+ r ^= n ^ P[15];
1671
+ n = S[r >>> 24];
1672
+ n += S[256 | r >> 16 & 255];
1673
+ n ^= S[512 | r >> 8 & 255];
1674
+ n += S[768 | r & 255];
1675
+ l ^= n ^ P[16];
1676
+ lr[off] = r ^ P[BLOWFISH_NUM_ROUNDS + 1];
1677
+ lr[off + 1] = l;
1678
+ return lr;
1679
+ }
1680
+ function _streamtoword(data, offp) {
1681
+ for (var i = 0, word = 0; i < 4; ++i)
1682
+ word = word << 8 | data[offp] & 255, offp = (offp + 1) % data.length;
1683
+ return { key: word, offp };
1684
+ }
1685
+ function _key(key, P, S) {
1686
+ var offset = 0, lr = [0, 0], plen = P.length, slen = S.length, sw;
1687
+ for (var i = 0; i < plen; i++)
1688
+ sw = _streamtoword(key, offset), offset = sw.offp, P[i] = P[i] ^ sw.key;
1689
+ for (i = 0; i < plen; i += 2)
1690
+ lr = _encipher(lr, 0, P, S), P[i] = lr[0], P[i + 1] = lr[1];
1691
+ for (i = 0; i < slen; i += 2)
1692
+ lr = _encipher(lr, 0, P, S), S[i] = lr[0], S[i + 1] = lr[1];
1693
+ }
1694
+ function _ekskey(data, key, P, S) {
1695
+ var offp = 0, lr = [0, 0], plen = P.length, slen = S.length, sw;
1696
+ for (var i = 0; i < plen; i++)
1697
+ sw = _streamtoword(key, offp), offp = sw.offp, P[i] = P[i] ^ sw.key;
1698
+ offp = 0;
1699
+ for (i = 0; i < plen; i += 2)
1700
+ sw = _streamtoword(data, offp), offp = sw.offp, lr[0] ^= sw.key, sw = _streamtoword(data, offp), offp = sw.offp, lr[1] ^= sw.key, lr = _encipher(lr, 0, P, S), P[i] = lr[0], P[i + 1] = lr[1];
1701
+ for (i = 0; i < slen; i += 2)
1702
+ sw = _streamtoword(data, offp), offp = sw.offp, lr[0] ^= sw.key, sw = _streamtoword(data, offp), offp = sw.offp, lr[1] ^= sw.key, lr = _encipher(lr, 0, P, S), S[i] = lr[0], S[i + 1] = lr[1];
1703
+ }
1704
+ function _crypt(b, salt, rounds, callback, progressCallback) {
1705
+ var cdata = C_ORIG.slice(), clen = cdata.length, err;
1706
+ if (rounds < 4 || rounds > 31) {
1707
+ err = Error("Illegal number of rounds (4-31): " + rounds);
1708
+ if (callback) {
1709
+ nextTick(callback.bind(this, err));
1710
+ return;
1711
+ } else
1712
+ throw err;
1713
+ }
1714
+ if (salt.length !== BCRYPT_SALT_LEN) {
1715
+ err = Error("Illegal salt length: " + salt.length + " != " + BCRYPT_SALT_LEN);
1716
+ if (callback) {
1717
+ nextTick(callback.bind(this, err));
1718
+ return;
1719
+ } else
1720
+ throw err;
1721
+ }
1722
+ rounds = 1 << rounds >>> 0;
1723
+ var P, S, i = 0, j;
1724
+ if (Int32Array) {
1725
+ P = new Int32Array(P_ORIG);
1726
+ S = new Int32Array(S_ORIG);
1727
+ } else {
1728
+ P = P_ORIG.slice();
1729
+ S = S_ORIG.slice();
1730
+ }
1731
+ _ekskey(salt, b, P, S);
1732
+ function next() {
1733
+ if (progressCallback)
1734
+ progressCallback(i / rounds);
1735
+ if (i < rounds) {
1736
+ var start = Date.now();
1737
+ for (; i < rounds; ) {
1738
+ i = i + 1;
1739
+ _key(b, P, S);
1740
+ _key(salt, P, S);
1741
+ if (Date.now() - start > MAX_EXECUTION_TIME)
1742
+ break;
1743
+ }
1744
+ } else {
1745
+ for (i = 0; i < 64; i++)
1746
+ for (j = 0; j < clen >> 1; j++)
1747
+ _encipher(cdata, j << 1, P, S);
1748
+ var ret = [];
1749
+ for (i = 0; i < clen; i++)
1750
+ ret.push((cdata[i] >> 24 & 255) >>> 0), ret.push((cdata[i] >> 16 & 255) >>> 0), ret.push((cdata[i] >> 8 & 255) >>> 0), ret.push((cdata[i] & 255) >>> 0);
1751
+ if (callback) {
1752
+ callback(null, ret);
1753
+ return;
1754
+ } else
1755
+ return ret;
1756
+ }
1757
+ if (callback)
1758
+ nextTick(next);
1759
+ }
1760
+ if (typeof callback !== "undefined") {
1761
+ next();
1762
+ } else {
1763
+ var res;
1764
+ while (true)
1765
+ if (typeof (res = next()) !== "undefined")
1766
+ return res || [];
1767
+ }
1768
+ }
1769
+ function _hash(s, salt, callback, progressCallback) {
1770
+ var err;
1771
+ if (typeof s !== "string" || typeof salt !== "string") {
1772
+ err = Error("Invalid string / salt: Not a string");
1773
+ if (callback) {
1774
+ nextTick(callback.bind(this, err));
1775
+ return;
1776
+ } else
1777
+ throw err;
1778
+ }
1779
+ var minor, offset;
1780
+ if (salt.charAt(0) !== "$" || salt.charAt(1) !== "2") {
1781
+ err = Error("Invalid salt version: " + salt.substring(0, 2));
1782
+ if (callback) {
1783
+ nextTick(callback.bind(this, err));
1784
+ return;
1785
+ } else
1786
+ throw err;
1787
+ }
1788
+ if (salt.charAt(2) === "$")
1789
+ minor = String.fromCharCode(0), offset = 3;
1790
+ else {
1791
+ minor = salt.charAt(2);
1792
+ if (minor !== "a" && minor !== "b" && minor !== "y" || salt.charAt(3) !== "$") {
1793
+ err = Error("Invalid salt revision: " + salt.substring(2, 4));
1794
+ if (callback) {
1795
+ nextTick(callback.bind(this, err));
1796
+ return;
1797
+ } else
1798
+ throw err;
1799
+ }
1800
+ offset = 4;
1801
+ }
1802
+ if (salt.charAt(offset + 2) > "$") {
1803
+ err = Error("Missing salt rounds");
1804
+ if (callback) {
1805
+ nextTick(callback.bind(this, err));
1806
+ return;
1807
+ } else
1808
+ throw err;
1809
+ }
1810
+ var r1 = parseInt(salt.substring(offset, offset + 1), 10) * 10, r2 = parseInt(salt.substring(offset + 1, offset + 2), 10), rounds = r1 + r2, real_salt = salt.substring(offset + 3, offset + 25);
1811
+ s += minor >= "a" ? "\0" : "";
1812
+ var passwordb = stringToBytes(s), saltb = base64_decode(real_salt, BCRYPT_SALT_LEN);
1813
+ function finish(bytes) {
1814
+ var res = [];
1815
+ res.push("$2");
1816
+ if (minor >= "a")
1817
+ res.push(minor);
1818
+ res.push("$");
1819
+ if (rounds < 10)
1820
+ res.push("0");
1821
+ res.push(rounds.toString());
1822
+ res.push("$");
1823
+ res.push(base64_encode(saltb, saltb.length));
1824
+ res.push(base64_encode(bytes, C_ORIG.length * 4 - 1));
1825
+ return res.join("");
1826
+ }
1827
+ if (typeof callback == "undefined")
1828
+ return finish(_crypt(passwordb, saltb, rounds));
1829
+ else {
1830
+ _crypt(passwordb, saltb, rounds, function(err2, bytes) {
1831
+ if (err2)
1832
+ callback(err2, null);
1833
+ else
1834
+ callback(null, finish(bytes));
1835
+ }, progressCallback);
1836
+ }
1837
+ }
1838
+ bcrypt2.encodeBase64 = base64_encode;
1839
+ bcrypt2.decodeBase64 = base64_decode;
1840
+ return bcrypt2;
1841
+ });
1842
+ }
1843
+ });
1844
+
1845
+ // ../../node_modules/.pnpm/bcryptjs@2.4.3/node_modules/bcryptjs/index.js
1846
+ var require_bcryptjs = __commonJS({
1847
+ "../../node_modules/.pnpm/bcryptjs@2.4.3/node_modules/bcryptjs/index.js"(exports, module) {
1848
+ module.exports = require_bcrypt();
1849
+ }
1850
+ });
1851
+
1852
+ // src/index.ts
2
1853
  import { Command } from "commander";
3
- import { FloomError } from "@floom/shared";
4
- import { log } from "./lib/output.js";
5
- import { loginCommand } from "./commands/login.js";
6
- import { logoutCommand } from "./commands/logout.js";
7
- import { whoamiCommand } from "./commands/whoami.js";
8
- import { initCommand } from "./commands/init.js";
9
- import { validateCommand } from "./commands/validate.js";
10
- import { publishCommand } from "./commands/publish.js";
11
- import { installCommand } from "./commands/install.js";
12
- import { installedCommand } from "./commands/installed.js";
13
- import { outdatedCommand } from "./commands/outdated.js";
14
- import { updateCommand } from "./commands/update.js";
15
- import { listCommand } from "./commands/list.js";
16
- import { infoCommand } from "./commands/info.js";
17
- import { shareCommand, unshareCommand } from "./commands/share.js";
18
- import { libraryCreateCommand, libraryInviteCommand, libraryLeaveCommand, libraryListCommand } from "./commands/library.js";
19
- import { VERSION } from "./version.js";
20
- const program = new Command();
21
- program
22
- .name("floom")
23
- .description("Floom CLI — publish, install, sync, and share AI agent skills.")
24
- .version(VERSION);
25
- program.command("login").description("Log in via browser (device code).").action(loginCommand);
1854
+
1855
+ // ../shared/src/manifest.ts
1856
+ import { z } from "zod";
1857
+ var slugSchema = z.string().regex(
1858
+ /^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$/,
1859
+ "name must be lowercase letters/digits/hyphens, 3-64 chars, start+end alphanumeric"
1860
+ );
1861
+ var semverSchema = z.string().regex(
1862
+ /^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$/,
1863
+ "version must be semver (e.g. 0.1.0 or 1.0.0-beta.1)"
1864
+ );
1865
+ var skillTargetSchema = z.enum([
1866
+ "generic",
1867
+ "claude",
1868
+ "codex",
1869
+ "cursor",
1870
+ "gemini",
1871
+ "opencode",
1872
+ "kimi",
1873
+ "custom"
1874
+ ]);
1875
+ var authorSchema = z.object({
1876
+ name: z.string().min(1),
1877
+ email: z.string().email().optional()
1878
+ });
1879
+ var declaredScriptSchema = z.object({
1880
+ path: z.string(),
1881
+ description: z.string().max(280)
1882
+ });
1883
+ var manifestSchema = z.object({
1884
+ schema_version: z.literal("0.1"),
1885
+ name: slugSchema,
1886
+ title: z.string().min(1).max(120),
1887
+ description: z.string().min(1).max(500),
1888
+ version: semverSchema,
1889
+ entrypoint: z.string().default("SKILL.md"),
1890
+ targets: z.array(skillTargetSchema).default(["generic"]),
1891
+ tags: z.array(z.string().min(1).max(32)).max(10).optional(),
1892
+ authors: z.array(authorSchema).optional(),
1893
+ license: z.string().optional(),
1894
+ homepage: z.string().url().optional(),
1895
+ repository: z.string().url().optional(),
1896
+ source_url: z.string().url().optional(),
1897
+ declared_scripts: z.array(declaredScriptSchema).optional(),
1898
+ min_floom_version: semverSchema.optional()
1899
+ }).strict();
1900
+ function parseManifest(raw) {
1901
+ const result = manifestSchema.safeParse(raw);
1902
+ if (result.success) return { ok: true, manifest: result.data };
1903
+ const issue = result.error.issues[0];
1904
+ return {
1905
+ ok: false,
1906
+ error: `${issue.path.join(".") || "manifest"}: ${issue.message}`
1907
+ };
1908
+ }
1909
+ async function readManifest(skillDir) {
1910
+ const { readFile: readFile9 } = await import("node:fs/promises");
1911
+ const { join: join12 } = await import("node:path");
1912
+ try {
1913
+ const raw = await readFile9(join12(skillDir, "skill.json"), "utf8");
1914
+ let parsed;
1915
+ try {
1916
+ parsed = JSON.parse(raw);
1917
+ } catch (e) {
1918
+ return { ok: false, error: `skill.json is not valid JSON: ${e.message}` };
1919
+ }
1920
+ return parseManifest(parsed);
1921
+ } catch (e) {
1922
+ const err = e;
1923
+ if (err.code === "ENOENT") return { ok: false, error: "skill.json not found" };
1924
+ return { ok: false, error: `failed to read skill.json: ${err.message}` };
1925
+ }
1926
+ }
1927
+
1928
+ // ../shared/src/slug.ts
1929
+ var SLUG_RE = /^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$/;
1930
+ function isValidSlug(input) {
1931
+ return typeof input === "string" && SLUG_RE.test(input);
1932
+ }
1933
+ function slugErrorMessage(input) {
1934
+ if (typeof input !== "string") return "must be a string";
1935
+ if (input.length < 3) return "must be at least 3 characters";
1936
+ if (input.length > 64) return "must be at most 64 characters";
1937
+ if (!/^[a-z0-9]/.test(input)) return "must start with a lowercase letter or digit";
1938
+ if (!/[a-z0-9]$/.test(input)) return "must end with a lowercase letter or digit";
1939
+ if (!/^[a-z0-9-]+$/.test(input)) return "may only contain lowercase letters, digits, and hyphens";
1940
+ return null;
1941
+ }
1942
+ var REF_RE = /^@([a-z0-9][a-z0-9-]{1,30}[a-z0-9])\/([a-z0-9][a-z0-9-]{1,62}[a-z0-9])(?:@([^@/]+))?$/;
1943
+ var LIB_REF_RE = /^([a-z0-9][a-z0-9-]{1,62}[a-z0-9])\/([a-z0-9][a-z0-9-]{1,62}[a-z0-9])(?:@([^@/]+))?$/;
1944
+ function parseSkillRef(input) {
1945
+ const m = REF_RE.exec(input);
1946
+ if (m) {
1947
+ const [, owner2, slug2, version2] = m;
1948
+ return version2 ? { owner: owner2, slug: slug2, version: version2 } : { owner: owner2, slug: slug2 };
1949
+ }
1950
+ const m2 = LIB_REF_RE.exec(input);
1951
+ if (!m2) return null;
1952
+ const [, owner, slug, version] = m2;
1953
+ return version ? { owner, slug, version, isLibraryRef: true } : { owner, slug, isLibraryRef: true };
1954
+ }
1955
+ function formatSkillRef(ref) {
1956
+ return ref.version ? `@${ref.owner}/${ref.slug}@${ref.version}` : `@${ref.owner}/${ref.slug}`;
1957
+ }
1958
+
1959
+ // ../shared/src/errors.ts
1960
+ var FloomError = class extends Error {
1961
+ code;
1962
+ details;
1963
+ constructor(code, message, details) {
1964
+ super(message);
1965
+ this.name = "FloomError";
1966
+ this.code = code;
1967
+ this.details = details;
1968
+ }
1969
+ };
1970
+
1971
+ // ../shared/src/frontmatter.ts
1972
+ function parseSkillFrontmatter(input) {
1973
+ const trimmed = input.replace(/^\uFEFF/, "");
1974
+ if (!trimmed.startsWith("---")) {
1975
+ return { meta: { extras: {} }, body: input };
1976
+ }
1977
+ const afterOpen = trimmed.slice(3);
1978
+ const closeMatch = afterOpen.match(/\r?\n---\s*(?:\r?\n|$)/);
1979
+ if (!closeMatch || closeMatch.index === void 0) {
1980
+ return { meta: { extras: {} }, body: input };
1981
+ }
1982
+ const headerBlock = afterOpen.slice(0, closeMatch.index);
1983
+ const body = afterOpen.slice(closeMatch.index + closeMatch[0].length);
1984
+ const meta = { extras: {} };
1985
+ for (const rawLine of headerBlock.split(/\r?\n/)) {
1986
+ const line = rawLine.trim();
1987
+ if (!line || line.startsWith("#")) continue;
1988
+ const colon = line.indexOf(":");
1989
+ if (colon === -1) continue;
1990
+ const key = line.slice(0, colon).trim().toLowerCase();
1991
+ let value = line.slice(colon + 1).trim();
1992
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
1993
+ value = value.slice(1, -1);
1994
+ }
1995
+ if (key === "name") meta.name = value;
1996
+ else if (key === "description") meta.description = value;
1997
+ else meta.extras[key] = value;
1998
+ }
1999
+ return { meta, body };
2000
+ }
2001
+ function validateSkillFrontmatter(meta) {
2002
+ if (!meta.name) return "SKILL.md frontmatter missing required 'name' field";
2003
+ if (!meta.description) return "SKILL.md frontmatter missing required 'description' field";
2004
+ if (meta.description.length > 500) return "SKILL.md description must be at most 500 characters";
2005
+ return null;
2006
+ }
2007
+
2008
+ // ../shared/src/api-keys.ts
2009
+ var import_bcryptjs = __toESM(require_bcryptjs(), 1);
2010
+ import { randomBytes, scrypt as scryptCb, timingSafeEqual, createHash } from "node:crypto";
2011
+ import { promisify } from "node:util";
2012
+ var scrypt = promisify(scryptCb);
2013
+
2014
+ // ../shared/src/install-targets.ts
2015
+ import { homedir } from "node:os";
2016
+ import { join } from "node:path";
2017
+ var COMPATIBLE_AGENTS = {
2018
+ generic: ["Claude Code", "Codex CLI", "Cursor", "Gemini CLI", "OpenCode", "Kimi CLI"],
2019
+ all: ["Claude Code", "Codex CLI", "Cursor", "Gemini CLI", "OpenCode", "Kimi CLI"],
2020
+ claude: ["Claude Code", "OpenCode", "Kimi CLI"],
2021
+ codex: ["Codex CLI", "Gemini CLI (via interop alias)", "OpenCode", "Kimi CLI", "Cursor (auto-import)"],
2022
+ cursor: ["Cursor (auto-import)", "Codex CLI", "OpenCode", "Kimi CLI"],
2023
+ gemini: ["Gemini CLI"],
2024
+ opencode: ["OpenCode", "Claude Code", "Codex CLI", "Kimi CLI"],
2025
+ kimi: ["Kimi CLI", "Claude Code", "OpenCode"]
2026
+ };
2027
+ function presetDir(target, opts) {
2028
+ const cwd = opts.cwd ?? process.cwd();
2029
+ const root = opts.global ? homedir() : cwd;
2030
+ switch (target) {
2031
+ case "claude":
2032
+ return join(root, ".claude", "skills");
2033
+ case "gemini":
2034
+ return join(root, ".gemini", "skills");
2035
+ case "codex":
2036
+ case "cursor":
2037
+ case "generic":
2038
+ case "all":
2039
+ case "opencode":
2040
+ case "kimi":
2041
+ default:
2042
+ return join(root, ".agents", "skills");
2043
+ }
2044
+ }
2045
+ function resolveInstallDir(args) {
2046
+ if (args.to) {
2047
+ return {
2048
+ target: args.target ?? "generic",
2049
+ dir: args.to,
2050
+ origin: "explicit",
2051
+ compatibleAgents: COMPATIBLE_AGENTS[args.target ?? "generic"]
2052
+ };
2053
+ }
2054
+ if (process.env.FLOOM_SKILLS_DIR) {
2055
+ return {
2056
+ target: args.target ?? "generic",
2057
+ dir: process.env.FLOOM_SKILLS_DIR,
2058
+ origin: "env",
2059
+ compatibleAgents: COMPATIBLE_AGENTS[args.target ?? "generic"]
2060
+ };
2061
+ }
2062
+ const target = args.target ?? "generic";
2063
+ return {
2064
+ target,
2065
+ dir: presetDir(target, { global: args.global, cwd: args.cwd }),
2066
+ origin: "preset",
2067
+ compatibleAgents: COMPATIBLE_AGENTS[target]
2068
+ };
2069
+ }
2070
+
2071
+ // ../shared/src/security-scan.ts
2072
+ import { readFile } from "node:fs/promises";
2073
+ var PATTERNS = [
2074
+ { label: "OpenAI API key", category: "secret", regex: /\bsk-proj-[A-Za-z0-9_-]{20,}\b/g },
2075
+ { label: "OpenAI API key", category: "secret", regex: /\bsk-[A-Za-z0-9]{32,}\b/g },
2076
+ { label: "Anthropic API key", category: "secret", regex: /\bsk-ant-[A-Za-z0-9_-]{20,}\b/g },
2077
+ { label: "Google API key", category: "secret", regex: /\bAIza[0-9A-Za-z_-]{25,}\b/g },
2078
+ { label: "GitHub token", category: "secret", regex: /\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{30,}\b/g },
2079
+ { label: "GitHub token", category: "secret", regex: /\bgithub_pat_[A-Za-z0-9_]{40,}\b/g },
2080
+ { label: "Supabase access token", category: "secret", regex: /\bsbp_[A-Za-z0-9]{30,}\b/g },
2081
+ { label: "Stripe secret key", category: "secret", regex: /\bsk_(?:live|test)_[A-Za-z0-9]{20,}\b/g },
2082
+ { label: "Slack token", category: "secret", regex: /\bxox[baprs]-[A-Za-z0-9-]{20,}\b/g },
2083
+ { label: "AWS access key", category: "secret", regex: /\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g },
2084
+ { label: "Floom API token", category: "secret", regex: /\bflm_v1_[A-Za-z0-9_-]{14}_[A-Za-z0-9_-]{32}\b/g },
2085
+ { label: "Private key", category: "secret", regex: /-----BEGIN (?:RSA |EC |OPENSSH |)PRIVATE KEY-----/g },
2086
+ { label: "Prompt injection instruction", category: "prompt_injection", regex: /\bignore (?:all )?(?:previous|prior|above|earlier) instructions\b/gi },
2087
+ { label: "Prompt injection instruction", category: "prompt_injection", regex: /\bdisregard (?:all )?(?:previous|prior|above|earlier) instructions\b/gi },
2088
+ { label: "Prompt injection instruction", category: "prompt_injection", regex: /\bforget (?:all )?(?:previous|prior|above|earlier) instructions\b/gi },
2089
+ { label: "Prompt injection instruction", category: "prompt_injection", regex: /\boverride (?:the )?(?:system|developer|safety) instructions\b/gi },
2090
+ { label: "System prompt extraction", category: "prompt_injection", regex: /\b(?:reveal|print|show|dump|expose|leak) (?:the )?(?:system prompt|developer message|hidden instructions)\b/gi },
2091
+ { label: "Data exfiltration instruction", category: "data_exfiltration", regex: /\b(?:send|post|upload|exfiltrate|copy) (?:[^.\n]{0,80})\b(?:api keys?|tokens?|secrets?|environment variables|\.env|credentials)\b(?:[^.\n]{0,120})\b(?:to|into) https?:\/\//gi },
2092
+ { label: "Data exfiltration instruction", category: "data_exfiltration", regex: /\b(?:curl|wget|fetch)\b[^\n]{0,160}\b(?:api keys?|tokens?|secrets?|environment variables|\.env|credentials)\b/gi },
2093
+ { label: "Credential harvesting instruction", category: "data_exfiltration", regex: /\b(?:collect|harvest|steal|extract) (?:[^.\n]{0,80})\b(?:api keys?|tokens?|secrets?|environment variables|\.env|credentials)\b/gi },
2094
+ { label: "Possible personal email address", category: "personal_data", severity: "medium", regex: /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi },
2095
+ { label: "Possible phone number", category: "personal_data", severity: "medium", regex: /\b(?:\+?\d[\s().-]?){9,}\d\b/g },
2096
+ { label: "Dangerous shell command", category: "data_exfiltration", regex: /\bcurl\b[^\n|]{0,120}\|\s*(?:sh|bash)\b/gi },
2097
+ { label: "Dangerous shell command", category: "data_exfiltration", regex: /\brm\s+-rf\s+(?:\/|\$HOME|~)\b/g }
2098
+ ];
2099
+ var GENERIC_ASSIGNMENT_RE = /\b(?:api[_-]?key|secret|access[_-]?token|auth[_-]?token|bearer[_-]?token)\b\s*[:=]\s*["']?([A-Za-z0-9_./+=-]{24,})["']?/gi;
2100
+ var PROVIDER_LIKE_ASSIGNMENT_RE = /\b(?:api[_-]?key|secret|access[_-]?token|auth[_-]?token|bearer[_-]?token)\b\s*[:=]\s*["']?((?:sk|pk|rk)-[A-Za-z0-9_-]{8,}|sbp_[A-Za-z0-9]{12,}|xox[baprs]-[A-Za-z0-9-]{12,})["']?/gi;
2101
+ var PLACEHOLDER_RE = /(?:^|[_./+=-])(?:your|example|sample|placeholder|replace|changeme|todo|xxx|test|demo|dummy|fake|mock|staging|dev|local|redacted)(?:$|[_./+=-])/i;
2102
+ var EXAMPLE_EMAIL_RE = /@(example\.(?:com|org|net)|example|test|localhost)$/i;
2103
+ var TEXT_FILE_RE = /\.(?:md|mdx|txt|json|jsonc|ya?ml|toml|ini|env|example|ts|tsx|js|jsx|mjs|cjs|py|rb|go|rs|java|kt|sh|bash|zsh|fish|ps1|sql|html|css|csv)$/i;
2104
+ var FORBIDDEN_FILE_PATTERNS = [
2105
+ { label: "Environment file", severity: "high", regex: /(^|\/)\.env(?:$|\.local$|\.production$|\.development$)/ },
2106
+ { label: "Private key file", severity: "high", regex: /(^|\/)(?:id_rsa|id_ed25519|.*\.(?:pem|key|p12|pfx))$/i },
2107
+ { label: "npm credentials file", severity: "high", regex: /(^|\/)\.npmrc$/ },
2108
+ { label: "Credentials file", severity: "high", regex: /(^|\/)(?:credentials|service-account|service_account)\.json$/i },
2109
+ { label: "Example environment file", severity: "medium", regex: /(^|\/)\.env\.example$/ }
2110
+ ];
2111
+ function redact(value) {
2112
+ if (value.length <= 12) return "[redacted]";
2113
+ return `${value.slice(0, 4)}...${value.slice(-4)}`;
2114
+ }
2115
+ function lineNumberAt(input, index) {
2116
+ let line = 1;
2117
+ for (let i = 0; i < index; i++) {
2118
+ if (input.charCodeAt(i) === 10) line++;
2119
+ }
2120
+ return line;
2121
+ }
2122
+ function isProbablyText(buf, path) {
2123
+ if (TEXT_FILE_RE.test(path)) return true;
2124
+ if (buf.includes(0)) return false;
2125
+ const sample = buf.subarray(0, Math.min(buf.length, 4096));
2126
+ let suspicious = 0;
2127
+ for (const byte of sample) {
2128
+ if (byte < 9 || byte > 13 && byte < 32) suspicious++;
2129
+ }
2130
+ return sample.length === 0 || suspicious / sample.length < 0.02;
2131
+ }
2132
+ function scanSkillText(input, opts = {}) {
2133
+ const findings = [];
2134
+ const seen = /* @__PURE__ */ new Set();
2135
+ const push = (label, category, severity, index, value) => {
2136
+ const key = `${opts.path ?? ""}:${label}:${category}:${index}:${value}`;
2137
+ if (seen.has(key)) return;
2138
+ seen.add(key);
2139
+ findings.push({ label, category, path: opts.path, severity, line: lineNumberAt(input, index), preview: redact(value.replace(/\s+/g, " ").trim()) });
2140
+ };
2141
+ for (const pattern of PATTERNS) {
2142
+ pattern.regex.lastIndex = 0;
2143
+ for (const match of input.matchAll(pattern.regex)) {
2144
+ const value = match[0] ?? "";
2145
+ if (pattern.category === "personal_data" && EXAMPLE_EMAIL_RE.test(value)) continue;
2146
+ push(pattern.label, pattern.category, pattern.severity ?? "high", match.index ?? 0, value);
2147
+ }
2148
+ }
2149
+ GENERIC_ASSIGNMENT_RE.lastIndex = 0;
2150
+ for (const match of input.matchAll(GENERIC_ASSIGNMENT_RE)) {
2151
+ const value = match[1] ?? "";
2152
+ if (!value || PLACEHOLDER_RE.test(value)) continue;
2153
+ push("Possible secret assignment", "secret", "high", match.index ?? 0, value);
2154
+ }
2155
+ PROVIDER_LIKE_ASSIGNMENT_RE.lastIndex = 0;
2156
+ for (const match of input.matchAll(PROVIDER_LIKE_ASSIGNMENT_RE)) {
2157
+ const value = match[1] ?? "";
2158
+ if (!value) continue;
2159
+ push("Provider-like secret assignment", "secret", "high", match.index ?? 0, value);
2160
+ }
2161
+ return findings.sort((a, b) => (a.path ?? "").localeCompare(b.path ?? "") || a.line - b.line || a.label.localeCompare(b.label));
2162
+ }
2163
+ function scanSkillMarkdown(input) {
2164
+ return scanSkillText(input);
2165
+ }
2166
+ function isBlockingSecurityFinding(finding) {
2167
+ return finding.severity === "high" && (finding.category === "secret" || finding.category === "data_exfiltration" || finding.category === "unsafe_file");
2168
+ }
2169
+ async function scanSkillBundleEntries(entries) {
2170
+ const findings = [];
2171
+ for (const entry of entries) {
2172
+ for (const rule of FORBIDDEN_FILE_PATTERNS) {
2173
+ if (rule.regex.test(entry.relPath)) {
2174
+ findings.push({ label: rule.label, path: entry.relPath, line: 1, preview: entry.relPath, severity: rule.severity, category: "unsafe_file" });
2175
+ }
2176
+ }
2177
+ if (!isProbablyText(entry.data, entry.relPath)) continue;
2178
+ findings.push(...scanSkillText(entry.data.toString("utf8"), { path: entry.relPath }));
2179
+ }
2180
+ return findings.sort((a, b) => (a.path ?? "").localeCompare(b.path ?? "") || a.line - b.line || a.label.localeCompare(b.label));
2181
+ }
2182
+ async function scanSkillBundleFiles(files) {
2183
+ const entries = [];
2184
+ for (const file of files) {
2185
+ const buf = await readFile(file.absPath);
2186
+ entries.push({ relPath: file.relPath, data: buf });
2187
+ }
2188
+ return scanSkillBundleEntries(entries);
2189
+ }
2190
+
2191
+ // ../shared/src/skill-package.ts
2192
+ import { readFile as readFile2, readdir, stat, lstat, mkdir } from "node:fs/promises";
2193
+ import { join as join2, relative, sep, posix } from "node:path";
2194
+ import { createHash as createHash2 } from "node:crypto";
2195
+ var LIMITS = {
2196
+ maxBundleBytes: 10 * 1024 * 1024,
2197
+ // 10 MB compressed
2198
+ maxUncompressedBytes: 50 * 1024 * 1024,
2199
+ maxFiles: 100,
2200
+ maxFileBytes: 2 * 1024 * 1024,
2201
+ // 2 MB per file
2202
+ maxPathLength: 200
2203
+ };
2204
+ var DEFAULT_IGNORE = [
2205
+ ".git",
2206
+ "node_modules",
2207
+ "dist",
2208
+ "build",
2209
+ ".next",
2210
+ ".cache",
2211
+ ".DS_Store",
2212
+ ".env",
2213
+ ".env.local",
2214
+ ".env.development",
2215
+ ".env.production",
2216
+ "*.pem",
2217
+ "*.key",
2218
+ "*.p12",
2219
+ "*.sqlite",
2220
+ "*.db"
2221
+ ];
2222
+ function matchesGlob(name, pat) {
2223
+ if (pat.includes("*")) {
2224
+ const re = new RegExp("^" + pat.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*") + "$");
2225
+ return re.test(name);
2226
+ }
2227
+ return name === pat;
2228
+ }
2229
+ function isIgnored(relPath, patterns) {
2230
+ const parts = relPath.split(posix.sep);
2231
+ for (const pat of patterns) {
2232
+ const cleanPat = pat.replace(/^\/|\/$/g, "");
2233
+ if (parts.some((p) => matchesGlob(p, cleanPat))) return true;
2234
+ }
2235
+ return false;
2236
+ }
2237
+ async function loadFloomIgnore(dir) {
2238
+ try {
2239
+ const raw = await readFile2(join2(dir, ".floomignore"), "utf8");
2240
+ return raw.split(/\r?\n/).map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
2241
+ } catch {
2242
+ return [];
2243
+ }
2244
+ }
2245
+ async function walk(rootDir, ignore, acc, current) {
2246
+ const entries = await readdir(current, { withFileTypes: true });
2247
+ for (const entry of entries) {
2248
+ const abs = join2(current, entry.name);
2249
+ const rel = relative(rootDir, abs).split(sep).join(posix.sep);
2250
+ if (entry.isSymbolicLink()) {
2251
+ throw new Error(`Symlinks are not allowed: ${rel}`);
2252
+ }
2253
+ if (isIgnored(rel, ignore)) continue;
2254
+ if (entry.isDirectory()) {
2255
+ await walk(rootDir, ignore, acc, abs);
2256
+ continue;
2257
+ }
2258
+ if (!entry.isFile()) continue;
2259
+ const ls = await lstat(abs);
2260
+ if (ls.isSymbolicLink()) throw new Error(`Symlinks are not allowed: ${rel}`);
2261
+ if (rel.length > LIMITS.maxPathLength) {
2262
+ throw new Error(`Path too long (>${LIMITS.maxPathLength} chars): ${rel}`);
2263
+ }
2264
+ if (rel.includes("..")) {
2265
+ throw new Error(`Path traversal detected: ${rel}`);
2266
+ }
2267
+ const buf = await readFile2(abs);
2268
+ if (buf.length > LIMITS.maxFileBytes) {
2269
+ throw new Error(`File too large (${buf.length} > ${LIMITS.maxFileBytes}): ${rel}`);
2270
+ }
2271
+ const sha256 = createHash2("sha256").update(buf).digest("hex");
2272
+ acc.push({ relPath: rel, absPath: abs, size: buf.length, sha256 });
2273
+ }
2274
+ }
2275
+ async function collectBundle(rootDir) {
2276
+ const st = await stat(rootDir);
2277
+ if (!st.isDirectory()) throw new Error(`Not a directory: ${rootDir}`);
2278
+ const ignore = [...DEFAULT_IGNORE, ...await loadFloomIgnore(rootDir)];
2279
+ const files = [];
2280
+ await walk(rootDir, ignore, files, rootDir);
2281
+ files.sort((a, b) => a.relPath.localeCompare(b.relPath));
2282
+ if (files.length === 0) throw new Error("No files to bundle (after applying ignores)");
2283
+ if (files.length > LIMITS.maxFiles) {
2284
+ throw new Error(`Too many files (${files.length} > ${LIMITS.maxFiles})`);
2285
+ }
2286
+ const total = files.reduce((n, f) => n + f.size, 0);
2287
+ if (total > LIMITS.maxUncompressedBytes) {
2288
+ throw new Error(`Bundle too large uncompressed (${total} > ${LIMITS.maxUncompressedBytes})`);
2289
+ }
2290
+ const hasScripts = files.some((f) => f.relPath.startsWith("scripts/"));
2291
+ return { rootDir, files, totalUncompressedBytes: total, hasScripts };
2292
+ }
2293
+ async function packBundle(bundle) {
2294
+ const tar = await import("tar");
2295
+ const stream = tar.create(
2296
+ {
2297
+ gzip: { level: 9 },
2298
+ cwd: bundle.rootDir,
2299
+ portable: true,
2300
+ noMtime: true
2301
+ },
2302
+ bundle.files.map((f) => f.relPath)
2303
+ );
2304
+ const chunks = [];
2305
+ for await (const chunk of stream) {
2306
+ chunks.push(Buffer.from(chunk));
2307
+ }
2308
+ const buf = Buffer.concat(chunks);
2309
+ if (buf.length > LIMITS.maxBundleBytes) {
2310
+ throw new Error(`Compressed bundle too large (${buf.length} > ${LIMITS.maxBundleBytes})`);
2311
+ }
2312
+ return { bytes: buf, sha256: createHash2("sha256").update(buf).digest("hex") };
2313
+ }
2314
+ async function extractBundle(buf, destDir) {
2315
+ const tar = await import("tar");
2316
+ const { Readable } = await import("node:stream");
2317
+ await mkdir(destDir, { recursive: true });
2318
+ await new Promise((resolve3, reject) => {
2319
+ const extractStream = tar.extract({
2320
+ cwd: destDir,
2321
+ strict: true,
2322
+ preserveOwner: false,
2323
+ filter: (path) => {
2324
+ if (path.startsWith("/") || path.includes("..")) return false;
2325
+ if (path.length > LIMITS.maxPathLength) return false;
2326
+ return true;
2327
+ },
2328
+ onwarn: (_code, msg) => {
2329
+ if (msg.toLowerCase().includes("symlink")) reject(new Error("Bundle contains symlinks"));
2330
+ }
2331
+ });
2332
+ Readable.from(buf).pipe(extractStream).on("finish", () => resolve3()).on("error", reject);
2333
+ });
2334
+ }
2335
+ function verifyBundleHash(buf, expected) {
2336
+ const actual = createHash2("sha256").update(buf).digest("hex");
2337
+ return actual === expected;
2338
+ }
2339
+
2340
+ // src/lib/output.ts
2341
+ import chalk from "chalk";
2342
+ var log = {
2343
+ info: (msg) => console.log(msg),
2344
+ ok: (msg) => console.log(chalk.green("\u2713 ") + msg),
2345
+ warn: (msg) => console.log(chalk.yellow("! ") + msg),
2346
+ err: (msg) => console.error(chalk.red("\u2717 ") + msg),
2347
+ step: (msg) => console.log(chalk.dim("\xB7 ") + msg),
2348
+ heading: (msg) => console.log("\n" + chalk.bold(msg)),
2349
+ kv: (key, value) => console.log(` ${chalk.dim(key.padEnd(16))}${value}`),
2350
+ blank: () => console.log("")
2351
+ };
2352
+
2353
+ // src/commands/login.ts
2354
+ import { exec } from "node:child_process";
2355
+ import { promisify as promisify2 } from "node:util";
2356
+
2357
+ // src/config.ts
2358
+ import { homedir as homedir2 } from "node:os";
2359
+ import { join as join3 } from "node:path";
2360
+ import { mkdir as mkdir2, readFile as readFile3, writeFile, chmod } from "node:fs/promises";
2361
+ var CONFIG_DIR = join3(homedir2(), ".floom");
2362
+ var AUTH_FILE = join3(CONFIG_DIR, "auth.json");
2363
+ var DEFAULT_APP_URL = "https://floom.dev";
2364
+ var DEFAULT_API_URL = "https://floom-v0.vercel.app/api/v1";
2365
+ async function ensureDir() {
2366
+ await mkdir2(CONFIG_DIR, { recursive: true, mode: 448 });
2367
+ }
2368
+ async function readAuth() {
2369
+ try {
2370
+ const raw = await readFile3(AUTH_FILE, "utf8");
2371
+ return JSON.parse(raw);
2372
+ } catch (e) {
2373
+ if (e.code === "ENOENT") return null;
2374
+ throw e;
2375
+ }
2376
+ }
2377
+ async function writeAuth(state) {
2378
+ await ensureDir();
2379
+ await writeFile(AUTH_FILE, JSON.stringify(state, null, 2), { mode: 384 });
2380
+ try {
2381
+ await chmod(AUTH_FILE, 384);
2382
+ } catch {
2383
+ }
2384
+ }
2385
+ async function clearAuth() {
2386
+ const { unlink } = await import("node:fs/promises");
2387
+ try {
2388
+ await unlink(AUTH_FILE);
2389
+ } catch {
2390
+ }
2391
+ }
2392
+ function getApiUrl() {
2393
+ if (process.env.FLOOM_API_URL) return process.env.FLOOM_API_URL;
2394
+ if (process.env.FLOOM_APP_URL) return `${getAppUrl().replace(/\/$/, "")}/api/v1`;
2395
+ return DEFAULT_API_URL;
2396
+ }
2397
+ function getAppUrl() {
2398
+ return process.env.FLOOM_APP_URL ?? DEFAULT_APP_URL;
2399
+ }
2400
+ function getApiBaseUrls(preferred) {
2401
+ const explicitApiUrl = process.env.FLOOM_API_URL?.trim();
2402
+ if (explicitApiUrl) return [explicitApiUrl.replace(/\/$/, "")];
2403
+ const primary = (preferred ?? getApiUrl()).replace(/\/$/, "");
2404
+ const bases = [primary];
2405
+ if (preferred && !process.env.FLOOM_APP_URL) bases.push(DEFAULT_API_URL);
2406
+ return Array.from(new Set(bases));
2407
+ }
2408
+
2409
+ // src/version.ts
2410
+ var VERSION = "0.2.1";
2411
+
2412
+ // src/api-client.ts
2413
+ var DEFAULT_TIMEOUT_MS = 2e4;
2414
+ function timeoutMs() {
2415
+ const raw = Number(process.env.FLOOM_API_TIMEOUT_MS);
2416
+ return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_TIMEOUT_MS;
2417
+ }
2418
+ async function fetchWithTimeout(url, init = {}) {
2419
+ const controller = new AbortController();
2420
+ const timer = setTimeout(() => controller.abort(), timeoutMs());
2421
+ try {
2422
+ return await fetch(url, { ...init, signal: controller.signal });
2423
+ } catch (e) {
2424
+ if (e.name === "AbortError") {
2425
+ throw new Error(`Request timed out after ${timeoutMs()}ms`);
2426
+ }
2427
+ throw e;
2428
+ } finally {
2429
+ clearTimeout(timer);
2430
+ }
2431
+ }
2432
+ async function api(path, opts = {}) {
2433
+ const auth = await readAuth();
2434
+ if (opts.authRequired && !auth) {
2435
+ throw new FloomError("AUTH_REQUIRED", "Not logged in. Run: floom login");
2436
+ }
2437
+ let lastError = null;
2438
+ const bases = getApiBaseUrls(auth?.apiUrl);
2439
+ for (const base of bases) {
2440
+ const url = new URL(base + path);
2441
+ if (opts.query) {
2442
+ for (const [k, v] of Object.entries(opts.query)) {
2443
+ if (v !== void 0) url.searchParams.set(k, String(v));
2444
+ }
2445
+ }
2446
+ const headers = {
2447
+ "Content-Type": "application/json",
2448
+ "User-Agent": `floom-cli/${VERSION}`,
2449
+ "x-floom-cli-version": VERSION
2450
+ };
2451
+ if (auth) headers.Authorization = `Bearer ${auth.token}`;
2452
+ let res;
2453
+ try {
2454
+ res = await fetchWithTimeout(url.toString(), {
2455
+ method: opts.method ?? "GET",
2456
+ headers,
2457
+ body: opts.body !== void 0 ? JSON.stringify(opts.body) : void 0
2458
+ });
2459
+ } catch (e) {
2460
+ lastError = new FloomError(
2461
+ "INTERNAL_ERROR",
2462
+ `Unable to reach Floom API at ${base}: ${e.message}`,
2463
+ { apiUrl: base }
2464
+ );
2465
+ continue;
2466
+ }
2467
+ const text = await res.text();
2468
+ let json = null;
2469
+ try {
2470
+ json = text ? JSON.parse(text) : null;
2471
+ } catch {
2472
+ }
2473
+ if (res.ok) return json;
2474
+ const err = json?.error ?? {};
2475
+ lastError = new FloomError(
2476
+ err.code ?? "INTERNAL_ERROR",
2477
+ err.message ?? `HTTP ${res.status} ${res.statusText}`,
2478
+ { status: res.status, requestId: err.request_id, apiUrl: base }
2479
+ );
2480
+ if (res.status !== 404 || json?.error) break;
2481
+ }
2482
+ throw lastError ?? new FloomError("INTERNAL_ERROR", "API request failed");
2483
+ }
2484
+ async function rawPut(url, body, contentType = "application/octet-stream") {
2485
+ const u8 = body instanceof Buffer ? new Uint8Array(body) : body;
2486
+ let res;
2487
+ try {
2488
+ res = await fetchWithTimeout(url, {
2489
+ method: "PUT",
2490
+ headers: { "Content-Type": contentType },
2491
+ body: u8
2492
+ });
2493
+ } catch (e) {
2494
+ throw new FloomError("UPLOAD_FAILED", `Upload failed: ${e.message}`);
2495
+ }
2496
+ if (!res.ok) {
2497
+ throw new FloomError(
2498
+ "UPLOAD_FAILED",
2499
+ `Upload failed: HTTP ${res.status} ${res.statusText}`
2500
+ );
2501
+ }
2502
+ }
2503
+ async function rawGet(url) {
2504
+ let res;
2505
+ try {
2506
+ res = await fetchWithTimeout(url);
2507
+ } catch (e) {
2508
+ throw new FloomError("DOWNLOAD_FAILED", `Download failed: ${e.message}`);
2509
+ }
2510
+ if (!res.ok) {
2511
+ throw new FloomError(
2512
+ "DOWNLOAD_FAILED",
2513
+ `Download failed: HTTP ${res.status} ${res.statusText}`
2514
+ );
2515
+ }
2516
+ const ab = await res.arrayBuffer();
2517
+ return Buffer.from(ab);
2518
+ }
2519
+
2520
+ // src/commands/login.ts
2521
+ var sh = promisify2(exec);
2522
+ async function openInBrowser(url) {
2523
+ const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
2524
+ try {
2525
+ await sh(`${opener} ${JSON.stringify(url)}`);
2526
+ } catch {
2527
+ }
2528
+ }
2529
+ async function loginCommand() {
2530
+ log.heading("Starting CLI login...");
2531
+ const session = await api("/cli/sessions", {
2532
+ method: "POST",
2533
+ body: { client: "floom-cli", version: VERSION }
2534
+ });
2535
+ log.info("");
2536
+ log.info(`Open this URL in your browser:`);
2537
+ log.info(` ${session.verification_uri}`);
2538
+ log.info("");
2539
+ log.info(`Your code: ${session.user_code}`);
2540
+ log.info("");
2541
+ log.info("Waiting for approval in the browser. Press Ctrl+C to cancel.");
2542
+ openInBrowser(session.verification_uri).catch(() => {
2543
+ });
2544
+ const deadline = new Date(session.expires_at).getTime();
2545
+ const interval = Math.max(2, session.poll_interval_seconds) * 1e3;
2546
+ while (Date.now() < deadline) {
2547
+ await new Promise((r) => setTimeout(r, interval));
2548
+ const pollPath = `/cli/sessions/${session.session_id}?device_code=${encodeURIComponent(session.device_code)}`;
2549
+ const poll = await api(pollPath);
2550
+ if (poll.status === "approved" && poll.token && poll.handle && poll.email) {
2551
+ await writeAuth({
2552
+ token: poll.token,
2553
+ handle: poll.handle,
2554
+ email: poll.email,
2555
+ apiUrl: getApiUrl()
2556
+ });
2557
+ log.ok(`Logged in as @${poll.handle} (${poll.email})`);
2558
+ log.info("");
2559
+ log.info("Next:");
2560
+ log.info(" floom init");
2561
+ log.info(" floom publish");
2562
+ log.info(` floom install @${poll.handle}/your-skill --for codex`);
2563
+ return;
2564
+ }
2565
+ if (poll.status === "denied") {
2566
+ log.err("Login denied.");
2567
+ process.exit(1);
2568
+ }
2569
+ if (poll.status === "expired") {
2570
+ log.err("Login session expired. Run `floom login` again.");
2571
+ process.exit(1);
2572
+ }
2573
+ process.stdout.write(".");
2574
+ }
2575
+ log.err("Login timed out.");
2576
+ process.exit(1);
2577
+ }
2578
+
2579
+ // src/commands/logout.ts
2580
+ async function logoutCommand() {
2581
+ const auth = await readAuth();
2582
+ if (!auth) {
2583
+ log.info("Not logged in.");
2584
+ return;
2585
+ }
2586
+ try {
2587
+ await api("/cli/sessions/revoke", { method: "POST", authRequired: true });
2588
+ } catch {
2589
+ }
2590
+ await clearAuth();
2591
+ log.ok("Logged out.");
2592
+ }
2593
+
2594
+ // src/commands/whoami.ts
2595
+ async function whoamiCommand() {
2596
+ const auth = await readAuth();
2597
+ if (!auth) {
2598
+ log.info("Not logged in. Run: floom login");
2599
+ return;
2600
+ }
2601
+ log.heading("Logged in as:");
2602
+ log.kv("handle", `@${auth.handle}`);
2603
+ log.kv("email", auth.email);
2604
+ log.kv("api url", auth.apiUrl);
2605
+ }
2606
+
2607
+ // src/commands/init.ts
2608
+ import { writeFile as writeFile2, stat as stat2 } from "node:fs/promises";
2609
+ import { join as join4, basename } from "node:path";
2610
+ import prompts from "prompts";
2611
+ async function pathExists(p) {
2612
+ try {
2613
+ await stat2(p);
2614
+ return true;
2615
+ } catch {
2616
+ return false;
2617
+ }
2618
+ }
2619
+ async function initCommand() {
2620
+ const cwd = process.cwd();
2621
+ const folderName = basename(cwd);
2622
+ if (await pathExists(join4(cwd, "skill.json"))) {
2623
+ log.err("skill.json already exists in this folder. Edit it directly or run from a fresh directory.");
2624
+ process.exit(1);
2625
+ }
2626
+ const defaultName = folderName.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
2627
+ const answers = await prompts([
2628
+ {
2629
+ type: "text",
2630
+ name: "name",
2631
+ message: "Skill name (lowercase, hyphens):",
2632
+ initial: isValidSlug(defaultName) ? defaultName : "",
2633
+ validate: (v) => slugErrorMessage(v) ?? true
2634
+ },
2635
+ {
2636
+ type: "text",
2637
+ name: "title",
2638
+ message: "Title (human-readable):",
2639
+ initial: (prev) => prev.split("-").map((w) => w[0]?.toUpperCase() + w.slice(1)).join(" "),
2640
+ validate: (v) => v.trim().length > 0 ? true : "title required"
2641
+ },
2642
+ {
2643
+ type: "text",
2644
+ name: "description",
2645
+ message: "One-line description:",
2646
+ validate: (v) => v.trim().length > 0 ? true : "description required"
2647
+ },
2648
+ {
2649
+ type: "text",
2650
+ name: "version",
2651
+ message: "Version:",
2652
+ initial: "0.1.0"
2653
+ }
2654
+ ]);
2655
+ if (!answers.name) {
2656
+ log.err("Init cancelled.");
2657
+ process.exit(1);
2658
+ }
2659
+ const manifest = {
2660
+ schema_version: "0.1",
2661
+ name: answers.name,
2662
+ title: answers.title,
2663
+ description: answers.description,
2664
+ version: answers.version,
2665
+ entrypoint: "SKILL.md",
2666
+ targets: ["generic"]
2667
+ };
2668
+ const skillMd = `---
2669
+ name: ${answers.name}
2670
+ description: ${answers.description}
2671
+ ---
2672
+
2673
+ # ${answers.title}
2674
+
2675
+ ## Purpose
2676
+
2677
+ ${answers.description}
2678
+
2679
+ ## When to use
2680
+
2681
+ (Describe when this skill should be activated.)
2682
+
2683
+ ## Process
2684
+
2685
+ 1. (Step one)
2686
+ 2. (Step two)
2687
+
2688
+ ## Output
2689
+
2690
+ (Describe what the skill produces.)
2691
+ `;
2692
+ const floomIgnore = `# Floom CLI ignore patterns
2693
+ # One pattern per line, glob-style
2694
+ tmp/
2695
+ drafts/
2696
+ *.log
2697
+ `;
2698
+ await writeFile2(join4(cwd, "skill.json"), JSON.stringify(manifest, null, 2) + "\n", "utf8");
2699
+ await writeFile2(join4(cwd, "SKILL.md"), skillMd, "utf8");
2700
+ await writeFile2(join4(cwd, ".floomignore"), floomIgnore, "utf8");
2701
+ log.blank();
2702
+ log.ok("Skill scaffolded.");
2703
+ log.kv("skill.json", "manifest (edit metadata)");
2704
+ log.kv("SKILL.md", "instructions for the agent");
2705
+ log.kv(".floomignore", "patterns to exclude from publish");
2706
+ log.blank();
2707
+ log.info("Next:");
2708
+ log.info(" 1. Edit SKILL.md");
2709
+ log.info(" 2. floom validate");
2710
+ log.info(" 3. floom publish");
2711
+ }
2712
+
2713
+ // src/commands/validate.ts
2714
+ import { readFile as readFile5 } from "node:fs/promises";
2715
+ import { join as join5 } from "node:path";
2716
+ async function validateSkill(dir) {
2717
+ const report = {
2718
+ ok: true,
2719
+ manifest: { ok: true },
2720
+ skill_md: { ok: true },
2721
+ name_matches: { ok: false, message: "skipped because skill.json and SKILL.md are required" },
2722
+ bundle: { ok: false, message: "skipped because skill.json and SKILL.md are required" },
2723
+ security: { ok: false, message: "skipped because SKILL.md is required", findings: [] }
2724
+ };
2725
+ const m = await readManifest(dir);
2726
+ if (!m.ok) {
2727
+ report.manifest = { ok: false, message: m.error };
2728
+ report.ok = false;
2729
+ }
2730
+ let skillMd;
2731
+ try {
2732
+ skillMd = await readFile5(join5(dir, "SKILL.md"), "utf8");
2733
+ } catch {
2734
+ report.skill_md = { ok: false, message: "SKILL.md not found" };
2735
+ report.ok = false;
2736
+ }
2737
+ if (!skillMd) return report;
2738
+ const { meta } = parseSkillFrontmatter(skillMd);
2739
+ const fmErr = validateSkillFrontmatter(meta);
2740
+ if (fmErr) {
2741
+ report.skill_md = { ok: false, message: fmErr };
2742
+ report.ok = false;
2743
+ }
2744
+ if (m.ok) {
2745
+ report.name_matches = { ok: true };
2746
+ if (meta.name && meta.name !== m.manifest.name) {
2747
+ report.name_matches = {
2748
+ ok: false,
2749
+ message: `skill.json name="${m.manifest.name}" but SKILL.md frontmatter name="${meta.name}"`
2750
+ };
2751
+ report.ok = false;
2752
+ }
2753
+ }
2754
+ report.security = { ok: true, findings: [] };
2755
+ const findings = scanSkillMarkdown(skillMd);
2756
+ if (findings.length > 0) {
2757
+ const blocking = findings.filter(isBlockingSecurityFinding);
2758
+ report.security = { ok: blocking.length === 0, findings };
2759
+ if (blocking.length > 0) report.ok = false;
2760
+ }
2761
+ if (!m.ok) return report;
2762
+ try {
2763
+ const bundle = await collectBundle(dir);
2764
+ const bundleFindings = await scanSkillBundleFiles(bundle.files);
2765
+ const blocking = bundleFindings.filter(isBlockingSecurityFinding);
2766
+ report.security = { ok: blocking.length === 0, findings: bundleFindings };
2767
+ if (blocking.length > 0) report.ok = false;
2768
+ report.bundle = {
2769
+ ok: true,
2770
+ files: bundle.files.length,
2771
+ size: bundle.totalUncompressedBytes,
2772
+ has_scripts: bundle.hasScripts
2773
+ };
2774
+ } catch (e) {
2775
+ report.bundle = { ok: false, message: e.message };
2776
+ report.ok = false;
2777
+ }
2778
+ return report;
2779
+ }
2780
+ async function validateCommand(opts = {}) {
2781
+ const dir = process.cwd();
2782
+ const r = await validateSkill(dir);
2783
+ if (opts.json) {
2784
+ console.log(JSON.stringify(r, null, 2));
2785
+ process.exit(r.ok ? 0 : 1);
2786
+ }
2787
+ log.heading("Validating skill...");
2788
+ const line = (ok, label, detail) => ok ? log.ok(`${label.padEnd(28)} ${detail ?? ""}`.trim()) : log.err(`${label.padEnd(28)} ${detail ?? ""}`.trim());
2789
+ line(r.manifest.ok, "manifest schema", r.manifest.message);
2790
+ line(r.skill_md.ok, "SKILL.md present", r.skill_md.message);
2791
+ line(r.name_matches.ok, "name fields match", r.name_matches.message);
2792
+ if (r.bundle.ok) {
2793
+ line(true, "files + size limits", `${r.bundle.files} files, ${(r.bundle.size ?? 0) / 1024 | 0} KB`);
2794
+ } else {
2795
+ line(false, "files + size limits", r.bundle.message);
2796
+ }
2797
+ if (r.security.findings.length === 0) {
2798
+ line(r.security.ok, "bundle security scan", r.security.message ?? "clean");
2799
+ } else {
2800
+ const blocking = r.security.findings.filter(isBlockingSecurityFinding).length;
2801
+ const detail = blocking > 0 ? `${r.security.findings.length} finding(s), ${blocking} blocking` : `${r.security.findings.length} warning(s)`;
2802
+ line(r.security.ok, "bundle security scan", detail);
2803
+ for (const f of r.security.findings) {
2804
+ const loc = f.path ? `${f.path}:${f.line}` : `line ${f.line}`;
2805
+ log.warn(` ${loc} [${f.severity}/${f.category}] ${f.label}: ${f.preview}`);
2806
+ }
2807
+ }
2808
+ if (r.bundle.has_scripts) {
2809
+ log.warn("This skill contains scripts/. Agents may execute these \u2014 review before activating.");
2810
+ }
2811
+ log.blank();
2812
+ if (r.ok) {
2813
+ log.ok("Valid.");
2814
+ } else {
2815
+ log.err("Invalid.");
2816
+ process.exit(1);
2817
+ }
2818
+ }
2819
+
2820
+ // src/commands/publish.ts
2821
+ import { readFile as readFile6 } from "node:fs/promises";
2822
+ import { join as join6 } from "node:path";
2823
+ async function publishCommand(opts = {}) {
2824
+ const auth = await readAuth();
2825
+ if (!auth && !opts.dryRun) {
2826
+ log.err("Not logged in. Run: floom login");
2827
+ process.exit(1);
2828
+ }
2829
+ const dir = process.cwd();
2830
+ log.heading("Validating skill...");
2831
+ const report = await validateSkill(dir);
2832
+ if (!report.ok) {
2833
+ log.err("Validation failed. Run `floom validate` for details.");
2834
+ process.exit(1);
2835
+ }
2836
+ log.ok("Validation passed.");
2837
+ const m = await readManifest(dir);
2838
+ if (!m.ok) {
2839
+ log.err(m.error);
2840
+ process.exit(1);
2841
+ }
2842
+ const manifest = m.manifest;
2843
+ const skillMd = await readFile6(join6(dir, "SKILL.md"), "utf8");
2844
+ const { meta } = parseSkillFrontmatter(skillMd);
2845
+ const refRoot = opts.workspace ?? opts.library ?? auth?.handle ?? "<your-handle>";
2846
+ log.heading(`${opts.dryRun ? "Dry-running" : "Publishing"} ${refRoot}/${manifest.name}@${manifest.version}`);
2847
+ log.step("Packing bundle...");
2848
+ const bundle = await collectBundle(dir);
2849
+ const packed = await packBundle(bundle);
2850
+ log.kv("files", String(bundle.files.length));
2851
+ log.kv("size", `${packed.bytes.length} bytes (${(packed.bytes.length / 1024).toFixed(1)} KB)`);
2852
+ log.kv("sha256", packed.sha256);
2853
+ if (opts.dryRun) {
2854
+ log.blank();
2855
+ log.ok("Dry run passed. No upload was requested.");
2856
+ return;
2857
+ }
2858
+ const activeAuth = auth;
2859
+ if (!activeAuth) {
2860
+ log.err("Not logged in. Run: floom login");
2861
+ process.exit(1);
2862
+ }
2863
+ log.step("Requesting upload URL...");
2864
+ let initResp;
2865
+ try {
2866
+ initResp = await api(`/skills/${refRoot}/${manifest.name}/versions`, {
2867
+ method: "POST",
2868
+ authRequired: true,
2869
+ body: {
2870
+ manifest,
2871
+ skill_md: skillMd,
2872
+ bundle: {
2873
+ sha256: packed.sha256,
2874
+ size_bytes: packed.bytes.length
2875
+ },
2876
+ files: bundle.files.map((f) => ({
2877
+ path: f.relPath,
2878
+ sha256: f.sha256,
2879
+ size_bytes: f.size
2880
+ })),
2881
+ has_scripts: bundle.hasScripts
2882
+ }
2883
+ });
2884
+ } catch (e) {
2885
+ if (e instanceof FloomError && e.code === "VERSION_ALREADY_EXISTS") {
2886
+ log.err(`Version ${manifest.version} already exists for @${activeAuth.handle}/${manifest.name}.`);
2887
+ log.info("Bump the version in skill.json (e.g. 0.1.1) and try again.");
2888
+ process.exit(1);
2889
+ }
2890
+ throw e;
2891
+ }
2892
+ log.step("Uploading bundle...");
2893
+ await rawPut(initResp.upload.url, packed.bytes, "application/gzip");
2894
+ log.step("Finalizing...");
2895
+ const complete = await api(`/versions/${initResp.version_id}/complete`, {
2896
+ method: "POST",
2897
+ authRequired: true,
2898
+ body: { bundle_sha256: packed.sha256 }
2899
+ });
2900
+ log.blank();
2901
+ log.ok(`Published ${complete.ref}`);
2902
+ log.blank();
2903
+ log.info("View:");
2904
+ log.kv("", `${activeAuth.apiUrl.replace("/api/v1", "")}/@${activeAuth.handle}/${manifest.name}`);
2905
+ log.info("Install:");
2906
+ log.kv("", complete.install_command);
2907
+ }
2908
+
2909
+ // src/commands/install.ts
2910
+ import { mkdir as mkdir4, readdir as readdir3, rm, rename } from "node:fs/promises";
2911
+ import { join as join8 } from "node:path";
2912
+ import { tmpdir } from "node:os";
2913
+
2914
+ // src/lib/floom-lock.ts
2915
+ import { readFile as readFile7, writeFile as writeFile3, stat as stat3, readdir as readdir2 } from "node:fs/promises";
2916
+ import { join as join7, relative as relative2, sep as sep2, posix as posix2 } from "node:path";
2917
+ import { createHash as createHash3 } from "node:crypto";
2918
+ var EMPTY = { schema_version: "0.1", skills: {} };
2919
+ async function readLock(projectDir) {
2920
+ try {
2921
+ const raw = await readFile7(join7(projectDir, "floom.lock"), "utf8");
2922
+ const parsed = JSON.parse(raw);
2923
+ return parsed.schema_version === "0.1" ? parsed : { ...EMPTY };
2924
+ } catch (e) {
2925
+ if (e.code === "ENOENT") return { ...EMPTY };
2926
+ throw e;
2927
+ }
2928
+ }
2929
+ async function writeLock(projectDir, lock) {
2930
+ await writeFile3(join7(projectDir, "floom.lock"), JSON.stringify(lock, null, 2) + "\n", "utf8");
2931
+ }
2932
+ function setLockEntry(lock, ref, entry) {
2933
+ return { ...lock, skills: { ...lock.skills, [ref]: entry } };
2934
+ }
2935
+ async function hashInstalledFolder(folderAbs) {
2936
+ const out = [];
2937
+ async function walk2(dir) {
2938
+ let entries;
2939
+ try {
2940
+ entries = await readdir2(dir, { withFileTypes: true });
2941
+ } catch {
2942
+ return;
2943
+ }
2944
+ for (const entry of entries) {
2945
+ const abs = join7(dir, entry.name);
2946
+ if (entry.isSymbolicLink()) continue;
2947
+ if (entry.isDirectory()) {
2948
+ await walk2(abs);
2949
+ continue;
2950
+ }
2951
+ if (!entry.isFile()) continue;
2952
+ const buf = await readFile7(abs);
2953
+ const rel = relative2(folderAbs, abs).split(sep2).join(posix2.sep);
2954
+ out.push({
2955
+ relPath: rel,
2956
+ sha256: createHash3("sha256").update(buf).digest("hex"),
2957
+ size: buf.length
2958
+ });
2959
+ }
2960
+ }
2961
+ try {
2962
+ await stat3(folderAbs);
2963
+ } catch {
2964
+ return out;
2965
+ }
2966
+ await walk2(folderAbs);
2967
+ out.sort((a, b) => a.relPath.localeCompare(b.relPath));
2968
+ return out;
2969
+ }
2970
+
2971
+ // src/commands/install.ts
2972
+ var CLI_VERSION = VERSION;
2973
+ function semverGte(a, b) {
2974
+ const pa = a.split(".").map(Number);
2975
+ const pb = b.split(".").map(Number);
2976
+ for (let i = 0; i < 3; i++) {
2977
+ if ((pa[i] ?? 0) > (pb[i] ?? 0)) return true;
2978
+ if ((pa[i] ?? 0) < (pb[i] ?? 0)) return false;
2979
+ }
2980
+ return true;
2981
+ }
2982
+ async function installCommand(refStr, opts = {}) {
2983
+ const ref = parseSkillRef(refStr);
2984
+ if (!ref) {
2985
+ log.err(`Invalid skill ref: ${refStr}`);
2986
+ log.info("Expected: @owner/slug, workspace-slug/slug, or with @version suffix");
2987
+ process.exit(1);
2988
+ }
2989
+ let info;
2990
+ try {
2991
+ info = await api(`/skills/${ref.owner}/${ref.slug}`);
2992
+ } catch (e) {
2993
+ if (e instanceof FloomError && e.code === "SKILL_ACCESS_DENIED") {
2994
+ const auth = await readAuth();
2995
+ if (!auth) {
2996
+ log.err(`Cannot access ${formatSkillRef(ref)}.`);
2997
+ log.info("Run `floom login` to install private or unlisted skills.");
2998
+ process.exit(1);
2999
+ }
3000
+ log.err(`You do not have access to ${formatSkillRef(ref)}.`);
3001
+ log.info(`Ask the owner to share it with: ${auth.email}`);
3002
+ process.exit(1);
3003
+ }
3004
+ throw e;
3005
+ }
3006
+ if (info.min_floom_version && !semverGte(CLI_VERSION, info.min_floom_version)) {
3007
+ log.err(`This skill requires Floom CLI >= ${info.min_floom_version} (you have ${CLI_VERSION}).`);
3008
+ log.info("Upgrade:");
3009
+ log.info(" npm install -g @floomhq/skills@latest");
3010
+ process.exit(1);
3011
+ }
3012
+ const target = resolveInstallDir({
3013
+ target: opts.for ?? "generic",
3014
+ to: opts.to,
3015
+ global: opts.global
3016
+ });
3017
+ const projectDir = opts.global ? process.cwd() : process.cwd();
3018
+ const destFolder = join8(target.dir, ref.slug);
3019
+ const lock = await readLock(projectDir);
3020
+ const refKey = formatSkillRef({ owner: ref.owner, slug: ref.slug });
3021
+ const existing = lock.skills[refKey];
3022
+ let folderExists = false;
3023
+ try {
3024
+ const entries = await readdir3(destFolder);
3025
+ folderExists = entries.length > 0;
3026
+ } catch {
3027
+ }
3028
+ if (folderExists) {
3029
+ if (existing && existing.path === destFolder.replace(projectDir + "/", "")) {
3030
+ const current = await hashInstalledFolder(destFolder);
3031
+ if (!opts.force) {
3032
+ log.warn(`Folder already exists at ${destFolder} and may contain local edits.`);
3033
+ log.info(`Re-run with --force to overwrite, or remove the folder manually.`);
3034
+ process.exit(1);
3035
+ }
3036
+ } else if (!opts.force) {
3037
+ log.err(`Folder already exists at ${destFolder} (not tracked by floom.lock).`);
3038
+ log.info("Re-run with --force to overwrite, or remove the folder manually.");
3039
+ process.exit(1);
3040
+ }
3041
+ }
3042
+ log.step("Fetching skill metadata...");
3043
+ const dl = await api(`/skills/${ref.owner}/${ref.slug}/download`, {
3044
+ query: { version: ref.version }
3045
+ });
3046
+ log.step("Downloading bundle...");
3047
+ const buf = await rawGet(dl.download.url);
3048
+ if (!verifyBundleHash(buf, dl.bundle_sha256)) {
3049
+ log.err("Bundle hash mismatch \u2014 refusing to extract.");
3050
+ process.exit(1);
3051
+ }
3052
+ log.ok(`Bundle verified (${(buf.length / 1024).toFixed(1)} KB).`);
3053
+ const tmp = await import("node:fs/promises").then(
3054
+ (m) => m.mkdtemp(join8(tmpdir(), `floom-install-${ref.slug}-`))
3055
+ );
3056
+ try {
3057
+ await extractBundle(buf, tmp);
3058
+ await mkdir4(target.dir, { recursive: true });
3059
+ if (folderExists) {
3060
+ await rm(destFolder, { recursive: true, force: true });
3061
+ }
3062
+ await rename(tmp, destFolder);
3063
+ } catch (e) {
3064
+ await rm(tmp, { recursive: true, force: true }).catch(() => {
3065
+ });
3066
+ throw e;
3067
+ }
3068
+ const next = setLockEntry(lock, refKey, {
3069
+ version: dl.version,
3070
+ resolved: `${getAppUrl().replace(/\/$/, "")}/${refKey}`,
3071
+ bundle_sha256: dl.bundle_sha256,
3072
+ installed_at: (/* @__PURE__ */ new Date()).toISOString(),
3073
+ path: destFolder.replace(projectDir + "/", ""),
3074
+ preset: opts.for
3075
+ });
3076
+ await writeLock(projectDir, next);
3077
+ log.blank();
3078
+ log.ok(`Installed ${refKey}@${dl.version}`);
3079
+ log.kv("Path", destFolder);
3080
+ log.kv("Target", target.target);
3081
+ log.kv("Compatible with", target.compatibleAgents.join(", "));
3082
+ if (dl.has_scripts) {
3083
+ log.blank();
3084
+ log.warn("This skill contains executable scripts. Floom does not run them; your agent may.");
3085
+ log.warn("Review the scripts/ folder before activating.");
3086
+ }
3087
+ }
3088
+
3089
+ // src/commands/installed.ts
3090
+ async function installedCommand(opts = {}) {
3091
+ const lock = await readLock(process.cwd());
3092
+ const entries = Object.entries(lock.skills);
3093
+ if (opts.json) {
3094
+ console.log(JSON.stringify(lock, null, 2));
3095
+ return;
3096
+ }
3097
+ if (entries.length === 0) {
3098
+ log.info("No skills installed in this project.");
3099
+ log.info("Get one: floom install @owner/slug");
3100
+ return;
3101
+ }
3102
+ log.heading("Installed skills in this project");
3103
+ for (const [ref, e] of entries) {
3104
+ console.log(` ${ref.padEnd(40)} ${e.version.padEnd(8)} ${(e.preset ?? "-").padEnd(8)} ${e.path}`);
3105
+ }
3106
+ log.blank();
3107
+ log.info(`${entries.length} skill${entries.length === 1 ? "" : "s"} installed.`);
3108
+ }
3109
+
3110
+ // src/commands/outdated.ts
3111
+ function cmpSemver(a, b) {
3112
+ const pa = a.split(".").map((p) => parseInt(p, 10));
3113
+ const pb = b.split(".").map((p) => parseInt(p, 10));
3114
+ for (let i = 0; i < 3; i++) {
3115
+ const d = (pa[i] ?? 0) - (pb[i] ?? 0);
3116
+ if (d !== 0) return d;
3117
+ }
3118
+ return 0;
3119
+ }
3120
+ async function outdatedCommand() {
3121
+ const lock = await readLock(process.cwd());
3122
+ const entries = Object.entries(lock.skills);
3123
+ if (entries.length === 0) {
3124
+ log.info("No skills installed.");
3125
+ return;
3126
+ }
3127
+ log.heading("Checking for updates...");
3128
+ const outdated = [];
3129
+ for (const [ref, e] of entries) {
3130
+ const [, owner, slug] = /^@([^/]+)\/([^@]+)/.exec(ref) ?? [];
3131
+ if (!owner || !slug) continue;
3132
+ try {
3133
+ const info = await api(`/skills/${owner}/${slug}`);
3134
+ if (cmpSemver(info.latest_version, e.version) > 0) {
3135
+ outdated.push({ ref, current: e.version, latest: info.latest_version });
3136
+ }
3137
+ } catch (err) {
3138
+ log.warn(`Could not check ${ref}: ${err.message}`);
3139
+ }
3140
+ }
3141
+ log.blank();
3142
+ if (outdated.length === 0) {
3143
+ log.ok("All installed skills are up to date.");
3144
+ return;
3145
+ }
3146
+ log.heading("Outdated skills");
3147
+ for (const o of outdated) {
3148
+ console.log(` ${o.ref.padEnd(40)} ${o.current.padEnd(10)} -> ${o.latest.padEnd(10)} floom update ${o.ref}`);
3149
+ }
3150
+ log.blank();
3151
+ log.info(`${outdated.length} skill${outdated.length === 1 ? "" : "s"} can be updated.`);
3152
+ process.exit(1);
3153
+ }
3154
+
3155
+ // src/commands/update.ts
3156
+ import { rm as rm2, rename as rename2, mkdir as mkdir5 } from "node:fs/promises";
3157
+ import { tmpdir as tmpdir2 } from "node:os";
3158
+ import { join as join9, resolve as resolve2 } from "node:path";
3159
+ function cmpSemver2(a, b) {
3160
+ const pa = a.split(".").map((p) => parseInt(p, 10));
3161
+ const pb = b.split(".").map((p) => parseInt(p, 10));
3162
+ for (let i = 0; i < 3; i++) {
3163
+ const d = (pa[i] ?? 0) - (pb[i] ?? 0);
3164
+ if (d !== 0) return d;
3165
+ }
3166
+ return 0;
3167
+ }
3168
+ async function updateCommand(refStr, opts = {}) {
3169
+ const projectDir = process.cwd();
3170
+ const lock = await readLock(projectDir);
3171
+ const all = Object.entries(lock.skills);
3172
+ if (all.length === 0) {
3173
+ log.info("No installed skills.");
3174
+ return;
3175
+ }
3176
+ const targets = refStr ? all.filter(([r]) => r === refStr) : all;
3177
+ if (refStr && targets.length === 0) {
3178
+ log.err(`Not installed: ${refStr}`);
3179
+ process.exit(1);
3180
+ }
3181
+ let updated = 0, skipped = 0;
3182
+ for (const [ref, entry] of targets) {
3183
+ const [, owner, slug] = /^@([^/]+)\/([^@]+)/.exec(ref) ?? [];
3184
+ if (!owner || !slug) continue;
3185
+ let info;
3186
+ try {
3187
+ info = await api(`/skills/${owner}/${slug}`);
3188
+ } catch (e) {
3189
+ log.warn(`Skip ${ref}: ${e.message}`);
3190
+ skipped++;
3191
+ continue;
3192
+ }
3193
+ if (cmpSemver2(info.latest_version, entry.version) <= 0) {
3194
+ log.step(`${ref} is already at latest (${entry.version}).`);
3195
+ continue;
3196
+ }
3197
+ const installDir = resolve2(projectDir, entry.path);
3198
+ if (!opts.force) {
3199
+ const current = await hashInstalledFolder(installDir);
3200
+ log.step(`Updating ${ref}: ${entry.version} -> ${info.latest_version}`);
3201
+ }
3202
+ const dl = await api(`/skills/${owner}/${slug}/download`);
3203
+ const buf = await rawGet(dl.download.url);
3204
+ if (!verifyBundleHash(buf, dl.bundle_sha256)) {
3205
+ log.err(`Bundle hash mismatch for ${ref} \u2014 skipping.`);
3206
+ skipped++;
3207
+ continue;
3208
+ }
3209
+ const tmp = await import("node:fs/promises").then(
3210
+ (m) => m.mkdtemp(join9(tmpdir2(), `floom-update-${slug}-`))
3211
+ );
3212
+ try {
3213
+ await extractBundle(buf, tmp);
3214
+ await rm2(installDir, { recursive: true, force: true });
3215
+ await mkdir5(installDir.replace(/\/[^/]+$/, ""), { recursive: true });
3216
+ await rename2(tmp, installDir);
3217
+ } catch (e) {
3218
+ await rm2(tmp, { recursive: true, force: true }).catch(() => {
3219
+ });
3220
+ throw e;
3221
+ }
3222
+ const next = setLockEntry(lock, ref, {
3223
+ ...entry,
3224
+ version: dl.version,
3225
+ bundle_sha256: dl.bundle_sha256,
3226
+ installed_at: (/* @__PURE__ */ new Date()).toISOString()
3227
+ });
3228
+ await writeLock(projectDir, next);
3229
+ log.ok(`Updated ${ref}: ${entry.version} -> ${dl.version}`);
3230
+ updated++;
3231
+ }
3232
+ log.blank();
3233
+ log.info(`${updated} updated, ${skipped} skipped.`);
3234
+ }
3235
+
3236
+ // src/commands/list.ts
3237
+ async function listCommand(opts = {}) {
3238
+ const resp = await api("/skills", {
3239
+ authRequired: true,
3240
+ query: { q: opts.query, library: opts.workspace ?? opts.library, folder: opts.folder }
3241
+ });
3242
+ if (resp.skills.length === 0) {
3243
+ log.info("No skills.");
3244
+ return;
3245
+ }
3246
+ if (opts.flat) {
3247
+ for (const s of resp.skills) {
3248
+ console.log(`${s.library.slug}/${s.slug}`);
3249
+ }
3250
+ return;
3251
+ }
3252
+ const groups = /* @__PURE__ */ new Map();
3253
+ for (const skill of resp.skills) {
3254
+ const k = `${skill.library.slug} (${skill.library.name})`;
3255
+ const arr = groups.get(k) ?? [];
3256
+ arr.push(skill);
3257
+ groups.set(k, arr);
3258
+ }
3259
+ for (const [library, rows] of groups.entries()) {
3260
+ log.heading(library);
3261
+ for (const s of rows) {
3262
+ console.log(` ${`${s.library.slug}/${s.slug}`.padEnd(40)} ${s.visibility.padEnd(10)} ${s.title}`);
3263
+ }
3264
+ }
3265
+ }
3266
+
3267
+ // src/commands/info.ts
3268
+ async function infoCommand(refStr) {
3269
+ const ref = parseSkillRef(refStr);
3270
+ if (!ref) {
3271
+ log.err(`Invalid skill ref: ${refStr}`);
3272
+ process.exit(1);
3273
+ }
3274
+ const r = await api(`/skills/${ref.owner}/${ref.slug}`);
3275
+ log.heading(r.ref);
3276
+ log.kv("Title", r.title);
3277
+ log.kv("Description", r.description);
3278
+ log.kv("Latest", r.latest_version);
3279
+ log.kv("Visibility", r.visibility);
3280
+ log.kv("Owner", `@${r.owner.handle}${r.owner.display_name ? ` (${r.owner.display_name})` : ""}`);
3281
+ if (r.has_scripts) {
3282
+ log.kv("Scripts", "yes (review before activating)");
3283
+ }
3284
+ log.blank();
3285
+ log.info("Install:");
3286
+ log.info(` floom install ${r.ref}`);
3287
+ }
3288
+
3289
+ // src/commands/share.ts
3290
+ async function shareCommand(refStr, email, opts = {}) {
3291
+ const ref = parseSkillRef(refStr);
3292
+ if (!ref) {
3293
+ log.err(`Invalid skill ref: ${refStr}`);
3294
+ process.exit(1);
3295
+ }
3296
+ const role = opts.role ?? "viewer";
3297
+ const r = await api(`/skills/${ref.owner}/${ref.slug}/grants`, {
3298
+ method: "POST",
3299
+ authRequired: true,
3300
+ body: { email, role }
3301
+ });
3302
+ log.ok(`Shared ${refStr} with ${r.grant.email} as ${r.grant.role}.`);
3303
+ log.info("No email is sent in V0. They will see the skill under 'Shared with Me' on next login.");
3304
+ }
3305
+ async function unshareCommand(refStr, email) {
3306
+ const ref = parseSkillRef(refStr);
3307
+ if (!ref) {
3308
+ log.err(`Invalid skill ref: ${refStr}`);
3309
+ process.exit(1);
3310
+ }
3311
+ const list = await api(`/skills/${ref.owner}/${ref.slug}/grants`, { authRequired: true });
3312
+ const grant = list.grants.find((g) => (g.email ?? "").toLowerCase() === email.toLowerCase());
3313
+ if (!grant) {
3314
+ log.err(`No active grant for ${email} on ${refStr}.`);
3315
+ process.exit(1);
3316
+ }
3317
+ await api(`/skills/${ref.owner}/${ref.slug}/grants/${grant.id}`, { method: "DELETE", authRequired: true });
3318
+ log.ok(`Removed ${email}'s access to ${refStr}.`);
3319
+ }
3320
+
3321
+ // src/commands/library.ts
3322
+ async function libraryListCommand() {
3323
+ const resp = await api("/libraries", { authRequired: true });
3324
+ if (!resp.libraries.length) {
3325
+ log.info("No workspaces.");
3326
+ return;
3327
+ }
3328
+ for (const l of resp.libraries) {
3329
+ console.log(`${l.slug.padEnd(24)} ${l.type.padEnd(8)} ${l.role.padEnd(6)} ${l.name}`);
3330
+ }
3331
+ }
3332
+ async function libraryCreateCommand(slug, name) {
3333
+ const resp = await api("/libraries", { method: "POST", authRequired: true, body: { slug, name } });
3334
+ log.ok(`Created workspace ${resp.slug}`);
3335
+ }
3336
+ async function libraryInviteCommand(librarySlug, email, role = "viewer") {
3337
+ await api(`/libraries/${librarySlug}/pending-invites`, {
3338
+ method: "POST",
3339
+ authRequired: true,
3340
+ body: { email, role }
3341
+ });
3342
+ log.ok(`Invited ${email} to ${librarySlug} as ${role}`);
3343
+ }
3344
+ async function libraryLeaveCommand(librarySlug) {
3345
+ await api(`/libraries/${librarySlug}/members/me`, { method: "DELETE", authRequired: true });
3346
+ log.ok(`Left workspace ${librarySlug}`);
3347
+ }
3348
+
3349
+ // src/commands/mcp.ts
3350
+ import { mkdtemp, mkdir as mkdir6, readdir as readdir4, readFile as readFile8, rename as rename3, rm as rm3, writeFile as writeFile4 } from "node:fs/promises";
3351
+ import { join as join10 } from "node:path";
3352
+ import { homedir as homedir3, tmpdir as tmpdir3 } from "node:os";
3353
+ import { z as z2 } from "zod";
3354
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3355
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3356
+ var API_TIMEOUT_MS = 2e4;
3357
+ async function fetchWithTimeout2(url, init = {}) {
3358
+ const controller = new AbortController();
3359
+ const timer = setTimeout(() => controller.abort(), API_TIMEOUT_MS);
3360
+ try {
3361
+ return await fetch(url, { ...init, signal: controller.signal });
3362
+ } catch (e) {
3363
+ if (e.name === "AbortError") throw new Error(`Request timed out after ${API_TIMEOUT_MS}ms`);
3364
+ throw e;
3365
+ } finally {
3366
+ clearTimeout(timer);
3367
+ }
3368
+ }
3369
+ async function resolveToken() {
3370
+ const fromEnv = process.env.FLOOM_API_TOKEN?.trim();
3371
+ if (fromEnv) return fromEnv;
3372
+ const auth = await readAuth();
3373
+ if (auth?.token) return auth.token;
3374
+ const authPath = join10(homedir3(), ".floom", "auth.json");
3375
+ const raw = await readFile8(authPath, "utf8");
3376
+ const parsed = JSON.parse(raw);
3377
+ if (!parsed.token) throw new Error("Missing token in ~/.floom/auth.json");
3378
+ return parsed.token;
3379
+ }
3380
+ async function apiWithToken(token, path, query) {
3381
+ const auth = await readAuth();
3382
+ let lastError = null;
3383
+ for (const base of getApiBaseUrls(auth?.apiUrl)) {
3384
+ const url = new URL(base + path);
3385
+ if (query) {
3386
+ for (const [k, v] of Object.entries(query)) url.searchParams.set(k, v);
3387
+ }
3388
+ let res;
3389
+ try {
3390
+ res = await fetchWithTimeout2(url, {
3391
+ headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" }
3392
+ });
3393
+ } catch (e) {
3394
+ lastError = new Error(`Unable to reach Floom API at ${base}: ${e.message}`);
3395
+ continue;
3396
+ }
3397
+ const body = await res.text();
3398
+ let json = null;
3399
+ try {
3400
+ json = body ? JSON.parse(body) : null;
3401
+ } catch {
3402
+ json = { raw: body };
3403
+ }
3404
+ if (res.ok) return json;
3405
+ lastError = new Error(json?.error?.message ?? `HTTP ${res.status}`);
3406
+ if (res.status !== 404 || json?.error) break;
3407
+ }
3408
+ throw lastError ?? new Error("API request failed");
3409
+ }
3410
+ async function installViaApi(token, refText, target) {
3411
+ const parsed = parseSkillRef(refText);
3412
+ if (!parsed) throw new Error(`Invalid ref: ${refText}`);
3413
+ const info = await apiWithToken(token, `/skills/${parsed.owner}/${parsed.slug}`);
3414
+ const dl = await apiWithToken(token, `/skills/${parsed.owner}/${parsed.slug}/download`, parsed.version ? { version: parsed.version } : void 0);
3415
+ const bundle = await rawGet(dl.download.url);
3416
+ if (!verifyBundleHash(bundle, dl.bundle_sha256)) throw new Error("Bundle hash mismatch");
3417
+ const install = resolveInstallDir({ target });
3418
+ await mkdir6(install.dir, { recursive: true });
3419
+ const dest = join10(install.dir, parsed.slug);
3420
+ const exists = await readdir4(dest).then(() => true).catch(() => false);
3421
+ if (exists) await rm3(dest, { recursive: true, force: true });
3422
+ const temp = await mkdtemp(join10(tmpdir3(), `floom-mcp-${parsed.slug}-`));
3423
+ try {
3424
+ await extractBundle(bundle, temp);
3425
+ await rename3(temp, dest);
3426
+ } catch (e) {
3427
+ await rm3(temp, { recursive: true, force: true }).catch(() => {
3428
+ });
3429
+ throw e;
3430
+ }
3431
+ const lock = await readLock(process.cwd());
3432
+ const ref = formatSkillRef({ owner: parsed.owner, slug: parsed.slug });
3433
+ const next = setLockEntry(lock, ref, {
3434
+ version: dl.version,
3435
+ resolved: `${getAppUrl().replace(/\/$/, "")}/${ref}`,
3436
+ bundle_sha256: dl.bundle_sha256,
3437
+ installed_at: (/* @__PURE__ */ new Date()).toISOString(),
3438
+ path: dest.replace(process.cwd() + "/", ""),
3439
+ preset: target
3440
+ });
3441
+ await writeLock(process.cwd(), next);
3442
+ return { path: dest, version: dl.version, ref: info.ref ?? ref };
3443
+ }
3444
+ async function parseSkillBundle(bundle) {
3445
+ const tmp = await mkdtemp(join10(tmpdir3(), "floom-mcp-read-"));
3446
+ try {
3447
+ await extractBundle(bundle, tmp);
3448
+ const files = [];
3449
+ const walk2 = async (dir, rel = "") => {
3450
+ const entries = await readdir4(dir, { withFileTypes: true });
3451
+ for (const entry of entries) {
3452
+ const nextRel = rel ? `${rel}/${entry.name}` : entry.name;
3453
+ const full = join10(dir, entry.name);
3454
+ if (entry.isDirectory()) await walk2(full, nextRel);
3455
+ else files.push(nextRel);
3456
+ }
3457
+ };
3458
+ await walk2(tmp);
3459
+ const skillMdPath = files.find((f) => f.toUpperCase() === "SKILL.MD");
3460
+ const skillMd = skillMdPath ? await readFile8(join10(tmp, skillMdPath), "utf8") : "";
3461
+ const skillJsonPath = files.find((f) => f.toLowerCase() === "skill.json");
3462
+ const skillJson = skillJsonPath ? JSON.parse(await readFile8(join10(tmp, skillJsonPath), "utf8")) : null;
3463
+ return { files, skill_md: skillMd, skill_json: skillJson };
3464
+ } finally {
3465
+ await rm3(tmp, { recursive: true, force: true });
3466
+ }
3467
+ }
3468
+ async function mcpCommand() {
3469
+ const token = await resolveToken();
3470
+ const server = new McpServer({ name: "floom", version: VERSION });
3471
+ server.tool("search_skills", { query: z2.string().min(1), workspace: z2.string().optional(), library: z2.string().optional() }, async ({ query, workspace, library }) => {
3472
+ const workspaceSlug = workspace ?? library;
3473
+ const result = await apiWithToken(token, "/skills", { q: query, ...workspaceSlug ? { library: workspaceSlug } : {} });
3474
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
3475
+ });
3476
+ server.tool("get_skill", { ref: z2.string().min(3) }, async ({ ref }) => {
3477
+ const parsed = parseSkillRef(ref);
3478
+ if (!parsed) throw new Error("Invalid ref. Expected @owner/slug or workspace/slug");
3479
+ const meta = await apiWithToken(token, `/skills/${parsed.owner}/${parsed.slug}`);
3480
+ const dl = await apiWithToken(token, `/skills/${parsed.owner}/${parsed.slug}/download`);
3481
+ const buf = await rawGet(dl.download.url);
3482
+ const parsedBundle = await parseSkillBundle(buf);
3483
+ return { content: [{ type: "text", text: JSON.stringify({ ref, meta, ...parsedBundle }) }] };
3484
+ });
3485
+ async function listWorkspaces() {
3486
+ const result = await apiWithToken(token, "/libraries");
3487
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
3488
+ }
3489
+ server.tool("list_workspaces", {}, listWorkspaces);
3490
+ server.tool("list_libraries", {}, listWorkspaces);
3491
+ server.tool("install_skill", { ref: z2.string().min(3), target: z2.enum(["claude", "codex", "cursor", "kimi", "opencode", "gemini"]) }, async ({ ref, target }) => {
3492
+ const installed = await installViaApi(token, ref, target);
3493
+ return { content: [{ type: "text", text: JSON.stringify(installed) }] };
3494
+ });
3495
+ const transport = new StdioServerTransport();
3496
+ await server.connect(transport);
3497
+ }
3498
+
3499
+ // src/commands/doctor.ts
3500
+ import { mkdtemp as mkdtemp2, readdir as readdir5, rm as rm4 } from "node:fs/promises";
3501
+ import { tmpdir as tmpdir4 } from "node:os";
3502
+ import { join as join11 } from "node:path";
3503
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
3504
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
3505
+ function textOf(result) {
3506
+ return String(result?.content?.[0]?.text ?? "");
3507
+ }
3508
+ function pass(name, detail) {
3509
+ return { name, ok: true, detail };
3510
+ }
3511
+ function fail(name, detail) {
3512
+ return { name, ok: false, detail };
3513
+ }
3514
+ async function doctorCommand(opts = {}) {
3515
+ if (!opts.freshAgent) {
3516
+ const auth2 = await readAuth();
3517
+ const checks2 = [pass("cli_version", VERSION), auth2?.token ? pass("auth", `@${auth2.handle}`) : fail("auth", "not logged in")];
3518
+ emitDoctor(checks2, opts.json);
3519
+ if (checks2.some((check) => !check.ok)) process.exit(1);
3520
+ return;
3521
+ }
3522
+ const checks = [];
3523
+ const auth = await readAuth();
3524
+ const token = process.env.FLOOM_API_TOKEN?.trim() || auth?.token;
3525
+ if (!token) {
3526
+ checks.push(fail("fresh_agent_token", "missing FLOOM_API_TOKEN and ~/.floom/auth.json"));
3527
+ emitDoctor(checks, opts.json);
3528
+ process.exit(1);
3529
+ }
3530
+ const cliPath = process.argv[1];
3531
+ if (!cliPath) {
3532
+ checks.push(fail("fresh_agent_cli_path", "process.argv[1] is empty"));
3533
+ emitDoctor(checks, opts.json);
3534
+ process.exit(1);
3535
+ }
3536
+ const tmpHome = await mkdtemp2(join11(tmpdir4(), "floom-doctor-home-"));
3537
+ const tmpSkills = await mkdtemp2(join11(tmpdir4(), "floom-doctor-skills-"));
3538
+ const tmpProject = await mkdtemp2(join11(tmpdir4(), "floom-doctor-project-"));
3539
+ const transport = new StdioClientTransport({
3540
+ command: process.execPath,
3541
+ args: [cliPath, "mcp"],
3542
+ cwd: tmpProject,
3543
+ env: {
3544
+ ...process.env,
3545
+ HOME: tmpHome,
3546
+ FLOOM_API_TOKEN: token,
3547
+ FLOOM_SKILLS_DIR: tmpSkills,
3548
+ ...auth?.apiUrl ? { FLOOM_API_URL: auth.apiUrl } : {}
3549
+ },
3550
+ stderr: "pipe"
3551
+ });
3552
+ const client = new Client({ name: "floom-doctor", version: VERSION });
3553
+ try {
3554
+ await client.connect(transport);
3555
+ const tools = await client.listTools();
3556
+ const toolNames = tools.tools.map((tool) => tool.name).sort();
3557
+ const expected = ["get_skill", "install_skill", "list_workspaces", "search_skills"];
3558
+ const missing = expected.filter((name) => !toolNames.includes(name));
3559
+ checks.push(missing.length === 0 ? pass("mcp_tools", toolNames.join(", ")) : fail("mcp_tools", `missing ${missing.join(", ")}`));
3560
+ const workspaces = await client.callTool({ name: "list_workspaces", arguments: {} });
3561
+ checks.push(textOf(workspaces).length > 0 ? pass("mcp_list_workspaces", `${textOf(workspaces).length} chars`) : fail("mcp_list_workspaces", "empty response"));
3562
+ const search = await client.callTool({ name: "search_skills", arguments: { query: opts.query ?? "pdf" } });
3563
+ checks.push(textOf(search).length > 0 ? pass("mcp_search_skills", `${textOf(search).length} chars`) : fail("mcp_search_skills", "empty response"));
3564
+ if (opts.ref) {
3565
+ const skill = await client.callTool({ name: "get_skill", arguments: { ref: opts.ref } });
3566
+ checks.push(/SKILL\.md/.test(textOf(skill)) ? pass("mcp_get_skill", opts.ref) : fail("mcp_get_skill", "bundle did not include SKILL.md"));
3567
+ const installed = await client.callTool({ name: "install_skill", arguments: { ref: opts.ref, target: opts.target ?? "codex" } });
3568
+ const entries = await readdir5(tmpSkills);
3569
+ checks.push(entries.length > 0 ? pass("mcp_install_skill", textOf(installed)) : fail("mcp_install_skill", "target directory is empty"));
3570
+ }
3571
+ } catch (e) {
3572
+ checks.push(fail("fresh_agent_mcp", e.message));
3573
+ } finally {
3574
+ await client.close().catch(() => {
3575
+ });
3576
+ await rm4(tmpHome, { recursive: true, force: true });
3577
+ await rm4(tmpSkills, { recursive: true, force: true });
3578
+ await rm4(tmpProject, { recursive: true, force: true });
3579
+ }
3580
+ emitDoctor(checks, opts.json);
3581
+ if (checks.some((check) => !check.ok)) process.exit(1);
3582
+ }
3583
+ function emitDoctor(checks, json) {
3584
+ if (json) {
3585
+ console.log(JSON.stringify({ ok: checks.every((check) => check.ok), checks }, null, 2));
3586
+ return;
3587
+ }
3588
+ log.heading("Floom doctor");
3589
+ for (const check of checks) {
3590
+ const detail = check.detail ? ` ${check.detail}` : "";
3591
+ if (check.ok) log.ok(`${check.name}${detail}`);
3592
+ else log.err(`${check.name}${detail}`);
3593
+ }
3594
+ }
3595
+
3596
+ // src/index.ts
3597
+ var program = new Command();
3598
+ program.name("floom").description("Floom CLI \u2014 publish, install, sync, and share AI agent skills.").version(VERSION);
3599
+ program.command("login").description("Log in via browser (device code).").addHelpText("after", "\nExample:\n $ floom login").action(loginCommand);
26
3600
  program.command("logout").description("Log out and revoke local token.").action(logoutCommand);
27
3601
  program.command("whoami").description("Show the logged-in user.").action(whoamiCommand);
28
3602
  program.command("init").description("Scaffold a new skill in the current directory.").action(initCommand);
29
- program
30
- .command("validate")
31
- .description("Validate the skill in the current directory.")
32
- .option("--json", "Emit machine-readable JSON")
33
- .action((opts) => validateCommand(opts));
34
- program
35
- .command("publish")
36
- .description("Publish the skill in the current directory.")
37
- .option("--library <slug>", "Publish into a shared library slug (default: personal)")
38
- .action((opts) => publishCommand(opts));
39
- program.command("push").description("Alias for `publish`.").option("--library <slug>").action((opts) => publishCommand(opts));
40
- program
41
- .command("install <ref>")
42
- .description("Install a skill (default: .agents/skills/<slug>/).")
43
- .option("--for <target>", "Tool preset: claude | codex | cursor | gemini | opencode | kimi | all")
44
- .option("--to <path>", "Explicit install directory")
45
- .option("--global", "Install to user-level folder instead of project-local")
46
- .option("--force", "Overwrite existing folder")
47
- .action((ref, opts) => installCommand(ref, opts));
3603
+ program.command("validate").description("Validate the skill in the current directory.").option("--json", "Emit machine-readable JSON").action((opts) => validateCommand(opts));
3604
+ program.command("publish").description("Publish the skill in the current directory.").option("--dry-run", "Validate and pack locally without uploading.").option("--workspace <slug>", "Publish into a shared workspace slug (default: personal)").option("--library <slug>", "Legacy alias for --workspace").addHelpText("after", "\nExamples:\n $ floom publish\n $ floom publish --workspace team-workspace").action((opts) => publishCommand(opts));
3605
+ program.command("push").description("Alias for `publish`.").option("--dry-run", "Validate and pack locally without uploading.").option("--workspace <slug>", "Publish into a shared workspace slug").option("--library <slug>", "Legacy alias for --workspace").addHelpText("after", "\nExample:\n $ floom push --workspace team-workspace").action((opts) => publishCommand(opts));
3606
+ program.command("install <ref>").description("Install a skill (default: .agents/skills/<slug>/).").option("--for <target>", "Tool preset: claude | codex | cursor | gemini | opencode | kimi | all").option("--to <path>", "Explicit install directory").option("--global", "Install to user-level folder instead of project-local").option("--force", "Overwrite existing folder").addHelpText("after", "\nExamples:\n $ floom install @alice/research-brief\n $ floom install @alice/research-brief --for codex\n $ floom install @alice/research-brief --to .agents/skills").action((ref, opts) => installCommand(ref, opts));
48
3607
  program.command("installed").description("List installed skills in this project.").option("--json").action(installedCommand);
49
3608
  program.command("outdated").description("Show installed skills with newer versions available.").action(outdatedCommand);
50
- program
51
- .command("update [ref]")
52
- .description("Update installed skills to latest.")
53
- .option("--force", "Overwrite local edits")
54
- .action((ref, opts) => updateCommand(ref, opts));
55
- program
56
- .command("list")
57
- .description("List remote skills.")
58
- .option("--mine", "Only your own skills (default)")
59
- .option("--library <slug>", "Filter by library slug")
60
- .option("--folder <uuid>", "Filter by folder id")
61
- .option("--flat", "Print one ref per line")
62
- .option("--query <q>", "Filter by query")
63
- .action(listCommand);
3609
+ program.command("update [ref]").description("Update installed skills to latest.").option("--force", "Overwrite local edits").action((ref, opts) => updateCommand(ref, opts));
3610
+ program.command("list").description("List remote skills.").option("--mine", "Only your own skills (default)").option("--workspace <slug>", "Filter by workspace slug").option("--library <slug>", "Legacy alias for --workspace").option("--folder <uuid>", "Filter by folder id").option("--flat", "Print one ref per line").option("--query <q>", "Filter by query").action(listCommand);
64
3611
  program.command("info <ref>").description("Show details for a remote skill.").action(infoCommand);
65
- program
66
- .command("share <ref> <email>")
67
- .description("Invite someone to a skill by email.")
68
- .option("--role <role>", "viewer (default) or editor")
69
- .action((ref, email, opts) => shareCommand(ref, email, opts));
70
- program
71
- .command("unshare <ref> <email>")
72
- .description("Revoke someone's access.")
73
- .action((ref, email) => unshareCommand(ref, email));
74
- const lib = program.command("library").description("Manage libraries");
75
- lib.command("list").action(libraryListCommand);
76
- lib.command("create <slug> <name>").action((slug, name) => libraryCreateCommand(slug, name));
77
- lib.command("invite <librarySlug> <email>").option("--role <role>", "viewer|editor|admin", "viewer").action((librarySlug, email, opts) => libraryInviteCommand(librarySlug, email, opts.role));
78
- lib.command("leave <librarySlug>").action((librarySlug) => libraryLeaveCommand(librarySlug));
79
- // Global error handler
3612
+ program.command("share <ref> <email>").description("Invite someone to a skill by email.").option("--role <role>", "viewer (default) or editor").action((ref, email, opts) => shareCommand(ref, email, opts));
3613
+ program.command("unshare <ref> <email>").description("Revoke someone's access.").action((ref, email) => unshareCommand(ref, email));
3614
+ function addWorkspaceCommands(cmd) {
3615
+ cmd.command("list").action(libraryListCommand);
3616
+ cmd.command("create <slug> <name>").action((slug, name) => libraryCreateCommand(slug, name));
3617
+ cmd.command("invite <workspaceSlug> <email>").option("--role <role>", "viewer|editor|admin", "viewer").action((workspaceSlug, email, opts) => libraryInviteCommand(workspaceSlug, email, opts.role));
3618
+ cmd.command("leave <workspaceSlug>").action((workspaceSlug) => libraryLeaveCommand(workspaceSlug));
3619
+ }
3620
+ addWorkspaceCommands(program.command("workspace").description("Manage workspaces"));
3621
+ addWorkspaceCommands(program.command("library").description("Manage workspaces (legacy alias)"));
3622
+ program.command("doctor").description("Check local Floom CLI, auth, and fresh-agent MCP installability.").option("--fresh-agent", "Run MCP checks with a clean HOME and temp skills directory").option("--ref <ref>", "Skill ref to install during --fresh-agent, e.g. @depontefede/pdf").option("--target <target>", "Install target for --fresh-agent", "codex").option("--query <query>", "Search query for --fresh-agent", "pdf").option("--json", "Emit machine-readable JSON").action((opts) => doctorCommand(opts));
3623
+ program.command("mcp").description("Run local MCP server over stdio.").action(mcpCommand);
80
3624
  async function main() {
81
- try {
82
- await program.parseAsync(process.argv);
83
- }
84
- catch (e) {
85
- if (e instanceof FloomError) {
86
- log.err(e.message);
87
- if (e.code === "AUTH_REQUIRED" || e.code === "TOKEN_EXPIRED") {
88
- log.info("Run: floom login");
89
- }
90
- process.exit(1);
91
- }
92
- log.err(e.message ?? "Unknown error");
93
- if (process.env.FLOOM_DEBUG)
94
- console.error(e);
95
- process.exit(1);
3625
+ try {
3626
+ await program.parseAsync(process.argv);
3627
+ } catch (e) {
3628
+ if (e instanceof FloomError) {
3629
+ log.err(e.message);
3630
+ if (e.code === "AUTH_REQUIRED" || e.code === "TOKEN_EXPIRED") {
3631
+ log.info("Run: floom login");
3632
+ }
3633
+ process.exit(1);
96
3634
  }
3635
+ log.err(e.message ?? "Unknown error");
3636
+ if (process.env.FLOOM_DEBUG) console.error(e);
3637
+ process.exit(1);
3638
+ }
97
3639
  }
98
3640
  main();
99
- //# sourceMappingURL=index.js.map
3641
+ /*! Bundled license information:
3642
+
3643
+ bcryptjs/dist/bcrypt.js:
3644
+ (**
3645
+ * @license bcrypt.js (c) 2013 Daniel Wirtz <dcode@dcode.io>
3646
+ * Released under the Apache License, Version 2.0
3647
+ * see: https://github.com/dcodeIO/bcrypt.js for details
3648
+ *)
3649
+ */
3650
+ //# sourceMappingURL=index.js.map