@ghostystudio/cli 0.67.0 → 0.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -2
- package/dist/index.js +1131 -995
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -32,9 +32,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
32
32
|
mod
|
|
33
33
|
));
|
|
34
34
|
|
|
35
|
-
//
|
|
35
|
+
// ../../node_modules/yaml/dist/nodes/identity.js
|
|
36
36
|
var require_identity = __commonJS({
|
|
37
|
-
"
|
|
37
|
+
"../../node_modules/yaml/dist/nodes/identity.js"(exports) {
|
|
38
38
|
"use strict";
|
|
39
39
|
var ALIAS = /* @__PURE__ */ Symbol.for("yaml.alias");
|
|
40
40
|
var DOC = /* @__PURE__ */ Symbol.for("yaml.document");
|
|
@@ -89,9 +89,9 @@ var require_identity = __commonJS({
|
|
|
89
89
|
}
|
|
90
90
|
});
|
|
91
91
|
|
|
92
|
-
//
|
|
92
|
+
// ../../node_modules/yaml/dist/visit.js
|
|
93
93
|
var require_visit = __commonJS({
|
|
94
|
-
"
|
|
94
|
+
"../../node_modules/yaml/dist/visit.js"(exports) {
|
|
95
95
|
"use strict";
|
|
96
96
|
var identity = require_identity();
|
|
97
97
|
var BREAK = /* @__PURE__ */ Symbol("break visit");
|
|
@@ -247,9 +247,9 @@ var require_visit = __commonJS({
|
|
|
247
247
|
}
|
|
248
248
|
});
|
|
249
249
|
|
|
250
|
-
//
|
|
250
|
+
// ../../node_modules/yaml/dist/doc/directives.js
|
|
251
251
|
var require_directives = __commonJS({
|
|
252
|
-
"
|
|
252
|
+
"../../node_modules/yaml/dist/doc/directives.js"(exports) {
|
|
253
253
|
"use strict";
|
|
254
254
|
var identity = require_identity();
|
|
255
255
|
var visit = require_visit();
|
|
@@ -418,9 +418,9 @@ var require_directives = __commonJS({
|
|
|
418
418
|
}
|
|
419
419
|
});
|
|
420
420
|
|
|
421
|
-
//
|
|
421
|
+
// ../../node_modules/yaml/dist/doc/anchors.js
|
|
422
422
|
var require_anchors = __commonJS({
|
|
423
|
-
"
|
|
423
|
+
"../../node_modules/yaml/dist/doc/anchors.js"(exports) {
|
|
424
424
|
"use strict";
|
|
425
425
|
var identity = require_identity();
|
|
426
426
|
var visit = require_visit();
|
|
@@ -488,9 +488,9 @@ var require_anchors = __commonJS({
|
|
|
488
488
|
}
|
|
489
489
|
});
|
|
490
490
|
|
|
491
|
-
//
|
|
491
|
+
// ../../node_modules/yaml/dist/doc/applyReviver.js
|
|
492
492
|
var require_applyReviver = __commonJS({
|
|
493
|
-
"
|
|
493
|
+
"../../node_modules/yaml/dist/doc/applyReviver.js"(exports) {
|
|
494
494
|
"use strict";
|
|
495
495
|
function applyReviver(reviver, obj, key, val) {
|
|
496
496
|
if (val && typeof val === "object") {
|
|
@@ -538,9 +538,9 @@ var require_applyReviver = __commonJS({
|
|
|
538
538
|
}
|
|
539
539
|
});
|
|
540
540
|
|
|
541
|
-
//
|
|
541
|
+
// ../../node_modules/yaml/dist/nodes/toJS.js
|
|
542
542
|
var require_toJS = __commonJS({
|
|
543
|
-
"
|
|
543
|
+
"../../node_modules/yaml/dist/nodes/toJS.js"(exports) {
|
|
544
544
|
"use strict";
|
|
545
545
|
var identity = require_identity();
|
|
546
546
|
function toJS(value, arg, ctx) {
|
|
@@ -568,9 +568,9 @@ var require_toJS = __commonJS({
|
|
|
568
568
|
}
|
|
569
569
|
});
|
|
570
570
|
|
|
571
|
-
//
|
|
571
|
+
// ../../node_modules/yaml/dist/nodes/Node.js
|
|
572
572
|
var require_Node = __commonJS({
|
|
573
|
-
"
|
|
573
|
+
"../../node_modules/yaml/dist/nodes/Node.js"(exports) {
|
|
574
574
|
"use strict";
|
|
575
575
|
var applyReviver = require_applyReviver();
|
|
576
576
|
var identity = require_identity();
|
|
@@ -609,9 +609,9 @@ var require_Node = __commonJS({
|
|
|
609
609
|
}
|
|
610
610
|
});
|
|
611
611
|
|
|
612
|
-
//
|
|
612
|
+
// ../../node_modules/yaml/dist/nodes/Alias.js
|
|
613
613
|
var require_Alias = __commonJS({
|
|
614
|
-
"
|
|
614
|
+
"../../node_modules/yaml/dist/nodes/Alias.js"(exports) {
|
|
615
615
|
"use strict";
|
|
616
616
|
var anchors = require_anchors();
|
|
617
617
|
var visit = require_visit();
|
|
@@ -727,9 +727,9 @@ var require_Alias = __commonJS({
|
|
|
727
727
|
}
|
|
728
728
|
});
|
|
729
729
|
|
|
730
|
-
//
|
|
730
|
+
// ../../node_modules/yaml/dist/nodes/Scalar.js
|
|
731
731
|
var require_Scalar = __commonJS({
|
|
732
|
-
"
|
|
732
|
+
"../../node_modules/yaml/dist/nodes/Scalar.js"(exports) {
|
|
733
733
|
"use strict";
|
|
734
734
|
var identity = require_identity();
|
|
735
735
|
var Node = require_Node();
|
|
@@ -757,9 +757,9 @@ var require_Scalar = __commonJS({
|
|
|
757
757
|
}
|
|
758
758
|
});
|
|
759
759
|
|
|
760
|
-
//
|
|
760
|
+
// ../../node_modules/yaml/dist/doc/createNode.js
|
|
761
761
|
var require_createNode = __commonJS({
|
|
762
|
-
"
|
|
762
|
+
"../../node_modules/yaml/dist/doc/createNode.js"(exports) {
|
|
763
763
|
"use strict";
|
|
764
764
|
var Alias = require_Alias();
|
|
765
765
|
var identity = require_identity();
|
|
@@ -832,9 +832,9 @@ var require_createNode = __commonJS({
|
|
|
832
832
|
}
|
|
833
833
|
});
|
|
834
834
|
|
|
835
|
-
//
|
|
835
|
+
// ../../node_modules/yaml/dist/nodes/Collection.js
|
|
836
836
|
var require_Collection = __commonJS({
|
|
837
|
-
"
|
|
837
|
+
"../../node_modules/yaml/dist/nodes/Collection.js"(exports) {
|
|
838
838
|
"use strict";
|
|
839
839
|
var createNode = require_createNode();
|
|
840
840
|
var identity = require_identity();
|
|
@@ -975,9 +975,9 @@ var require_Collection = __commonJS({
|
|
|
975
975
|
}
|
|
976
976
|
});
|
|
977
977
|
|
|
978
|
-
//
|
|
978
|
+
// ../../node_modules/yaml/dist/stringify/stringifyComment.js
|
|
979
979
|
var require_stringifyComment = __commonJS({
|
|
980
|
-
"
|
|
980
|
+
"../../node_modules/yaml/dist/stringify/stringifyComment.js"(exports) {
|
|
981
981
|
"use strict";
|
|
982
982
|
var stringifyComment = (str) => str.replace(/^(?!$)(?: $)?/gm, "#");
|
|
983
983
|
function indentComment(comment, indent) {
|
|
@@ -992,9 +992,9 @@ var require_stringifyComment = __commonJS({
|
|
|
992
992
|
}
|
|
993
993
|
});
|
|
994
994
|
|
|
995
|
-
//
|
|
995
|
+
// ../../node_modules/yaml/dist/stringify/foldFlowLines.js
|
|
996
996
|
var require_foldFlowLines = __commonJS({
|
|
997
|
-
"
|
|
997
|
+
"../../node_modules/yaml/dist/stringify/foldFlowLines.js"(exports) {
|
|
998
998
|
"use strict";
|
|
999
999
|
var FOLD_FLOW = "flow";
|
|
1000
1000
|
var FOLD_BLOCK = "block";
|
|
@@ -1128,9 +1128,9 @@ ${indent}${text.slice(fold + 1, end2)}`;
|
|
|
1128
1128
|
}
|
|
1129
1129
|
});
|
|
1130
1130
|
|
|
1131
|
-
//
|
|
1131
|
+
// ../../node_modules/yaml/dist/stringify/stringifyString.js
|
|
1132
1132
|
var require_stringifyString = __commonJS({
|
|
1133
|
-
"
|
|
1133
|
+
"../../node_modules/yaml/dist/stringify/stringifyString.js"(exports) {
|
|
1134
1134
|
"use strict";
|
|
1135
1135
|
var Scalar = require_Scalar();
|
|
1136
1136
|
var foldFlowLines = require_foldFlowLines();
|
|
@@ -1411,9 +1411,9 @@ ${indent}`);
|
|
|
1411
1411
|
}
|
|
1412
1412
|
});
|
|
1413
1413
|
|
|
1414
|
-
//
|
|
1414
|
+
// ../../node_modules/yaml/dist/stringify/stringify.js
|
|
1415
1415
|
var require_stringify = __commonJS({
|
|
1416
|
-
"
|
|
1416
|
+
"../../node_modules/yaml/dist/stringify/stringify.js"(exports) {
|
|
1417
1417
|
"use strict";
|
|
1418
1418
|
var anchors = require_anchors();
|
|
1419
1419
|
var identity = require_identity();
|
|
@@ -1535,9 +1535,9 @@ ${ctx.indent}${str}`;
|
|
|
1535
1535
|
}
|
|
1536
1536
|
});
|
|
1537
1537
|
|
|
1538
|
-
//
|
|
1538
|
+
// ../../node_modules/yaml/dist/stringify/stringifyPair.js
|
|
1539
1539
|
var require_stringifyPair = __commonJS({
|
|
1540
|
-
"
|
|
1540
|
+
"../../node_modules/yaml/dist/stringify/stringifyPair.js"(exports) {
|
|
1541
1541
|
"use strict";
|
|
1542
1542
|
var identity = require_identity();
|
|
1543
1543
|
var Scalar = require_Scalar();
|
|
@@ -1668,9 +1668,9 @@ ${ctx.indent}`;
|
|
|
1668
1668
|
}
|
|
1669
1669
|
});
|
|
1670
1670
|
|
|
1671
|
-
//
|
|
1671
|
+
// ../../node_modules/yaml/dist/log.js
|
|
1672
1672
|
var require_log = __commonJS({
|
|
1673
|
-
"
|
|
1673
|
+
"../../node_modules/yaml/dist/log.js"(exports) {
|
|
1674
1674
|
"use strict";
|
|
1675
1675
|
var node_process = __require("process");
|
|
1676
1676
|
function debug(logLevel, ...messages) {
|
|
@@ -1690,9 +1690,9 @@ var require_log = __commonJS({
|
|
|
1690
1690
|
}
|
|
1691
1691
|
});
|
|
1692
1692
|
|
|
1693
|
-
//
|
|
1693
|
+
// ../../node_modules/yaml/dist/schema/yaml-1.1/merge.js
|
|
1694
1694
|
var require_merge = __commonJS({
|
|
1695
|
-
"
|
|
1695
|
+
"../../node_modules/yaml/dist/schema/yaml-1.1/merge.js"(exports) {
|
|
1696
1696
|
"use strict";
|
|
1697
1697
|
var identity = require_identity();
|
|
1698
1698
|
var Scalar = require_Scalar();
|
|
@@ -1750,9 +1750,9 @@ var require_merge = __commonJS({
|
|
|
1750
1750
|
}
|
|
1751
1751
|
});
|
|
1752
1752
|
|
|
1753
|
-
//
|
|
1753
|
+
// ../../node_modules/yaml/dist/nodes/addPairToJSMap.js
|
|
1754
1754
|
var require_addPairToJSMap = __commonJS({
|
|
1755
|
-
"
|
|
1755
|
+
"../../node_modules/yaml/dist/nodes/addPairToJSMap.js"(exports) {
|
|
1756
1756
|
"use strict";
|
|
1757
1757
|
var log = require_log();
|
|
1758
1758
|
var merge = require_merge();
|
|
@@ -1814,9 +1814,9 @@ var require_addPairToJSMap = __commonJS({
|
|
|
1814
1814
|
}
|
|
1815
1815
|
});
|
|
1816
1816
|
|
|
1817
|
-
//
|
|
1817
|
+
// ../../node_modules/yaml/dist/nodes/Pair.js
|
|
1818
1818
|
var require_Pair = __commonJS({
|
|
1819
|
-
"
|
|
1819
|
+
"../../node_modules/yaml/dist/nodes/Pair.js"(exports) {
|
|
1820
1820
|
"use strict";
|
|
1821
1821
|
var createNode = require_createNode();
|
|
1822
1822
|
var stringifyPair = require_stringifyPair();
|
|
@@ -1854,9 +1854,9 @@ var require_Pair = __commonJS({
|
|
|
1854
1854
|
}
|
|
1855
1855
|
});
|
|
1856
1856
|
|
|
1857
|
-
//
|
|
1857
|
+
// ../../node_modules/yaml/dist/stringify/stringifyCollection.js
|
|
1858
1858
|
var require_stringifyCollection = __commonJS({
|
|
1859
|
-
"
|
|
1859
|
+
"../../node_modules/yaml/dist/stringify/stringifyCollection.js"(exports) {
|
|
1860
1860
|
"use strict";
|
|
1861
1861
|
var identity = require_identity();
|
|
1862
1862
|
var stringify = require_stringify();
|
|
@@ -2005,9 +2005,9 @@ ${indent}${end}`;
|
|
|
2005
2005
|
}
|
|
2006
2006
|
});
|
|
2007
2007
|
|
|
2008
|
-
//
|
|
2008
|
+
// ../../node_modules/yaml/dist/nodes/YAMLMap.js
|
|
2009
2009
|
var require_YAMLMap = __commonJS({
|
|
2010
|
-
"
|
|
2010
|
+
"../../node_modules/yaml/dist/nodes/YAMLMap.js"(exports) {
|
|
2011
2011
|
"use strict";
|
|
2012
2012
|
var stringifyCollection = require_stringifyCollection();
|
|
2013
2013
|
var addPairToJSMap = require_addPairToJSMap();
|
|
@@ -2149,9 +2149,9 @@ var require_YAMLMap = __commonJS({
|
|
|
2149
2149
|
}
|
|
2150
2150
|
});
|
|
2151
2151
|
|
|
2152
|
-
//
|
|
2152
|
+
// ../../node_modules/yaml/dist/schema/common/map.js
|
|
2153
2153
|
var require_map = __commonJS({
|
|
2154
|
-
"
|
|
2154
|
+
"../../node_modules/yaml/dist/schema/common/map.js"(exports) {
|
|
2155
2155
|
"use strict";
|
|
2156
2156
|
var identity = require_identity();
|
|
2157
2157
|
var YAMLMap = require_YAMLMap();
|
|
@@ -2171,9 +2171,9 @@ var require_map = __commonJS({
|
|
|
2171
2171
|
}
|
|
2172
2172
|
});
|
|
2173
2173
|
|
|
2174
|
-
//
|
|
2174
|
+
// ../../node_modules/yaml/dist/nodes/YAMLSeq.js
|
|
2175
2175
|
var require_YAMLSeq = __commonJS({
|
|
2176
|
-
"
|
|
2176
|
+
"../../node_modules/yaml/dist/nodes/YAMLSeq.js"(exports) {
|
|
2177
2177
|
"use strict";
|
|
2178
2178
|
var createNode = require_createNode();
|
|
2179
2179
|
var stringifyCollection = require_stringifyCollection();
|
|
@@ -2287,9 +2287,9 @@ var require_YAMLSeq = __commonJS({
|
|
|
2287
2287
|
}
|
|
2288
2288
|
});
|
|
2289
2289
|
|
|
2290
|
-
//
|
|
2290
|
+
// ../../node_modules/yaml/dist/schema/common/seq.js
|
|
2291
2291
|
var require_seq = __commonJS({
|
|
2292
|
-
"
|
|
2292
|
+
"../../node_modules/yaml/dist/schema/common/seq.js"(exports) {
|
|
2293
2293
|
"use strict";
|
|
2294
2294
|
var identity = require_identity();
|
|
2295
2295
|
var YAMLSeq = require_YAMLSeq();
|
|
@@ -2309,9 +2309,9 @@ var require_seq = __commonJS({
|
|
|
2309
2309
|
}
|
|
2310
2310
|
});
|
|
2311
2311
|
|
|
2312
|
-
//
|
|
2312
|
+
// ../../node_modules/yaml/dist/schema/common/string.js
|
|
2313
2313
|
var require_string = __commonJS({
|
|
2314
|
-
"
|
|
2314
|
+
"../../node_modules/yaml/dist/schema/common/string.js"(exports) {
|
|
2315
2315
|
"use strict";
|
|
2316
2316
|
var stringifyString = require_stringifyString();
|
|
2317
2317
|
var string = {
|
|
@@ -2328,9 +2328,9 @@ var require_string = __commonJS({
|
|
|
2328
2328
|
}
|
|
2329
2329
|
});
|
|
2330
2330
|
|
|
2331
|
-
//
|
|
2331
|
+
// ../../node_modules/yaml/dist/schema/common/null.js
|
|
2332
2332
|
var require_null = __commonJS({
|
|
2333
|
-
"
|
|
2333
|
+
"../../node_modules/yaml/dist/schema/common/null.js"(exports) {
|
|
2334
2334
|
"use strict";
|
|
2335
2335
|
var Scalar = require_Scalar();
|
|
2336
2336
|
var nullTag = {
|
|
@@ -2346,9 +2346,9 @@ var require_null = __commonJS({
|
|
|
2346
2346
|
}
|
|
2347
2347
|
});
|
|
2348
2348
|
|
|
2349
|
-
//
|
|
2349
|
+
// ../../node_modules/yaml/dist/schema/core/bool.js
|
|
2350
2350
|
var require_bool = __commonJS({
|
|
2351
|
-
"
|
|
2351
|
+
"../../node_modules/yaml/dist/schema/core/bool.js"(exports) {
|
|
2352
2352
|
"use strict";
|
|
2353
2353
|
var Scalar = require_Scalar();
|
|
2354
2354
|
var boolTag = {
|
|
@@ -2370,9 +2370,9 @@ var require_bool = __commonJS({
|
|
|
2370
2370
|
}
|
|
2371
2371
|
});
|
|
2372
2372
|
|
|
2373
|
-
//
|
|
2373
|
+
// ../../node_modules/yaml/dist/stringify/stringifyNumber.js
|
|
2374
2374
|
var require_stringifyNumber = __commonJS({
|
|
2375
|
-
"
|
|
2375
|
+
"../../node_modules/yaml/dist/stringify/stringifyNumber.js"(exports) {
|
|
2376
2376
|
"use strict";
|
|
2377
2377
|
function stringifyNumber({ format, minFractionDigits, tag, value }) {
|
|
2378
2378
|
if (typeof value === "bigint")
|
|
@@ -2397,9 +2397,9 @@ var require_stringifyNumber = __commonJS({
|
|
|
2397
2397
|
}
|
|
2398
2398
|
});
|
|
2399
2399
|
|
|
2400
|
-
//
|
|
2400
|
+
// ../../node_modules/yaml/dist/schema/core/float.js
|
|
2401
2401
|
var require_float = __commonJS({
|
|
2402
|
-
"
|
|
2402
|
+
"../../node_modules/yaml/dist/schema/core/float.js"(exports) {
|
|
2403
2403
|
"use strict";
|
|
2404
2404
|
var Scalar = require_Scalar();
|
|
2405
2405
|
var stringifyNumber = require_stringifyNumber();
|
|
@@ -2443,9 +2443,9 @@ var require_float = __commonJS({
|
|
|
2443
2443
|
}
|
|
2444
2444
|
});
|
|
2445
2445
|
|
|
2446
|
-
//
|
|
2446
|
+
// ../../node_modules/yaml/dist/schema/core/int.js
|
|
2447
2447
|
var require_int = __commonJS({
|
|
2448
|
-
"
|
|
2448
|
+
"../../node_modules/yaml/dist/schema/core/int.js"(exports) {
|
|
2449
2449
|
"use strict";
|
|
2450
2450
|
var stringifyNumber = require_stringifyNumber();
|
|
2451
2451
|
var intIdentify = (value) => typeof value === "bigint" || Number.isInteger(value);
|
|
@@ -2488,9 +2488,9 @@ var require_int = __commonJS({
|
|
|
2488
2488
|
}
|
|
2489
2489
|
});
|
|
2490
2490
|
|
|
2491
|
-
//
|
|
2491
|
+
// ../../node_modules/yaml/dist/schema/core/schema.js
|
|
2492
2492
|
var require_schema = __commonJS({
|
|
2493
|
-
"
|
|
2493
|
+
"../../node_modules/yaml/dist/schema/core/schema.js"(exports) {
|
|
2494
2494
|
"use strict";
|
|
2495
2495
|
var map = require_map();
|
|
2496
2496
|
var _null = require_null();
|
|
@@ -2516,9 +2516,9 @@ var require_schema = __commonJS({
|
|
|
2516
2516
|
}
|
|
2517
2517
|
});
|
|
2518
2518
|
|
|
2519
|
-
//
|
|
2519
|
+
// ../../node_modules/yaml/dist/schema/json/schema.js
|
|
2520
2520
|
var require_schema2 = __commonJS({
|
|
2521
|
-
"
|
|
2521
|
+
"../../node_modules/yaml/dist/schema/json/schema.js"(exports) {
|
|
2522
2522
|
"use strict";
|
|
2523
2523
|
var Scalar = require_Scalar();
|
|
2524
2524
|
var map = require_map();
|
|
@@ -2583,9 +2583,9 @@ var require_schema2 = __commonJS({
|
|
|
2583
2583
|
}
|
|
2584
2584
|
});
|
|
2585
2585
|
|
|
2586
|
-
//
|
|
2586
|
+
// ../../node_modules/yaml/dist/schema/yaml-1.1/binary.js
|
|
2587
2587
|
var require_binary = __commonJS({
|
|
2588
|
-
"
|
|
2588
|
+
"../../node_modules/yaml/dist/schema/yaml-1.1/binary.js"(exports) {
|
|
2589
2589
|
"use strict";
|
|
2590
2590
|
var node_buffer = __require("buffer");
|
|
2591
2591
|
var Scalar = require_Scalar();
|
|
@@ -2649,9 +2649,9 @@ var require_binary = __commonJS({
|
|
|
2649
2649
|
}
|
|
2650
2650
|
});
|
|
2651
2651
|
|
|
2652
|
-
//
|
|
2652
|
+
// ../../node_modules/yaml/dist/schema/yaml-1.1/pairs.js
|
|
2653
2653
|
var require_pairs = __commonJS({
|
|
2654
|
-
"
|
|
2654
|
+
"../../node_modules/yaml/dist/schema/yaml-1.1/pairs.js"(exports) {
|
|
2655
2655
|
"use strict";
|
|
2656
2656
|
var identity = require_identity();
|
|
2657
2657
|
var Pair = require_Pair();
|
|
@@ -2727,9 +2727,9 @@ ${cn.comment}` : item.comment;
|
|
|
2727
2727
|
}
|
|
2728
2728
|
});
|
|
2729
2729
|
|
|
2730
|
-
//
|
|
2730
|
+
// ../../node_modules/yaml/dist/schema/yaml-1.1/omap.js
|
|
2731
2731
|
var require_omap = __commonJS({
|
|
2732
|
-
"
|
|
2732
|
+
"../../node_modules/yaml/dist/schema/yaml-1.1/omap.js"(exports) {
|
|
2733
2733
|
"use strict";
|
|
2734
2734
|
var identity = require_identity();
|
|
2735
2735
|
var toJS = require_toJS();
|
|
@@ -2805,9 +2805,9 @@ var require_omap = __commonJS({
|
|
|
2805
2805
|
}
|
|
2806
2806
|
});
|
|
2807
2807
|
|
|
2808
|
-
//
|
|
2808
|
+
// ../../node_modules/yaml/dist/schema/yaml-1.1/bool.js
|
|
2809
2809
|
var require_bool2 = __commonJS({
|
|
2810
|
-
"
|
|
2810
|
+
"../../node_modules/yaml/dist/schema/yaml-1.1/bool.js"(exports) {
|
|
2811
2811
|
"use strict";
|
|
2812
2812
|
var Scalar = require_Scalar();
|
|
2813
2813
|
function boolStringify({ value, source }, ctx) {
|
|
@@ -2837,9 +2837,9 @@ var require_bool2 = __commonJS({
|
|
|
2837
2837
|
}
|
|
2838
2838
|
});
|
|
2839
2839
|
|
|
2840
|
-
//
|
|
2840
|
+
// ../../node_modules/yaml/dist/schema/yaml-1.1/float.js
|
|
2841
2841
|
var require_float2 = __commonJS({
|
|
2842
|
-
"
|
|
2842
|
+
"../../node_modules/yaml/dist/schema/yaml-1.1/float.js"(exports) {
|
|
2843
2843
|
"use strict";
|
|
2844
2844
|
var Scalar = require_Scalar();
|
|
2845
2845
|
var stringifyNumber = require_stringifyNumber();
|
|
@@ -2886,9 +2886,9 @@ var require_float2 = __commonJS({
|
|
|
2886
2886
|
}
|
|
2887
2887
|
});
|
|
2888
2888
|
|
|
2889
|
-
//
|
|
2889
|
+
// ../../node_modules/yaml/dist/schema/yaml-1.1/int.js
|
|
2890
2890
|
var require_int2 = __commonJS({
|
|
2891
|
-
"
|
|
2891
|
+
"../../node_modules/yaml/dist/schema/yaml-1.1/int.js"(exports) {
|
|
2892
2892
|
"use strict";
|
|
2893
2893
|
var stringifyNumber = require_stringifyNumber();
|
|
2894
2894
|
var intIdentify = (value) => typeof value === "bigint" || Number.isInteger(value);
|
|
@@ -2965,9 +2965,9 @@ var require_int2 = __commonJS({
|
|
|
2965
2965
|
}
|
|
2966
2966
|
});
|
|
2967
2967
|
|
|
2968
|
-
//
|
|
2968
|
+
// ../../node_modules/yaml/dist/schema/yaml-1.1/set.js
|
|
2969
2969
|
var require_set = __commonJS({
|
|
2970
|
-
"
|
|
2970
|
+
"../../node_modules/yaml/dist/schema/yaml-1.1/set.js"(exports) {
|
|
2971
2971
|
"use strict";
|
|
2972
2972
|
var identity = require_identity();
|
|
2973
2973
|
var Pair = require_Pair();
|
|
@@ -3054,9 +3054,9 @@ var require_set = __commonJS({
|
|
|
3054
3054
|
}
|
|
3055
3055
|
});
|
|
3056
3056
|
|
|
3057
|
-
//
|
|
3057
|
+
// ../../node_modules/yaml/dist/schema/yaml-1.1/timestamp.js
|
|
3058
3058
|
var require_timestamp = __commonJS({
|
|
3059
|
-
"
|
|
3059
|
+
"../../node_modules/yaml/dist/schema/yaml-1.1/timestamp.js"(exports) {
|
|
3060
3060
|
"use strict";
|
|
3061
3061
|
var stringifyNumber = require_stringifyNumber();
|
|
3062
3062
|
function parseSexagesimal(str, asBigInt) {
|
|
@@ -3142,9 +3142,9 @@ var require_timestamp = __commonJS({
|
|
|
3142
3142
|
}
|
|
3143
3143
|
});
|
|
3144
3144
|
|
|
3145
|
-
//
|
|
3145
|
+
// ../../node_modules/yaml/dist/schema/yaml-1.1/schema.js
|
|
3146
3146
|
var require_schema3 = __commonJS({
|
|
3147
|
-
"
|
|
3147
|
+
"../../node_modules/yaml/dist/schema/yaml-1.1/schema.js"(exports) {
|
|
3148
3148
|
"use strict";
|
|
3149
3149
|
var map = require_map();
|
|
3150
3150
|
var _null = require_null();
|
|
@@ -3186,9 +3186,9 @@ var require_schema3 = __commonJS({
|
|
|
3186
3186
|
}
|
|
3187
3187
|
});
|
|
3188
3188
|
|
|
3189
|
-
//
|
|
3189
|
+
// ../../node_modules/yaml/dist/schema/tags.js
|
|
3190
3190
|
var require_tags = __commonJS({
|
|
3191
|
-
"
|
|
3191
|
+
"../../node_modules/yaml/dist/schema/tags.js"(exports) {
|
|
3192
3192
|
"use strict";
|
|
3193
3193
|
var map = require_map();
|
|
3194
3194
|
var _null = require_null();
|
|
@@ -3280,9 +3280,9 @@ var require_tags = __commonJS({
|
|
|
3280
3280
|
}
|
|
3281
3281
|
});
|
|
3282
3282
|
|
|
3283
|
-
//
|
|
3283
|
+
// ../../node_modules/yaml/dist/schema/Schema.js
|
|
3284
3284
|
var require_Schema = __commonJS({
|
|
3285
|
-
"
|
|
3285
|
+
"../../node_modules/yaml/dist/schema/Schema.js"(exports) {
|
|
3286
3286
|
"use strict";
|
|
3287
3287
|
var identity = require_identity();
|
|
3288
3288
|
var map = require_map();
|
|
@@ -3312,9 +3312,9 @@ var require_Schema = __commonJS({
|
|
|
3312
3312
|
}
|
|
3313
3313
|
});
|
|
3314
3314
|
|
|
3315
|
-
//
|
|
3315
|
+
// ../../node_modules/yaml/dist/stringify/stringifyDocument.js
|
|
3316
3316
|
var require_stringifyDocument = __commonJS({
|
|
3317
|
-
"
|
|
3317
|
+
"../../node_modules/yaml/dist/stringify/stringifyDocument.js"(exports) {
|
|
3318
3318
|
"use strict";
|
|
3319
3319
|
var identity = require_identity();
|
|
3320
3320
|
var stringify = require_stringify();
|
|
@@ -3392,9 +3392,9 @@ var require_stringifyDocument = __commonJS({
|
|
|
3392
3392
|
}
|
|
3393
3393
|
});
|
|
3394
3394
|
|
|
3395
|
-
//
|
|
3395
|
+
// ../../node_modules/yaml/dist/doc/Document.js
|
|
3396
3396
|
var require_Document = __commonJS({
|
|
3397
|
-
"
|
|
3397
|
+
"../../node_modules/yaml/dist/doc/Document.js"(exports) {
|
|
3398
3398
|
"use strict";
|
|
3399
3399
|
var Alias = require_Alias();
|
|
3400
3400
|
var Collection = require_Collection();
|
|
@@ -3701,9 +3701,9 @@ var require_Document = __commonJS({
|
|
|
3701
3701
|
}
|
|
3702
3702
|
});
|
|
3703
3703
|
|
|
3704
|
-
//
|
|
3704
|
+
// ../../node_modules/yaml/dist/errors.js
|
|
3705
3705
|
var require_errors = __commonJS({
|
|
3706
|
-
"
|
|
3706
|
+
"../../node_modules/yaml/dist/errors.js"(exports) {
|
|
3707
3707
|
"use strict";
|
|
3708
3708
|
var YAMLError = class extends Error {
|
|
3709
3709
|
constructor(name, pos, code, message) {
|
|
@@ -3766,9 +3766,9 @@ ${pointer}
|
|
|
3766
3766
|
}
|
|
3767
3767
|
});
|
|
3768
3768
|
|
|
3769
|
-
//
|
|
3769
|
+
// ../../node_modules/yaml/dist/compose/resolve-props.js
|
|
3770
3770
|
var require_resolve_props = __commonJS({
|
|
3771
|
-
"
|
|
3771
|
+
"../../node_modules/yaml/dist/compose/resolve-props.js"(exports) {
|
|
3772
3772
|
"use strict";
|
|
3773
3773
|
function resolveProps(tokens, { flow, indicator, next, offset, onError, parentIndent, startOnNewline }) {
|
|
3774
3774
|
let spaceBefore = false;
|
|
@@ -3900,9 +3900,9 @@ var require_resolve_props = __commonJS({
|
|
|
3900
3900
|
}
|
|
3901
3901
|
});
|
|
3902
3902
|
|
|
3903
|
-
//
|
|
3903
|
+
// ../../node_modules/yaml/dist/compose/util-contains-newline.js
|
|
3904
3904
|
var require_util_contains_newline = __commonJS({
|
|
3905
|
-
"
|
|
3905
|
+
"../../node_modules/yaml/dist/compose/util-contains-newline.js"(exports) {
|
|
3906
3906
|
"use strict";
|
|
3907
3907
|
function containsNewline(key) {
|
|
3908
3908
|
if (!key)
|
|
@@ -3942,9 +3942,9 @@ var require_util_contains_newline = __commonJS({
|
|
|
3942
3942
|
}
|
|
3943
3943
|
});
|
|
3944
3944
|
|
|
3945
|
-
//
|
|
3945
|
+
// ../../node_modules/yaml/dist/compose/util-flow-indent-check.js
|
|
3946
3946
|
var require_util_flow_indent_check = __commonJS({
|
|
3947
|
-
"
|
|
3947
|
+
"../../node_modules/yaml/dist/compose/util-flow-indent-check.js"(exports) {
|
|
3948
3948
|
"use strict";
|
|
3949
3949
|
var utilContainsNewline = require_util_contains_newline();
|
|
3950
3950
|
function flowIndentCheck(indent, fc, onError) {
|
|
@@ -3960,9 +3960,9 @@ var require_util_flow_indent_check = __commonJS({
|
|
|
3960
3960
|
}
|
|
3961
3961
|
});
|
|
3962
3962
|
|
|
3963
|
-
//
|
|
3963
|
+
// ../../node_modules/yaml/dist/compose/util-map-includes.js
|
|
3964
3964
|
var require_util_map_includes = __commonJS({
|
|
3965
|
-
"
|
|
3965
|
+
"../../node_modules/yaml/dist/compose/util-map-includes.js"(exports) {
|
|
3966
3966
|
"use strict";
|
|
3967
3967
|
var identity = require_identity();
|
|
3968
3968
|
function mapIncludes(ctx, items, search) {
|
|
@@ -3976,9 +3976,9 @@ var require_util_map_includes = __commonJS({
|
|
|
3976
3976
|
}
|
|
3977
3977
|
});
|
|
3978
3978
|
|
|
3979
|
-
//
|
|
3979
|
+
// ../../node_modules/yaml/dist/compose/resolve-block-map.js
|
|
3980
3980
|
var require_resolve_block_map = __commonJS({
|
|
3981
|
-
"
|
|
3981
|
+
"../../node_modules/yaml/dist/compose/resolve-block-map.js"(exports) {
|
|
3982
3982
|
"use strict";
|
|
3983
3983
|
var Pair = require_Pair();
|
|
3984
3984
|
var YAMLMap = require_YAMLMap();
|
|
@@ -4084,9 +4084,9 @@ var require_resolve_block_map = __commonJS({
|
|
|
4084
4084
|
}
|
|
4085
4085
|
});
|
|
4086
4086
|
|
|
4087
|
-
//
|
|
4087
|
+
// ../../node_modules/yaml/dist/compose/resolve-block-seq.js
|
|
4088
4088
|
var require_resolve_block_seq = __commonJS({
|
|
4089
|
-
"
|
|
4089
|
+
"../../node_modules/yaml/dist/compose/resolve-block-seq.js"(exports) {
|
|
4090
4090
|
"use strict";
|
|
4091
4091
|
var YAMLSeq = require_YAMLSeq();
|
|
4092
4092
|
var resolveProps = require_resolve_props();
|
|
@@ -4135,9 +4135,9 @@ var require_resolve_block_seq = __commonJS({
|
|
|
4135
4135
|
}
|
|
4136
4136
|
});
|
|
4137
4137
|
|
|
4138
|
-
//
|
|
4138
|
+
// ../../node_modules/yaml/dist/compose/resolve-end.js
|
|
4139
4139
|
var require_resolve_end = __commonJS({
|
|
4140
|
-
"
|
|
4140
|
+
"../../node_modules/yaml/dist/compose/resolve-end.js"(exports) {
|
|
4141
4141
|
"use strict";
|
|
4142
4142
|
function resolveEnd(end, offset, reqSpace, onError) {
|
|
4143
4143
|
let comment = "";
|
|
@@ -4178,9 +4178,9 @@ var require_resolve_end = __commonJS({
|
|
|
4178
4178
|
}
|
|
4179
4179
|
});
|
|
4180
4180
|
|
|
4181
|
-
//
|
|
4181
|
+
// ../../node_modules/yaml/dist/compose/resolve-flow-collection.js
|
|
4182
4182
|
var require_resolve_flow_collection = __commonJS({
|
|
4183
|
-
"
|
|
4183
|
+
"../../node_modules/yaml/dist/compose/resolve-flow-collection.js"(exports) {
|
|
4184
4184
|
"use strict";
|
|
4185
4185
|
var identity = require_identity();
|
|
4186
4186
|
var Pair = require_Pair();
|
|
@@ -4372,9 +4372,9 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
4372
4372
|
}
|
|
4373
4373
|
});
|
|
4374
4374
|
|
|
4375
|
-
//
|
|
4375
|
+
// ../../node_modules/yaml/dist/compose/compose-collection.js
|
|
4376
4376
|
var require_compose_collection = __commonJS({
|
|
4377
|
-
"
|
|
4377
|
+
"../../node_modules/yaml/dist/compose/compose-collection.js"(exports) {
|
|
4378
4378
|
"use strict";
|
|
4379
4379
|
var identity = require_identity();
|
|
4380
4380
|
var Scalar = require_Scalar();
|
|
@@ -4437,9 +4437,9 @@ var require_compose_collection = __commonJS({
|
|
|
4437
4437
|
}
|
|
4438
4438
|
});
|
|
4439
4439
|
|
|
4440
|
-
//
|
|
4440
|
+
// ../../node_modules/yaml/dist/compose/resolve-block-scalar.js
|
|
4441
4441
|
var require_resolve_block_scalar = __commonJS({
|
|
4442
|
-
"
|
|
4442
|
+
"../../node_modules/yaml/dist/compose/resolve-block-scalar.js"(exports) {
|
|
4443
4443
|
"use strict";
|
|
4444
4444
|
var Scalar = require_Scalar();
|
|
4445
4445
|
function resolveBlockScalar(ctx, scalar, onError) {
|
|
@@ -4620,9 +4620,9 @@ var require_resolve_block_scalar = __commonJS({
|
|
|
4620
4620
|
}
|
|
4621
4621
|
});
|
|
4622
4622
|
|
|
4623
|
-
//
|
|
4623
|
+
// ../../node_modules/yaml/dist/compose/resolve-flow-scalar.js
|
|
4624
4624
|
var require_resolve_flow_scalar = __commonJS({
|
|
4625
|
-
"
|
|
4625
|
+
"../../node_modules/yaml/dist/compose/resolve-flow-scalar.js"(exports) {
|
|
4626
4626
|
"use strict";
|
|
4627
4627
|
var Scalar = require_Scalar();
|
|
4628
4628
|
var resolveEnd = require_resolve_end();
|
|
@@ -4841,9 +4841,9 @@ var require_resolve_flow_scalar = __commonJS({
|
|
|
4841
4841
|
}
|
|
4842
4842
|
});
|
|
4843
4843
|
|
|
4844
|
-
//
|
|
4844
|
+
// ../../node_modules/yaml/dist/compose/compose-scalar.js
|
|
4845
4845
|
var require_compose_scalar = __commonJS({
|
|
4846
|
-
"
|
|
4846
|
+
"../../node_modules/yaml/dist/compose/compose-scalar.js"(exports) {
|
|
4847
4847
|
"use strict";
|
|
4848
4848
|
var identity = require_identity();
|
|
4849
4849
|
var Scalar = require_Scalar();
|
|
@@ -4922,9 +4922,9 @@ var require_compose_scalar = __commonJS({
|
|
|
4922
4922
|
}
|
|
4923
4923
|
});
|
|
4924
4924
|
|
|
4925
|
-
//
|
|
4925
|
+
// ../../node_modules/yaml/dist/compose/util-empty-scalar-position.js
|
|
4926
4926
|
var require_util_empty_scalar_position = __commonJS({
|
|
4927
|
-
"
|
|
4927
|
+
"../../node_modules/yaml/dist/compose/util-empty-scalar-position.js"(exports) {
|
|
4928
4928
|
"use strict";
|
|
4929
4929
|
function emptyScalarPosition(offset, before, pos) {
|
|
4930
4930
|
if (before) {
|
|
@@ -4952,9 +4952,9 @@ var require_util_empty_scalar_position = __commonJS({
|
|
|
4952
4952
|
}
|
|
4953
4953
|
});
|
|
4954
4954
|
|
|
4955
|
-
//
|
|
4955
|
+
// ../../node_modules/yaml/dist/compose/compose-node.js
|
|
4956
4956
|
var require_compose_node = __commonJS({
|
|
4957
|
-
"
|
|
4957
|
+
"../../node_modules/yaml/dist/compose/compose-node.js"(exports) {
|
|
4958
4958
|
"use strict";
|
|
4959
4959
|
var Alias = require_Alias();
|
|
4960
4960
|
var identity = require_identity();
|
|
@@ -5058,9 +5058,9 @@ var require_compose_node = __commonJS({
|
|
|
5058
5058
|
}
|
|
5059
5059
|
});
|
|
5060
5060
|
|
|
5061
|
-
//
|
|
5061
|
+
// ../../node_modules/yaml/dist/compose/compose-doc.js
|
|
5062
5062
|
var require_compose_doc = __commonJS({
|
|
5063
|
-
"
|
|
5063
|
+
"../../node_modules/yaml/dist/compose/compose-doc.js"(exports) {
|
|
5064
5064
|
"use strict";
|
|
5065
5065
|
var Document = require_Document();
|
|
5066
5066
|
var composeNode = require_compose_node();
|
|
@@ -5101,9 +5101,9 @@ var require_compose_doc = __commonJS({
|
|
|
5101
5101
|
}
|
|
5102
5102
|
});
|
|
5103
5103
|
|
|
5104
|
-
//
|
|
5104
|
+
// ../../node_modules/yaml/dist/compose/composer.js
|
|
5105
5105
|
var require_composer = __commonJS({
|
|
5106
|
-
"
|
|
5106
|
+
"../../node_modules/yaml/dist/compose/composer.js"(exports) {
|
|
5107
5107
|
"use strict";
|
|
5108
5108
|
var node_process = __require("process");
|
|
5109
5109
|
var directives = require_directives();
|
|
@@ -5309,9 +5309,9 @@ ${end.comment}` : end.comment;
|
|
|
5309
5309
|
}
|
|
5310
5310
|
});
|
|
5311
5311
|
|
|
5312
|
-
//
|
|
5312
|
+
// ../../node_modules/yaml/dist/parse/cst-scalar.js
|
|
5313
5313
|
var require_cst_scalar = __commonJS({
|
|
5314
|
-
"
|
|
5314
|
+
"../../node_modules/yaml/dist/parse/cst-scalar.js"(exports) {
|
|
5315
5315
|
"use strict";
|
|
5316
5316
|
var resolveBlockScalar = require_resolve_block_scalar();
|
|
5317
5317
|
var resolveFlowScalar = require_resolve_flow_scalar();
|
|
@@ -5494,9 +5494,9 @@ var require_cst_scalar = __commonJS({
|
|
|
5494
5494
|
}
|
|
5495
5495
|
});
|
|
5496
5496
|
|
|
5497
|
-
//
|
|
5497
|
+
// ../../node_modules/yaml/dist/parse/cst-stringify.js
|
|
5498
5498
|
var require_cst_stringify = __commonJS({
|
|
5499
|
-
"
|
|
5499
|
+
"../../node_modules/yaml/dist/parse/cst-stringify.js"(exports) {
|
|
5500
5500
|
"use strict";
|
|
5501
5501
|
var stringify = (cst) => "type" in cst ? stringifyToken(cst) : stringifyItem(cst);
|
|
5502
5502
|
function stringifyToken(token) {
|
|
@@ -5555,9 +5555,9 @@ var require_cst_stringify = __commonJS({
|
|
|
5555
5555
|
}
|
|
5556
5556
|
});
|
|
5557
5557
|
|
|
5558
|
-
//
|
|
5558
|
+
// ../../node_modules/yaml/dist/parse/cst-visit.js
|
|
5559
5559
|
var require_cst_visit = __commonJS({
|
|
5560
|
-
"
|
|
5560
|
+
"../../node_modules/yaml/dist/parse/cst-visit.js"(exports) {
|
|
5561
5561
|
"use strict";
|
|
5562
5562
|
var BREAK = /* @__PURE__ */ Symbol("break visit");
|
|
5563
5563
|
var SKIP2 = /* @__PURE__ */ Symbol("skip children");
|
|
@@ -5617,9 +5617,9 @@ var require_cst_visit = __commonJS({
|
|
|
5617
5617
|
}
|
|
5618
5618
|
});
|
|
5619
5619
|
|
|
5620
|
-
//
|
|
5620
|
+
// ../../node_modules/yaml/dist/parse/cst.js
|
|
5621
5621
|
var require_cst = __commonJS({
|
|
5622
|
-
"
|
|
5622
|
+
"../../node_modules/yaml/dist/parse/cst.js"(exports) {
|
|
5623
5623
|
"use strict";
|
|
5624
5624
|
var cstScalar = require_cst_scalar();
|
|
5625
5625
|
var cstStringify = require_cst_stringify();
|
|
@@ -5719,9 +5719,9 @@ var require_cst = __commonJS({
|
|
|
5719
5719
|
}
|
|
5720
5720
|
});
|
|
5721
5721
|
|
|
5722
|
-
//
|
|
5722
|
+
// ../../node_modules/yaml/dist/parse/lexer.js
|
|
5723
5723
|
var require_lexer = __commonJS({
|
|
5724
|
-
"
|
|
5724
|
+
"../../node_modules/yaml/dist/parse/lexer.js"(exports) {
|
|
5725
5725
|
"use strict";
|
|
5726
5726
|
var cst = require_cst();
|
|
5727
5727
|
function isEmpty(ch) {
|
|
@@ -6308,9 +6308,9 @@ var require_lexer = __commonJS({
|
|
|
6308
6308
|
}
|
|
6309
6309
|
});
|
|
6310
6310
|
|
|
6311
|
-
//
|
|
6311
|
+
// ../../node_modules/yaml/dist/parse/line-counter.js
|
|
6312
6312
|
var require_line_counter = __commonJS({
|
|
6313
|
-
"
|
|
6313
|
+
"../../node_modules/yaml/dist/parse/line-counter.js"(exports) {
|
|
6314
6314
|
"use strict";
|
|
6315
6315
|
var LineCounter = class {
|
|
6316
6316
|
constructor() {
|
|
@@ -6339,9 +6339,9 @@ var require_line_counter = __commonJS({
|
|
|
6339
6339
|
}
|
|
6340
6340
|
});
|
|
6341
6341
|
|
|
6342
|
-
//
|
|
6342
|
+
// ../../node_modules/yaml/dist/parse/parser.js
|
|
6343
6343
|
var require_parser = __commonJS({
|
|
6344
|
-
"
|
|
6344
|
+
"../../node_modules/yaml/dist/parse/parser.js"(exports) {
|
|
6345
6345
|
"use strict";
|
|
6346
6346
|
var node_process = __require("process");
|
|
6347
6347
|
var cst = require_cst();
|
|
@@ -7213,9 +7213,9 @@ var require_parser = __commonJS({
|
|
|
7213
7213
|
}
|
|
7214
7214
|
});
|
|
7215
7215
|
|
|
7216
|
-
//
|
|
7216
|
+
// ../../node_modules/yaml/dist/public-api.js
|
|
7217
7217
|
var require_public_api = __commonJS({
|
|
7218
|
-
"
|
|
7218
|
+
"../../node_modules/yaml/dist/public-api.js"(exports) {
|
|
7219
7219
|
"use strict";
|
|
7220
7220
|
var composer = require_composer();
|
|
7221
7221
|
var Document = require_Document();
|
|
@@ -7310,9 +7310,9 @@ var require_public_api = __commonJS({
|
|
|
7310
7310
|
}
|
|
7311
7311
|
});
|
|
7312
7312
|
|
|
7313
|
-
//
|
|
7313
|
+
// ../../node_modules/yaml/dist/index.js
|
|
7314
7314
|
var require_dist = __commonJS({
|
|
7315
|
-
"
|
|
7315
|
+
"../../node_modules/yaml/dist/index.js"(exports) {
|
|
7316
7316
|
"use strict";
|
|
7317
7317
|
var composer = require_composer();
|
|
7318
7318
|
var Document = require_Document();
|
|
@@ -8478,7 +8478,7 @@ async function postLong(path, body, timeoutMs = 9e5) {
|
|
|
8478
8478
|
const req = httpsRequest(`${base}${path}`, {
|
|
8479
8479
|
method: "POST",
|
|
8480
8480
|
timeout: timeoutMs,
|
|
8481
|
-
headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.
|
|
8481
|
+
headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.69.0"}`, "content-type": "application/json", "content-length": Buffer.byteLength(data) }
|
|
8482
8482
|
}, (res) => {
|
|
8483
8483
|
let buf = "";
|
|
8484
8484
|
res.on("data", (c) => buf += c);
|
|
@@ -8520,7 +8520,7 @@ async function request(path, opts = {}, retried = false) {
|
|
|
8520
8520
|
method: opts.method ?? (opts.body !== void 0 || opts.raw !== void 0 ? "POST" : "GET"),
|
|
8521
8521
|
headers: {
|
|
8522
8522
|
authorization: `Bearer ${token}`,
|
|
8523
|
-
"user-agent": `ghosty-cli/${"0.
|
|
8523
|
+
"user-agent": `ghosty-cli/${"0.69.0"}`,
|
|
8524
8524
|
"accept-language": lang(),
|
|
8525
8525
|
...opts.body !== void 0 ? { "content-type": "application/json" } : {},
|
|
8526
8526
|
...opts.headers
|
|
@@ -10492,7 +10492,7 @@ async function call(path, v, init = {}) {
|
|
|
10492
10492
|
"x-ghosty-ts": ts,
|
|
10493
10493
|
"x-ghosty-sig": sig,
|
|
10494
10494
|
"content-type": "application/json",
|
|
10495
|
-
"user-agent": `ghosty-cli/${"0.
|
|
10495
|
+
"user-agent": `ghosty-cli/${"0.69.0"}`
|
|
10496
10496
|
},
|
|
10497
10497
|
body: method === "GET" ? void 0 : raw
|
|
10498
10498
|
});
|
|
@@ -12109,195 +12109,595 @@ ${t(`Archive ${plan.matched} card(s) on \xAB${plan.board}\xBB? (reversible: a ne
|
|
|
12109
12109
|
out(r, () => `${lavender("\u2713")} ${t(`Archived ${r.archived} card(s) on \xAB${r.board}\xBB.`, `Se archivaron ${r.archived} tarjeta(s) en \xAB${r.board}\xBB.`)}`);
|
|
12110
12110
|
}
|
|
12111
12111
|
|
|
12112
|
-
// src/commands/
|
|
12112
|
+
// src/commands/spaces.ts
|
|
12113
12113
|
var enc9 = encodeURIComponent;
|
|
12114
|
-
|
|
12115
|
-
|
|
12116
|
-
|
|
12117
|
-
|
|
12114
|
+
var wsPath = (slug, rest = "") => `/api/v2/workspaces/${enc9(slug)}${rest}`;
|
|
12115
|
+
var needSpace = (slug, example) => {
|
|
12116
|
+
if (!slug) throw usage(t("Which workspace?", "\xBFQu\xE9 espacio?"), `${t("Example", "Ejemplo")}: ${example} ${t("(or ghosty use <workspace>)", "(o ghosty use <espacio>)")}`);
|
|
12117
|
+
return slug;
|
|
12118
|
+
};
|
|
12119
|
+
function parseTokens(raw) {
|
|
12120
|
+
const m = /^\s*(\d+(?:\.\d+)?)\s*([kKmM]?)\s*$/.exec(raw);
|
|
12121
|
+
if (!m) throw usage(t(`Bad token amount: ${raw}.`, `Cantidad de tokens inv\xE1lida: ${raw}.`), t("Use 20M, 500k or a plain number.", "Usa 20M, 500k o un n\xFAmero."));
|
|
12122
|
+
const n = Number(m[1]) * (m[2].toLowerCase() === "m" ? 1e6 : m[2].toLowerCase() === "k" ? 1e3 : 1);
|
|
12123
|
+
return Math.round(n);
|
|
12124
|
+
}
|
|
12125
|
+
function fmtTokens(n) {
|
|
12126
|
+
if (n >= 1e6) return `${+(n / 1e6).toFixed(n % 1e6 === 0 ? 0 : 1)}M`;
|
|
12127
|
+
if (n >= 1e3) return `${Math.round(n / 1e3)}k`;
|
|
12128
|
+
return String(n);
|
|
12129
|
+
}
|
|
12130
|
+
function parseSwitch(flag, raw) {
|
|
12131
|
+
if (raw === void 0) return void 0;
|
|
12132
|
+
if (/^(on|true|yes|s[ií])$/i.test(raw)) return true;
|
|
12133
|
+
if (/^(off|false|no)$/i.test(raw)) return false;
|
|
12134
|
+
throw usage(t(`${flag} takes on or off.`, `${flag} acepta on u off.`));
|
|
12135
|
+
}
|
|
12136
|
+
async function enginesCmd(sub, v) {
|
|
12137
|
+
if (sub && sub !== "ls" && sub !== "list") throw usage(t(`Unknown engines subcommand: ${sub}.`, `Subcomando de engines desconocido: ${sub}.`), "ghosty engines ls [--models]");
|
|
12138
|
+
const r = await api("/api/v2/engines");
|
|
12139
|
+
out(r, () => {
|
|
12140
|
+
if (!v.models) {
|
|
12141
|
+
const rows = r.engines.map((e) => ({ engine: e.id, provider: e.provider, default: e.defaultModel ?? "", models: e.models.map((m) => m.id).join(", ") }));
|
|
12142
|
+
return `${table(rows, ["engine", "provider", "default"])}
|
|
12143
|
+
${dim(t("Models per engine: ghosty engines ls --models", "Modelos de cada motor: ghosty engines ls --models"))}`;
|
|
12144
|
+
}
|
|
12145
|
+
return r.engines.map((e) => {
|
|
12146
|
+
const rows = e.models.map((m) => ({ model: m.id + (m.id === e.defaultModel ? " *" : ""), label: m.label, cost: `${m.multiplier}\xD7`, note: m.ownKeyOnly ? t("your own key only", "s\xF3lo con llave propia") : "" }));
|
|
12147
|
+
return `${bold(e.id)} ${dim(`${e.provider} \xB7 ${e.protocol}${e.vision ? t(" \xB7 sees images", " \xB7 ve im\xE1genes") : ""}`)}
|
|
12148
|
+
${table(rows, ["model", "label", "cost", "note"])}`;
|
|
12149
|
+
}).join("\n\n") + `
|
|
12150
|
+
${dim(t("* default \xB7 cost = balance multiplier per turn", "* por default \xB7 costo = multiplicador de saldo por turno"))}`;
|
|
12151
|
+
});
|
|
12152
|
+
}
|
|
12153
|
+
function bagsText(r) {
|
|
12154
|
+
const rows = r.bags.map((b) => ({
|
|
12155
|
+
bag: b.name,
|
|
12156
|
+
tokens: fmtTokens(b.tokens),
|
|
12157
|
+
used: `${fmtTokens(b.used)} (${Math.round(b.ratio * 100)}%)`,
|
|
12158
|
+
kind: b.recurring ? t("monthly", "mensual") : t(`one-time since ${b.since?.slice(0, 10)}`, `carga \xFAnica desde ${b.since?.slice(0, 10)}`),
|
|
12159
|
+
cap: b.hardCap ? t("cuts", "corta") : t("warns", "avisa"),
|
|
12160
|
+
agents: b.agents.map((a) => a.name ?? a.id).join(", ") || "\u2014"
|
|
12161
|
+
}));
|
|
12162
|
+
const free = r.unbagged.length ? `
|
|
12163
|
+
${dim(t(`Workspace balance (no bag): ${r.unbagged.map((a) => a.name ?? a.id).join(", ")}`, `Saldo del espacio (sin bolsa): ${r.unbagged.map((a) => a.name ?? a.id).join(", ")}`))}` : "";
|
|
12164
|
+
return `${bold(r.workspace)}
|
|
12165
|
+
${r.bags.length ? table(rows, ["bag", "tokens", "used", "kind", "cap", "agents"]) : dim(t("No bags: every agent uses the workspace balance.", "Sin bolsas: todos los agentes usan el saldo del espacio."))}${free}`;
|
|
12166
|
+
}
|
|
12167
|
+
async function bagsCmd(sub, slug, name, v, context) {
|
|
12168
|
+
const ex = 'ghosty bags ls <workspace> \xB7 create <workspace> "<bag>" --tokens 20M [--recurring off] \xB7 set <workspace> "<bag>" --tokens 30M \xB7 rm <workspace> "<bag>"';
|
|
12169
|
+
if (sub && !["ls", "list", "create", "new", "set", "rm", "delete"].includes(sub)) {
|
|
12170
|
+
name = slug;
|
|
12171
|
+
slug = sub;
|
|
12172
|
+
sub = "ls";
|
|
12118
12173
|
}
|
|
12174
|
+
slug = needSpace(slug ?? context, ex);
|
|
12175
|
+
const recurring = parseSwitch("--recurring", v.recurring);
|
|
12176
|
+
const hardCap = parseSwitch("--hard-cap", v["hard-cap"]);
|
|
12119
12177
|
switch (sub ?? "ls") {
|
|
12120
12178
|
case "ls":
|
|
12121
12179
|
case "list": {
|
|
12122
|
-
|
|
12123
|
-
|
|
12124
|
-
const rows = r.boards.map((b) => ({ name: b.main ? `${b.name} (${t("main", "principal")})` : b.name, cards: b.cards, agents: b.agents.map((x) => x.name ?? x.id).join(", "), columns: b.columns.length, id: b.id }));
|
|
12125
|
-
return out(r, () => table(rows, ["name", "cards", "agents", "columns", "id"]));
|
|
12126
|
-
}
|
|
12127
|
-
case "create": {
|
|
12128
|
-
if (!a1 || !a2) throw usage(t("Missing workspace or name.", "Falta el espacio o el nombre."), t("Example", "Ejemplo") + ': ghosty boards create <workspace> "Siiqtec - Ixmiquilpan" --columns-from main');
|
|
12129
|
-
const r = await api(`/api/v2/workspaces/${enc9(a1)}/boards`, { method: "POST", body: { name: a2, ...v["columns-from"] ? { columnsFrom: v["columns-from"] } : {} } });
|
|
12130
|
-
return out(r, () => `${lavender("\u2713")} ${t(`Board \xAB${r.name}\xBB created${r.columnsFrom ? ` with the ${r.columns} column(s) of \xAB${r.columnsFrom}\xBB` : ""}.`, `Tablero \xAB${r.name}\xBB creado${r.columnsFrom ? ` con las ${r.columns} columna(s) de \xAB${r.columnsFrom}\xBB` : ""}.`)} ${dim(`${t("Send an agent's cards there", "Manda ah\xED las tarjetas de un agente")}: ghosty boards assign <agent-id> "${r.name}"`)}${r.warning ? `
|
|
12131
|
-
${lavender(`\u26A0\uFE0F ${serverText(r.warning)}`)}` : ""}`);
|
|
12180
|
+
const r = await api(wsPath(slug, "/bags"));
|
|
12181
|
+
return out(r, () => bagsText(r));
|
|
12132
12182
|
}
|
|
12133
|
-
case "
|
|
12134
|
-
|
|
12135
|
-
|
|
12136
|
-
|
|
12137
|
-
const r = await api(
|
|
12138
|
-
return out(r, () => `${lavender("\u2713")} ${t(`
|
|
12183
|
+
case "create":
|
|
12184
|
+
case "new": {
|
|
12185
|
+
if (!name) throw usage(t("Missing the bag's name.", "Falta el nombre de la bolsa."), ex);
|
|
12186
|
+
if (!v.tokens) throw usage(t("Missing --tokens.", "Falta --tokens."), `ghosty bags create ${slug} "${name}" --tokens 20M`);
|
|
12187
|
+
const r = await api(wsPath(slug, "/bags"), { method: "POST", body: { name, tokens: parseTokens(v.tokens), ...recurring !== void 0 ? { recurring } : {}, ...hardCap !== void 0 ? { hardCap } : {}, ...v.note ? { note: v.note } : {} } });
|
|
12188
|
+
return out(r, () => `${lavender("\u2713")} ${t(`Bag \xAB${name}\xBB created.`, `Bolsa \xAB${name}\xBB creada.`)} ${dim(t(`Give it agents: ghosty agents set <agent> --bag "${name}"`, `Cu\xE9lgale agentes: ghosty agents set <agente> --bag "${name}"`))}
|
|
12189
|
+
${bagsText(r)}`);
|
|
12139
12190
|
}
|
|
12140
|
-
case "
|
|
12141
|
-
if (!
|
|
12142
|
-
const
|
|
12143
|
-
|
|
12191
|
+
case "set": {
|
|
12192
|
+
if (!name) throw usage(t("Missing the bag's name.", "Falta el nombre de la bolsa."), ex);
|
|
12193
|
+
const body = { ...v.tokens ? { tokens: parseTokens(v.tokens) } : {}, ...recurring !== void 0 ? { recurring } : {}, ...hardCap !== void 0 ? { hardCap } : {}, ...v.note !== void 0 ? { note: v.note } : {}, ...v.name ? { name: v.name } : {} };
|
|
12194
|
+
if (!Object.keys(body).length) throw usage(t("Nothing to change.", "Nada que cambiar."), "--tokens 30M | --recurring on|off | --hard-cap on|off | --note TEXT | --name NEW");
|
|
12195
|
+
const r = await api(wsPath(slug, `/bags/${enc9(name)}`), { method: "PATCH", body });
|
|
12196
|
+
return out(r, () => `${lavender("\u2713")} ${t(`Bag \xAB${r.updated}\xBB updated.`, `Bolsa \xAB${r.updated}\xBB actualizada.`)}
|
|
12197
|
+
${bagsText(r)}`);
|
|
12144
12198
|
}
|
|
12145
|
-
case "
|
|
12146
|
-
|
|
12147
|
-
if (!
|
|
12148
|
-
|
|
12149
|
-
|
|
12150
|
-
const
|
|
12151
|
-
|
|
12152
|
-
|
|
12153
|
-
const sample = table(plan.sample.map((c) => ({ folio: c.folio ? `#${c.folio}` : "", name: c.name ?? "", phone: c.phone })), ["folio", "name", "phone"]);
|
|
12154
|
-
const text = `${sample}
|
|
12155
|
-
${t(`${plan.moved} of ${plan.matched} card(s)`, `${plan.moved} de ${plan.matched} tarjeta(s)`)} \xAB${plan.from}\xBB \u2192 \xAB${plan.to}\xBB${plan.skipped.length ? dim(t(` \xB7 ${plan.skipped.length} already in \xAB${plan.to}\xBB, skipped`, ` \xB7 ${plan.skipped.length} ya en \xAB${plan.to}\xBB, se omiten`)) : ""}`;
|
|
12156
|
-
if (v["dry-run"] || !plan.moved) return out(plan, () => `${text}
|
|
12157
|
-
${dim(t("Dry run: nothing changed.", "Simulacro: no se cambi\xF3 nada."))}`);
|
|
12158
|
-
await confirm(`${text}
|
|
12159
|
-
${t("Move them with their threads and orders? (they get a new folio there)", "\xBFMoverlas con sus hilos y pedidos? (all\xE1 reciben folio nuevo)")}`, { yes: v.yes, retry });
|
|
12160
|
-
const r = await api(path, { method: "POST", body });
|
|
12161
|
-
return out(r, () => `${lavender("\u2713")} ${t(`Moved ${r.moved} card(s) (${r.messages} message(s), ${r.orders} order(s)) to \xAB${r.to}\xBB.`, `Se movieron ${r.moved} tarjeta(s) (${r.messages} mensaje(s), ${r.orders} pedido(s)) a \xAB${r.to}\xBB.`)}${r.skipped.length ? dim(t(` Skipped ${r.skipped.length}.`, ` Se omitieron ${r.skipped.length}.`)) : ""}`);
|
|
12199
|
+
case "rm":
|
|
12200
|
+
case "delete": {
|
|
12201
|
+
if (!name) throw usage(t("Missing the bag's name.", "Falta el nombre de la bolsa."), ex);
|
|
12202
|
+
requireYesIfHeadless(v.yes, `ghosty bags rm ${slug} "${name}"`);
|
|
12203
|
+
await confirm(t(`Delete bag \xAB${name}\xBB from ${slug}? (only if no agent uses it)`, `\xBFBorrar la bolsa \xAB${name}\xBB de ${slug}? (s\xF3lo si ning\xFAn agente la usa)`), { yes: v.yes, retry: `ghosty bags rm ${slug} "${name}"` });
|
|
12204
|
+
const r = await api(wsPath(slug, `/bags/${enc9(name)}`), { method: "DELETE" });
|
|
12205
|
+
return out(r, () => `${lavender("\u2713")} ${t(`Bag \xAB${r.deleted}\xBB deleted.`, `Bolsa \xAB${r.deleted}\xBB borrada.`)}
|
|
12206
|
+
${bagsText(r)}`);
|
|
12162
12207
|
}
|
|
12163
|
-
default:
|
|
12164
|
-
throw usage(t(`Unknown boards subcommand: ${sub}.`, `Subcomando de boards desconocido: ${sub}.`), t("Try", "Prueba") + ": ghosty boards ls | create | assign | move-cards | rm");
|
|
12165
12208
|
}
|
|
12166
12209
|
}
|
|
12167
|
-
|
|
12168
|
-
|
|
12169
|
-
|
|
12170
|
-
|
|
12171
|
-
|
|
12172
|
-
|
|
12173
|
-
|
|
12174
|
-
|
|
12175
|
-
|
|
12176
|
-
|
|
12177
|
-
|
|
12178
|
-
|
|
12179
|
-
|
|
12180
|
-
|
|
12181
|
-
|
|
12182
|
-
|
|
12183
|
-
|
|
12184
|
-
|
|
12185
|
-
|
|
12186
|
-
|
|
12187
|
-
|
|
12188
|
-
|
|
12189
|
-
|
|
12190
|
-
|
|
12191
|
-
|
|
12192
|
-
|
|
12193
|
-
|
|
12194
|
-
|
|
12195
|
-
|
|
12196
|
-
|
|
12197
|
-
|
|
12198
|
-
|
|
12199
|
-
|
|
12200
|
-
|
|
12201
|
-
|
|
12202
|
-
|
|
12203
|
-
|
|
12204
|
-
|
|
12205
|
-
|
|
12206
|
-
|
|
12207
|
-
|
|
12208
|
-
|
|
12209
|
-
|
|
12210
|
-
|
|
12211
|
-
|
|
12212
|
-
|
|
12213
|
-
|
|
12214
|
-
|
|
12215
|
-
|
|
12216
|
-
|
|
12217
|
-
|
|
12218
|
-
|
|
12219
|
-
|
|
12220
|
-
|
|
12221
|
-
|
|
12222
|
-
|
|
12223
|
-
|
|
12224
|
-
|
|
12225
|
-
|
|
12226
|
-
|
|
12227
|
-
|
|
12228
|
-
|
|
12229
|
-
|
|
12230
|
-
|
|
12231
|
-
|
|
12232
|
-
|
|
12233
|
-
|
|
12234
|
-
|
|
12235
|
-
|
|
12236
|
-
|
|
12237
|
-
|
|
12238
|
-
|
|
12239
|
-
|
|
12240
|
-
|
|
12241
|
-
|
|
12242
|
-
|
|
12243
|
-
|
|
12244
|
-
|
|
12245
|
-
|
|
12246
|
-
|
|
12247
|
-
|
|
12248
|
-
|
|
12249
|
-
|
|
12250
|
-
|
|
12251
|
-
|
|
12252
|
-
|
|
12253
|
-
|
|
12254
|
-
|
|
12255
|
-
|
|
12256
|
-
|
|
12257
|
-
|
|
12258
|
-
|
|
12259
|
-
|
|
12260
|
-
|
|
12261
|
-
|
|
12262
|
-
|
|
12263
|
-
|
|
12264
|
-
|
|
12265
|
-
|
|
12266
|
-
|
|
12267
|
-
|
|
12268
|
-
|
|
12269
|
-
|
|
12270
|
-
|
|
12271
|
-
|
|
12272
|
-
|
|
12273
|
-
|
|
12274
|
-
|
|
12275
|
-
|
|
12276
|
-
"
|
|
12277
|
-
|
|
12278
|
-
}
|
|
12279
|
-
|
|
12280
|
-
|
|
12281
|
-
|
|
12282
|
-
|
|
12283
|
-
|
|
12284
|
-
|
|
12285
|
-
|
|
12286
|
-
|
|
12287
|
-
|
|
12288
|
-
|
|
12289
|
-
|
|
12290
|
-
|
|
12291
|
-
|
|
12292
|
-
|
|
12293
|
-
|
|
12294
|
-
|
|
12295
|
-
|
|
12296
|
-
|
|
12297
|
-
|
|
12298
|
-
|
|
12299
|
-
|
|
12300
|
-
|
|
12210
|
+
async function spacesCmd(sub, slug, arg, v, context) {
|
|
12211
|
+
const ex = "ghosty spaces ls [--user EMAIL] \xB7 create <slug> [--combo teams|sales|both|none] [--dry-run] \xB7 join|leave <workspace> \xB7 set <workspace> --combo teams|sales|both|none | --model-cap 0.25|1|4|none | --house-claude on|off \xB7 renew <workspace> --until 2026-11-01 [--note TEXT] \xB7 rename <old> <new> [--dry-run] \xB7 archive|restore <workspace> [--dry-run] \xB7 transfer <workspace> --to EMAIL [--keep-as admin|member|none] [--copy-keys] [--dry-run] \xB7 log <workspace> [--since 30d] [--action workspace]";
|
|
12212
|
+
if (!sub || sub === "ls" || sub === "list") {
|
|
12213
|
+
const r = await api(`/api/v2/workspaces${v.user ? `?user=${enc9(v.user)}` : ""}`);
|
|
12214
|
+
const rows = r.workspaces.map((w) => ({ workspace: w.slug, role: w.role ?? "", plan: w.plan, combo: w.combo, owner: w.owner ?? "", paid: w.paidUntil ?? "" }));
|
|
12215
|
+
return out(r, () => rows.length ? `${bold(r.user)}
|
|
12216
|
+
${table(rows, ["workspace", "role", "plan", "combo", "owner", "paid"])}` : dim(t(`${r.user} has no workspaces.`, `${r.user} no tiene espacios.`)));
|
|
12217
|
+
}
|
|
12218
|
+
if (sub === "create") {
|
|
12219
|
+
slug = needSpace(slug, "ghosty spaces create <slug> [--combo teams|sales|both|none] [--dry-run]");
|
|
12220
|
+
const r = await api("/api/v2/workspaces", { method: "POST", body: { slug, ...v.combo ? { combo: v.combo } : {}, ...v["dry-run"] ? { dryRun: true } : {} } });
|
|
12221
|
+
const line2 = `${r.workspace} \xB7 ${r.owner} \xB7 ${r.plan} \xB7 ${r.combo}`;
|
|
12222
|
+
if (!r.created) return out(r, () => `${line2}
|
|
12223
|
+
${dim(t("Dry run: nothing created.", "Simulaci\xF3n: no se cre\xF3 nada."))}`);
|
|
12224
|
+
return out(r, () => `${lavender("\u2713")} ${line2}
|
|
12225
|
+
${dim(t(`Next: ghosty use ${r.workspace} \xB7 ghosty partner enable ${r.workspace}`, `Sigue: ghosty use ${r.workspace} \xB7 ghosty partner enable ${r.workspace}`))}`);
|
|
12226
|
+
}
|
|
12227
|
+
if (sub === "log") {
|
|
12228
|
+
slug = needSpace(slug, "ghosty spaces log <workspace> [--since 30d] [--action workspace]");
|
|
12229
|
+
const q = new URLSearchParams({ limit: v.limit ?? "50" });
|
|
12230
|
+
if (v.since) q.set("since", v.since);
|
|
12231
|
+
if (v.action) q.set("action", v.action);
|
|
12232
|
+
const r = await api(wsPath(slug, `/log?${q}`));
|
|
12233
|
+
const rows = r.events.map((e) => ({ at: e.at.slice(0, 16).replace("T", " "), actor: e.actor, action: e.action, detail: serverText(e.detail ? JSON.stringify(e.detail) : "").slice(0, 110) }));
|
|
12234
|
+
return out(r, () => rows.length ? table(rows, ["at", "actor", "action", "detail"]) : dim(t(`No events in ${r.workspace}${v.since ? ` since ${v.since}` : ""}.`, `Sin eventos en ${r.workspace}${v.since ? ` desde ${v.since}` : ""}.`)));
|
|
12235
|
+
}
|
|
12236
|
+
if (sub === "join" || sub === "leave") {
|
|
12237
|
+
slug = needSpace(slug, `ghosty spaces ${sub} <workspace>`);
|
|
12238
|
+
const r = await api(wsPath(slug, "/staff"), { method: "POST", body: { join: sub === "join" } });
|
|
12239
|
+
return out(r, () => `${lavender("\u2713")} ${r.joined ? t(`You're in ${r.workspace} as staff (no seat; logged). Leave: ghosty spaces leave ${r.workspace}`, `Entraste a ${r.workspace} como staff (sin asiento; queda en bit\xE1cora). Salir: ghosty spaces leave ${r.workspace}`) : t(`You left ${r.workspace}.`, `Saliste de ${r.workspace}.`)}`);
|
|
12240
|
+
}
|
|
12241
|
+
if (sub === "set") {
|
|
12242
|
+
slug = needSpace(slug ?? context, "ghosty spaces set <workspace> --combo sales | --model-cap 4");
|
|
12243
|
+
const cap = v["model-cap"];
|
|
12244
|
+
const house = parseSwitch("--house-claude", v["house-claude"]);
|
|
12245
|
+
if (!v.combo && cap === void 0 && house === void 0) throw usage(t("Nothing to change.", "Nada que cambiar."), "--combo teams|sales|both|none \xB7 --model-cap 0.25|1|4|none \xB7 --house-claude on|off");
|
|
12246
|
+
const steps = [];
|
|
12247
|
+
if (v.combo) steps.push({ label: "combo", path: wsPath(slug, "/combo"), body: { combo: v.combo } });
|
|
12248
|
+
if (cap !== void 0) steps.push({ label: "model-cap", path: wsPath(slug, "/model-cap"), body: { cap } });
|
|
12249
|
+
if (house !== void 0) steps.push({ label: "house-claude", path: wsPath(slug, "/house-claude"), body: { on: house } });
|
|
12250
|
+
const show2 = (x) => x === null ? t("plan's", "el del plan") : x === true ? "on" : x === false ? "off" : String(x);
|
|
12251
|
+
const plans = await Promise.all(steps.map(async (st) => ({ ...st, plan: await api(st.path, { method: "POST", body: { ...st.body, dryRun: true } }) })));
|
|
12252
|
+
const lines = plans.map((p) => `${p.plan.workspace}: ${p.label} ${show2(p.plan.from)} \u2192 ${show2(p.plan.to)}`);
|
|
12253
|
+
const pending = plans.filter((p) => p.plan.changed);
|
|
12254
|
+
if (!pending.length) return out(plans.map((p) => p.plan), () => dim(t(`Nothing to do: ${slug} already has that.`, `Nada que hacer: ${slug} ya lo tiene.`)));
|
|
12255
|
+
if (v["dry-run"]) return out(plans.map((p) => p.plan), () => `${lines.join("\n")}
|
|
12256
|
+
${dim(t("Dry run: nothing changed.", "Simulaci\xF3n: no cambi\xF3 nada."))}`);
|
|
12257
|
+
const retry = `ghosty spaces set ${slug}${v.combo ? ` --combo ${v.combo}` : ""}${cap !== void 0 ? ` --model-cap ${cap}` : ""}${house !== void 0 ? ` --house-claude ${house ? "on" : "off"}` : ""}`;
|
|
12258
|
+
requireYesIfHeadless(v.yes, retry);
|
|
12259
|
+
await confirm(`${lines.join("\n")}
|
|
12260
|
+
${t("Change it?", "\xBFCambiarlo?")}`, { yes: v.yes, retry });
|
|
12261
|
+
const done = [];
|
|
12262
|
+
for (const p of pending) done.push(await api(p.path, { method: "POST", body: p.body }));
|
|
12263
|
+
return out(done, () => done.map((r, i) => `${lavender("\u2713")} ${r.workspace}: ${pending[i].label} ${show2(r.to)}`).join("\n"));
|
|
12264
|
+
}
|
|
12265
|
+
if (sub === "renew") {
|
|
12266
|
+
slug = needSpace(slug ?? context, ex);
|
|
12267
|
+
if (!v.until) throw usage(t("Missing --until YYYY-MM-DD.", "Falta --until AAAA-MM-DD."), `ghosty spaces renew ${slug} --until 2026-11-01`);
|
|
12268
|
+
const path = wsPath(slug, "/renew");
|
|
12269
|
+
const plan = await api(path, { method: "POST", body: { until: v.until, dryRun: true } });
|
|
12270
|
+
const line2 = t(`${plan.workspace} (${plan.plan}): paid until ${plan.from ?? "\u2014"} \u2192 ${plan.to}`, `${plan.workspace} (${plan.plan}): pagado hasta ${plan.from ?? "\u2014"} \u2192 ${plan.to}`);
|
|
12271
|
+
if (v["dry-run"]) return out(plan, () => `${line2}
|
|
12272
|
+
${dim(t("Dry run: nothing changed.", "Simulaci\xF3n: no cambi\xF3 nada."))}`);
|
|
12273
|
+
requireYesIfHeadless(v.yes, `ghosty spaces renew ${slug} --until ${v.until}`);
|
|
12274
|
+
await confirm(`${line2}
|
|
12275
|
+
${t("Renew?", "\xBFRenovar?")}`, { yes: v.yes, retry: `ghosty spaces renew ${slug} --until ${v.until}` });
|
|
12276
|
+
const r = await api(path, { method: "POST", body: { until: v.until, ...v.note ? { note: v.note } : {} } });
|
|
12277
|
+
return out(r, () => `${lavender("\u2713")} ${line2} ${dim(t("(logged in the workspace's audit)", "(queda en la bit\xE1cora del espacio)"))}`);
|
|
12278
|
+
}
|
|
12279
|
+
if (sub === "rename") {
|
|
12280
|
+
slug = needSpace(slug, ex);
|
|
12281
|
+
if (!arg) throw usage(t("Missing the new name.", "Falta el nombre nuevo."), `ghosty spaces rename ${slug} <new> --dry-run`);
|
|
12282
|
+
const path = wsPath(slug, "/rename");
|
|
12283
|
+
const plan = await api(path, { method: "POST", body: { to: arg, dryRun: true } });
|
|
12284
|
+
const text = `${plan.from} \u2192 ${bold(plan.to)}
|
|
12285
|
+
${plan.warnings.map((w) => dim(` \xB7 ${serverText(w)}`)).join("\n")}`;
|
|
12286
|
+
if (v["dry-run"]) return out(plan, () => `${text}
|
|
12287
|
+
${dim(t("Dry run: nothing changed.", "Simulaci\xF3n: no cambi\xF3 nada."))}`);
|
|
12288
|
+
requireYesIfHeadless(v.yes, `ghosty spaces rename ${slug} ${arg}`);
|
|
12289
|
+
await confirm(`${text}
|
|
12290
|
+
${t("Rename?", "\xBFRenombrar?")}`, { yes: v.yes, expect: plan.from, retry: `ghosty spaces rename ${slug} ${arg}` });
|
|
12291
|
+
const r = await api(path, { method: "POST", body: { to: arg } });
|
|
12292
|
+
return out(r, () => `${lavender("\u2713")} ${t(`Renamed: ${r.from} \u2192 ${r.to}. Undo: ghosty spaces rename ${r.to} ${r.from}`, `Renombrado: ${r.from} \u2192 ${r.to}. Deshacer: ghosty spaces rename ${r.to} ${r.from}`)}`);
|
|
12293
|
+
}
|
|
12294
|
+
if (sub === "archive" || sub === "restore") {
|
|
12295
|
+
slug = needSpace(slug, `ghosty spaces ${sub} <workspace> --dry-run`);
|
|
12296
|
+
const archive = sub === "archive";
|
|
12297
|
+
const path = wsPath(slug, "/archive");
|
|
12298
|
+
const plan = await api(path, { method: "POST", body: { archive, dryRun: true } });
|
|
12299
|
+
const line2 = `${plan.slug}: ${plan.from} \u2192 ${bold(plan.to)} ${dim(t(`(${plan.agents} agent(s); they and their data stay as they are)`, `(${plan.agents} agente(s); ellos y sus datos se quedan igual)`))}`;
|
|
12300
|
+
if (!plan.changed) return out(plan, () => dim(t(`Nothing to do: ${plan.slug} is already ${plan.from}.`, `Nada que hacer: ${plan.slug} ya est\xE1 ${plan.from}.`)));
|
|
12301
|
+
if (v["dry-run"]) return out(plan, () => `${line2}
|
|
12302
|
+
${dim(t("Dry run: nothing changed.", "Simulaci\xF3n: no cambi\xF3 nada."))}`);
|
|
12303
|
+
const retry = `ghosty spaces ${sub} ${slug}`;
|
|
12304
|
+
requireYesIfHeadless(v.yes, retry);
|
|
12305
|
+
await confirm(`${line2}
|
|
12306
|
+
${archive ? t("Archive it?", "\xBFArchivarlo?") : t("Restore it?", "\xBFRestaurarlo?")}`, { yes: v.yes, retry, ...archive ? { expect: plan.slug } : {} });
|
|
12307
|
+
const r = await api(path, { method: "POST", body: { archive } });
|
|
12308
|
+
return out(r, () => archive ? `${lavender("\u2713")} ${t(`Archived: ${r.slug}. Undo: ghosty spaces restore ${r.slug}`, `Archivado: ${r.slug}. Deshacer: ghosty spaces restore ${r.slug}`)}` : `${lavender("\u2713")} ${t(`Restored: ${r.slug}.`, `Restaurado: ${r.slug}.`)}`);
|
|
12309
|
+
}
|
|
12310
|
+
if (sub === "transfer") {
|
|
12311
|
+
slug = needSpace(slug ?? context, "ghosty spaces transfer <workspace> --to EMAIL --dry-run");
|
|
12312
|
+
const toEmail = v.to ?? arg;
|
|
12313
|
+
if (!toEmail) throw usage(t("Missing --to EMAIL.", "Falta --to CORREO."), `ghosty spaces transfer ${slug} --to new@owner.com --keep-as admin --copy-keys --dry-run`);
|
|
12314
|
+
const body = { to: toEmail, ...v["keep-as"] ? { keepAs: v["keep-as"] } : {}, ...v["copy-keys"] ? { copyKeys: true } : {} };
|
|
12315
|
+
const path = wsPath(slug, "/transfer");
|
|
12316
|
+
const plan = await api(path, { method: "POST", body: { ...body, dryRun: true } });
|
|
12317
|
+
const text = [
|
|
12318
|
+
`${plan.workspace}: ${plan.from ?? "\u2014"} \u2192 ${bold(plan.to)} ${dim(t(`(previous owner stays as ${plan.keepAs})`, `(el anterior queda como ${plan.keepAs})`))}`,
|
|
12319
|
+
`${t("agents", "agentes")}: ${plan.agents.join(", ") || "\u2014"}`,
|
|
12320
|
+
`${t("keys", "llaves")}: ${plan.keys.copy.length ? t(`copies ${plan.keys.copy.join(", ")}`, `copia ${plan.keys.copy.join(", ")}`) : t("copies none", "no copia")}${plan.keys.alreadyHas.length ? dim(t(` \xB7 already has ${plan.keys.alreadyHas.join(", ")}`, ` \xB7 ya tiene ${plan.keys.alreadyHas.join(", ")}`)) : ""}`,
|
|
12321
|
+
...plan.warnings.map((w) => red(` \xB7 ${serverText(w)}`))
|
|
12322
|
+
].join("\n");
|
|
12323
|
+
if (v["dry-run"]) return out(plan, () => `${text}
|
|
12324
|
+
${dim(t("Dry run: nothing changed.", "Simulaci\xF3n: no cambi\xF3 nada."))}`);
|
|
12325
|
+
const retry = `ghosty spaces transfer ${slug} --to ${toEmail}${v["keep-as"] ? ` --keep-as ${v["keep-as"]}` : ""}${v["copy-keys"] ? " --copy-keys" : ""}`;
|
|
12326
|
+
requireYesIfHeadless(v.yes, retry);
|
|
12327
|
+
await confirm(`${text}
|
|
12328
|
+
${t("Transfer it? Its agents' boxes are recycled (a turn in flight finishes first).", "\xBFTraspasarlo? Se reciclan las cajas de sus agentes (un turno en vuelo termina antes).")}`, { yes: v.yes, expect: plan.workspace, retry });
|
|
12329
|
+
const r = await api(path, { method: "POST", body });
|
|
12330
|
+
return out(r, () => `${lavender("\u2713")} ${t(`${r.workspace} now belongs to ${r.to}; ${r.from ?? "\u2014"} stays as ${r.keepAs}. ${r.recycled} agent(s) recycled.`, `${r.workspace} ya es de ${r.to}; ${r.from ?? "\u2014"} queda como ${r.keepAs}. ${r.recycled} agente(s) reciclado(s).`)}${r.warnings.length ? `
|
|
12331
|
+
${r.warnings.map((w) => red(` \xB7 ${serverText(w)}`)).join("\n")}` : ""}`);
|
|
12332
|
+
}
|
|
12333
|
+
throw usage(t(`Unknown spaces subcommand: ${sub ?? "(none)"}.`, `Subcomando de spaces desconocido: ${sub ?? "(ninguno)"}.`), ex);
|
|
12334
|
+
}
|
|
12335
|
+
async function workspaceUsage(slug, v) {
|
|
12336
|
+
slug = needSpace(slug, "ghosty usage --workspace <slug> --by agent,day --days 14");
|
|
12337
|
+
const r = await api(wsPath(slug, `/usage?days=${enc9(v.days ?? "14")}`));
|
|
12338
|
+
const cdmx2 = (iso) => new Date(Date.parse(iso) - 6 * 36e5).toISOString().slice(5, 16).replace("T", " ");
|
|
12339
|
+
if (v["quota-hits"]) {
|
|
12340
|
+
const rows2 = r.quotaHits.map((q) => ({ at: cdmx2(q.at), agent: q.agent, channel: q.channel, from: q.phone ?? q.conversationId.slice(0, 24), message: (q.preview ?? "").slice(0, 60) }));
|
|
12341
|
+
const total2 = r.agents.reduce((n, a) => n + a.noQuota, 0);
|
|
12342
|
+
return out(r.quotaHits, () => rows2.length ? `${table(rows2, ["at", "agent", "channel", "from", "message"])}
|
|
12343
|
+
${dim(t(`${total2} message(s) unanswered for lack of balance in ${r.days} day(s) (CDMX time)`, `${total2} mensaje(s) sin atender por saldo en ${r.days} d\xEDa(s) (hora CDMX)`))}` : dim(t(`No message ran out of balance in ${r.days} day(s).`, `Ning\xFAn mensaje se qued\xF3 sin saldo en ${r.days} d\xEDa(s).`)));
|
|
12344
|
+
}
|
|
12345
|
+
const by = new Set((v.by ?? "agent").split(",").map((x) => x.trim()));
|
|
12346
|
+
if ([...by].some((b) => b !== "agent" && b !== "day")) throw usage(t("--by takes agent, day or agent,day.", "--by acepta agent, day o agent,day."));
|
|
12347
|
+
let rows;
|
|
12348
|
+
const fmt2 = (x) => ({ turns: x.turns, failed: x.failed ? red(String(x.failed)) : 0, tokens: fmtTokens(x.billable), "no balance": x.noQuota || "" });
|
|
12349
|
+
if (by.has("day") && by.has("agent")) rows = r.rows.map((x) => ({ day: x.day, agent: x.agent, ...fmt2(x) }));
|
|
12350
|
+
else if (by.has("day")) {
|
|
12351
|
+
const days = /* @__PURE__ */ new Map();
|
|
12352
|
+
for (const x of r.rows) {
|
|
12353
|
+
const d = days.get(x.day) ?? { agentId: "", agent: "", turns: 0, failed: 0, billable: 0, outputTokens: 0, cacheRead: 0, noQuota: 0 };
|
|
12354
|
+
d.turns += x.turns;
|
|
12355
|
+
d.failed += x.failed;
|
|
12356
|
+
d.billable += x.billable;
|
|
12357
|
+
d.noQuota += x.noQuota;
|
|
12358
|
+
days.set(x.day, d);
|
|
12359
|
+
}
|
|
12360
|
+
rows = [...days].map(([day3, x]) => ({ day: day3, ...fmt2(x) }));
|
|
12361
|
+
} else rows = r.agents.map((x) => ({ agent: x.agent, ...fmt2(x) }));
|
|
12362
|
+
const cols = [...by.has("day") ? ["day"] : [], ...by.has("agent") ? ["agent"] : [], "turns", "failed", "tokens", "no balance"];
|
|
12363
|
+
const total = r.agents.reduce((n, a) => n + a.billable, 0);
|
|
12364
|
+
out(r, () => `${bold(r.workspace)} ${dim(t(`last ${r.days} day(s), CDMX days`, `\xFAltimos ${r.days} d\xEDa(s), d\xEDas en hora CDMX`))}
|
|
12365
|
+
${table(rows, cols)}
|
|
12366
|
+
${dim(t(`${fmtTokens(total)} billable tokens \xB7 failed = error or stopped \xB7 no balance: ghosty turns ls --workspace ${r.workspace} --quota-hits`, `${fmtTokens(total)} tokens facturables \xB7 failed = error o detenido \xB7 sin saldo: ghosty turns ls --workspace ${r.workspace} --quota-hits`))}`);
|
|
12367
|
+
}
|
|
12368
|
+
var USAGE_DIMS = ["model", "day", "canal"];
|
|
12369
|
+
function groupAgentUsage(rows, by) {
|
|
12370
|
+
const groups = /* @__PURE__ */ new Map();
|
|
12371
|
+
for (const r of rows) {
|
|
12372
|
+
const k = by.map((d) => r[d]).join("|");
|
|
12373
|
+
const g = groups.get(k) ?? { day: by.includes("day") ? r.day : "", model: by.includes("model") ? r.model : "", canal: by.includes("canal") ? r.canal : "", turns: 0, inputTokens: 0, outputTokens: 0, cacheRead: 0, cacheCreation: 0, billable: 0, usd: 0 };
|
|
12374
|
+
g.turns += r.turns;
|
|
12375
|
+
g.inputTokens += r.inputTokens;
|
|
12376
|
+
g.outputTokens += r.outputTokens;
|
|
12377
|
+
g.cacheRead += r.cacheRead;
|
|
12378
|
+
g.cacheCreation += r.cacheCreation;
|
|
12379
|
+
g.billable += r.billable;
|
|
12380
|
+
g.usd += r.usd;
|
|
12381
|
+
groups.set(k, g);
|
|
12382
|
+
}
|
|
12383
|
+
return [...groups.values()].sort((a, b) => a.day.localeCompare(b.day) || b.usd - a.usd);
|
|
12384
|
+
}
|
|
12385
|
+
async function agentUsage(id, v) {
|
|
12386
|
+
if (v.by?.trim() === "visitor") return anonVisitorUsage(id, v);
|
|
12387
|
+
const by = (v.by ?? "model").split(",").map((x) => x.trim()).filter(Boolean);
|
|
12388
|
+
if (!by.length || by.some((b) => !USAGE_DIMS.includes(b))) throw usage(t("With --agent, --by takes model, day and/or canal (or visitor alone).", "Con --agent, --by acepta model, day y/o canal (o visitor solo)."), "ghosty usage --agent <id> --by model,day --cost");
|
|
12389
|
+
const r = await api(`/api/v2/agents/${enc9(id)}/usage?days=${enc9(v.days ?? "14")}`);
|
|
12390
|
+
const groups = groupAgentUsage(r.rows, by);
|
|
12391
|
+
const rows = groups.map((g) => ({ ...Object.fromEntries(by.map((d) => [d, g[d]])), turns: g.turns, tokens: fmtTokens(g.billable), "cache read": fmtTokens(g.cacheRead), out: fmtTokens(g.outputTokens), ...v.cost ? { usd: `$${g.usd.toFixed(2)}` } : {} }));
|
|
12392
|
+
const cols = [...by, "turns", "tokens", "cache read", "out", ...v.cost ? ["usd"] : []];
|
|
12393
|
+
const turns = r.rows.reduce((n, x) => n + x.turns, 0);
|
|
12394
|
+
const foot = v.cost ? t(`$${r.totalUsd.toFixed(2)} USD at provider list price (cache writes included) \xB7 ${turns} turn(s)`, `$${r.totalUsd.toFixed(2)} USD a precio de lista del proveedor (con escritura de cach\xE9) \xB7 ${turns} turno(s)`) : t(`${turns} turn(s) \xB7 USD per row: --cost`, `${turns} turno(s) \xB7 USD por fila: --cost`);
|
|
12395
|
+
out({ ...r, groups }, () => rows.length ? `${bold(r.agent)} ${dim(t(`last ${r.days} day(s), CDMX days`, `\xFAltimos ${r.days} d\xEDa(s), d\xEDas en hora CDMX`))}
|
|
12396
|
+
${table(rows, cols)}
|
|
12397
|
+
${dim(foot)}` : dim(t(`No usage in ${r.days} day(s).`, `Sin uso en ${r.days} d\xEDa(s).`)));
|
|
12398
|
+
}
|
|
12399
|
+
async function anonVisitorUsage(id, v) {
|
|
12400
|
+
const r = await api(`/api/v2/agents/${enc9(id)}/usage?days=${enc9(v.days ?? "14")}&visitors=1`);
|
|
12401
|
+
const vs = r.visitors ?? { list: [], total: { visitors: 0, accounts: 0, usd: 0 } };
|
|
12402
|
+
const yes = t("yes", "s\xED");
|
|
12403
|
+
const rows = vs.list.map((x) => ({
|
|
12404
|
+
visitor: x.visitor.slice(0, 8),
|
|
12405
|
+
first: x.firstAt ? x.firstAt.slice(0, 16).replace("T", " ") : "",
|
|
12406
|
+
msgs: x.messages,
|
|
12407
|
+
usd: `$${x.usd.toFixed(3)}`,
|
|
12408
|
+
page: x.page ? yes : "",
|
|
12409
|
+
pdf: x.pdfs || "",
|
|
12410
|
+
account: x.accountAt ? x.accountAt.slice(0, 10) : ""
|
|
12411
|
+
}));
|
|
12412
|
+
const { visitors, accounts, usd } = vs.total;
|
|
12413
|
+
const perVisitor = visitors ? usd / visitors : 0;
|
|
12414
|
+
const perAccount = accounts ? usd / accounts : null;
|
|
12415
|
+
const foot = t(
|
|
12416
|
+
`${visitors} visitor(s) \xB7 ${accounts} created an account (${visitors ? Math.round(accounts / visitors * 100) : 0}%) \xB7 $${usd.toFixed(2)} USD \xB7 $${perVisitor.toFixed(3)} per visitor${perAccount !== null ? ` \xB7 $${perAccount.toFixed(2)} per new account` : ""} (provider list price; times in UTC)`,
|
|
12417
|
+
`${visitors} visitante(s) \xB7 ${accounts} crearon cuenta (${visitors ? Math.round(accounts / visitors * 100) : 0}%) \xB7 $${usd.toFixed(2)} USD \xB7 $${perVisitor.toFixed(3)} por visitante${perAccount !== null ? ` \xB7 $${perAccount.toFixed(2)} por cuenta nueva` : ""} (precio de lista del proveedor; horas en UTC)`
|
|
12418
|
+
);
|
|
12419
|
+
out(r, () => rows.length ? `${bold(r.agent)} ${dim(t(`/c without an account, last ${r.days} day(s)`, `/c sin cuenta, \xFAltimos ${r.days} d\xEDa(s)`))}
|
|
12420
|
+
${table(rows, ["visitor", "first", "msgs", "usd", "page", "pdf", "account"])}
|
|
12421
|
+
${dim(foot)}` : dim(t(`No visitors in ${r.days} day(s).`, `Sin visitantes en ${r.days} d\xEDa(s).`)));
|
|
12422
|
+
}
|
|
12423
|
+
function fmtUntil(iso) {
|
|
12424
|
+
if (!iso) return "";
|
|
12425
|
+
const d = new Date(new Date(iso).getTime() - 6 * 36e5);
|
|
12426
|
+
return d.toISOString().slice(0, 16).replace("T", " ");
|
|
12427
|
+
}
|
|
12428
|
+
async function spacesMembers(action, slug, email, v, context) {
|
|
12429
|
+
if (context && slug?.includes("@") && !email) [slug, email] = [context, slug];
|
|
12430
|
+
if (action && !["ls", "list", "add", "rm", "remove"].includes(action) && !slug) [action, slug] = ["ls", action];
|
|
12431
|
+
const ex = "ghosty spaces members ls <workspace> \xB7 add <workspace> <email>[,email\u2026] [--role member|admin] [--until 2026-10-28|14d] \xB7 rm <workspace> <email>";
|
|
12432
|
+
slug = needSpace(slug ?? context, ex);
|
|
12433
|
+
switch (action ?? "ls") {
|
|
12434
|
+
case "ls":
|
|
12435
|
+
case "list": {
|
|
12436
|
+
const r = await api(wsPath(slug, "/members"));
|
|
12437
|
+
const rows = r.members.map((m) => ({ email: m.email, role: m.role.toLowerCase(), status: m.status, until: fmtUntil(m.until) }));
|
|
12438
|
+
return out(r, () => `${table(rows, ["email", "role", "status", "until"])}${r.error ? `
|
|
12439
|
+
${lavender(`\u26A0\uFE0F ${serverText(r.error)}`)}` : ""}`);
|
|
12440
|
+
}
|
|
12441
|
+
case "add": {
|
|
12442
|
+
if (!email) throw usage(t("Missing email.", "Falta el correo."), ex);
|
|
12443
|
+
const emails = email.split(",").map((e) => e.trim()).filter(Boolean);
|
|
12444
|
+
const r = await api(wsPath(slug, "/members"), { method: "POST", body: { emails, role: v.role ?? "member", ...v.until ? { until: v.until } : {} } });
|
|
12445
|
+
const lines = [
|
|
12446
|
+
...r.invited.map((e) => `${lavender("\u2713")} ${e} ${t(`added to ${r.workspace}`, `agregada a ${r.workspace}`)}${r.until ? dim(t(` until ${fmtUntil(r.until)} (CDMX), then removed`, ` hasta ${fmtUntil(r.until)} (CDMX), luego se retira sola`)) : ""}`),
|
|
12447
|
+
...r.extended.map((e) => `${lavender("\u2713")} ${e} ${t("was already in; expires", "ya estaba; vence")} ${fmtUntil(r.until)} (CDMX)`),
|
|
12448
|
+
...r.failed.map((f) => `${red("\u2717")} ${f.email}: ${serverText(f.error)}`),
|
|
12449
|
+
...r.mailFailed.map((e) => dim(t(`The invite email to ${e} failed; access works anyway.`, `El correo de invitaci\xF3n a ${e} fall\xF3; el acceso funciona igual.`)))
|
|
12450
|
+
];
|
|
12451
|
+
return out(r, () => lines.join("\n"));
|
|
12452
|
+
}
|
|
12453
|
+
case "rm":
|
|
12454
|
+
case "remove": {
|
|
12455
|
+
if (!email) throw usage(t("Missing email.", "Falta el correo."), ex);
|
|
12456
|
+
requireYesIfHeadless(v.yes, `ghosty spaces members rm ${slug} ${email}`);
|
|
12457
|
+
await confirm(t(`Remove ${email} from ${slug}? (loses the seat, the boards and the agents of the workspace)`, `\xBFQuitar a ${email} de ${slug}? (pierde el asiento, los tableros y los agentes del espacio)`), { yes: v.yes, retry: `ghosty spaces members rm ${slug} ${email}` });
|
|
12458
|
+
const r = await api(wsPath(slug, "/members"), { method: "DELETE", body: { email } });
|
|
12459
|
+
return out(r, () => `${lavender("\u2713")} ${r.result === "removed" ? t(`${r.email} removed from ${r.workspace}.`, `${r.email} fuera de ${r.workspace}.`) : t(`Invite to ${r.email} canceled.`, `Invitaci\xF3n a ${r.email} cancelada.`)}`);
|
|
12460
|
+
}
|
|
12461
|
+
default:
|
|
12462
|
+
throw usage(t(`Unknown members subcommand: ${action}.`, `Subcomando de members desconocido: ${action}.`), ex);
|
|
12463
|
+
}
|
|
12464
|
+
}
|
|
12465
|
+
|
|
12466
|
+
// src/commands/boards.ts
|
|
12467
|
+
var enc10 = encodeURIComponent;
|
|
12468
|
+
async function boardsCmd(sub, a1, a2, v, context) {
|
|
12469
|
+
if (context && sub !== "assign") {
|
|
12470
|
+
if ((sub === "ls" || sub === "list" || !sub || sub === "move-cards") && !a1) a1 = context;
|
|
12471
|
+
else if ((sub === "create" || sub === "rm") && a1 && !a2) [a1, a2] = [context, a1];
|
|
12472
|
+
else if (sub === "access" && !a2) [a1, a2] = [context, a1 ?? "main"];
|
|
12473
|
+
}
|
|
12474
|
+
switch (sub ?? "ls") {
|
|
12475
|
+
case "ls":
|
|
12476
|
+
case "list": {
|
|
12477
|
+
if (!a1) throw usage(t("Missing workspace.", "Falta el espacio."), t("Example", "Ejemplo") + ": ghosty boards ls <workspace-slug>");
|
|
12478
|
+
const r = await api(`/api/v2/workspaces/${enc10(a1)}/boards`);
|
|
12479
|
+
const rows = r.boards.map((b) => ({ name: b.main ? `${b.name} (${t("main", "principal")})` : b.name, cards: b.cards, agents: b.agents.map((x) => x.name ?? x.id).join(", "), columns: b.columns.length, id: b.id }));
|
|
12480
|
+
return out(r, () => table(rows, ["name", "cards", "agents", "columns", "id"]));
|
|
12481
|
+
}
|
|
12482
|
+
case "create": {
|
|
12483
|
+
if (!a1 || !a2) throw usage(t("Missing workspace or name.", "Falta el espacio o el nombre."), t("Example", "Ejemplo") + ': ghosty boards create <workspace> "Siiqtec - Ixmiquilpan" --columns-from main');
|
|
12484
|
+
const r = await api(`/api/v2/workspaces/${enc10(a1)}/boards`, { method: "POST", body: { name: a2, ...v["columns-from"] ? { columnsFrom: v["columns-from"] } : {} } });
|
|
12485
|
+
return out(r, () => `${lavender("\u2713")} ${t(`Board \xAB${r.name}\xBB created${r.columnsFrom ? ` with the ${r.columns} column(s) of \xAB${r.columnsFrom}\xBB` : ""}.`, `Tablero \xAB${r.name}\xBB creado${r.columnsFrom ? ` con las ${r.columns} columna(s) de \xAB${r.columnsFrom}\xBB` : ""}.`)} ${dim(`${t("Send an agent's cards there", "Manda ah\xED las tarjetas de un agente")}: ghosty boards assign <agent-id> "${r.name}"`)}${r.warning ? `
|
|
12486
|
+
${lavender(`\u26A0\uFE0F ${serverText(r.warning)}`)}` : ""}`);
|
|
12487
|
+
}
|
|
12488
|
+
case "rm": {
|
|
12489
|
+
if (!a1 || !a2) throw usage(t("Missing workspace or board.", "Falta el espacio o el tablero."), t("Example", "Ejemplo") + ': ghosty boards rm <workspace> "Prueba"');
|
|
12490
|
+
requireYesIfHeadless(v.yes, `ghosty boards rm ${a1} ${JSON.stringify(a2)}`);
|
|
12491
|
+
await confirm(t(`Delete the board \xAB${a2}\xBB of ${a1}? (only an empty one; its agents go back to the main board)`, `\xBFBorrar el tablero \xAB${a2}\xBB de ${a1}? (s\xF3lo si est\xE1 vac\xEDo; sus agentes regresan al tablero principal)`), { yes: v.yes, retry: `ghosty boards rm ${a1} ${JSON.stringify(a2)}` });
|
|
12492
|
+
const r = await api(`/api/v2/workspaces/${enc10(a1)}/boards`, { method: "DELETE", body: { board: a2 } });
|
|
12493
|
+
return out(r, () => `${lavender("\u2713")} ${t(`Board \xAB${r.deleted}\xBB deleted.`, `Tablero \xAB${r.deleted}\xBB borrado.`)}`);
|
|
12494
|
+
}
|
|
12495
|
+
case "assign": {
|
|
12496
|
+
if (!a1 || !a2) throw usage(t("Missing agent or board.", "Falta el agente o el tablero."), t("Example", "Ejemplo") + ': ghosty boards assign <agent-id> "Siiqtec - Ixmiquilpan" (' + t("or main", "o main") + ")");
|
|
12497
|
+
const r = await api(`/api/v2/agents/${enc10(a1)}`, { method: "PATCH", body: { board: a2 } });
|
|
12498
|
+
return out(r, () => `${lavender("\u2713")} ${t(`New cards of ${a1} go to \xAB${r.board}\xBB.`, `Las tarjetas nuevas de ${a1} van a \xAB${r.board}\xBB.`)} ${dim(`${t("Existing ones stay where they are", "Las que ya existen se quedan donde est\xE1n")}: ghosty boards move-cards ${r.workspace} --from \u2026 --to "${r.board}" \u2026`)}`);
|
|
12499
|
+
}
|
|
12500
|
+
case "move-cards": {
|
|
12501
|
+
if (!a1 || !v.from || !v.to) throw usage(t("Missing workspace, --from or --to.", "Falta el espacio, --from o --to."), t("Example", "Ejemplo") + ': ghosty boards move-cards <workspace> --from main --to "Siiqtec - Ixmiquilpan" --integration 6a3b02ad\u2026 --dry-run');
|
|
12502
|
+
if (!v.integration && !v.phone && !v.all) throw usage(t("Add a filter: --integration ID, --phone N or --all.", "Agrega un filtro: --integration ID, --phone N o --all."), t("A filter-less move would empty the board.", "Mover sin filtro vaciar\xEDa el tablero."));
|
|
12503
|
+
const path = `/api/v2/workspaces/${enc10(a1)}/boards/move-cards`;
|
|
12504
|
+
const body = { from: v.from, to: v.to, ...v.integration ? { integration: v.integration } : {}, ...v.phone ? { phone: v.phone } : {}, ...v.all ? { all: true } : {} };
|
|
12505
|
+
const retry = `ghosty boards move-cards ${a1} --from ${JSON.stringify(v.from)} --to ${JSON.stringify(v.to)}${v.integration ? ` --integration ${v.integration}` : ""}${v.phone ? ` --phone ${v.phone}` : ""}${v.all ? " --all" : ""}`;
|
|
12506
|
+
if (!v["dry-run"]) requireYesIfHeadless(v.yes, retry);
|
|
12507
|
+
const plan = await api(path, { method: "POST", body: { ...body, dryRun: true } });
|
|
12508
|
+
const sample = table(plan.sample.map((c) => ({ folio: c.folio ? `#${c.folio}` : "", name: c.name ?? "", phone: c.phone })), ["folio", "name", "phone"]);
|
|
12509
|
+
const text = `${sample}
|
|
12510
|
+
${t(`${plan.moved} of ${plan.matched} card(s)`, `${plan.moved} de ${plan.matched} tarjeta(s)`)} \xAB${plan.from}\xBB \u2192 \xAB${plan.to}\xBB${plan.skipped.length ? dim(t(` \xB7 ${plan.skipped.length} already in \xAB${plan.to}\xBB, skipped`, ` \xB7 ${plan.skipped.length} ya en \xAB${plan.to}\xBB, se omiten`)) : ""}`;
|
|
12511
|
+
if (v["dry-run"] || !plan.moved) return out(plan, () => `${text}
|
|
12512
|
+
${dim(t("Dry run: nothing changed.", "Simulacro: no se cambi\xF3 nada."))}`);
|
|
12513
|
+
await confirm(`${text}
|
|
12514
|
+
${t("Move them with their threads and orders? (they get a new folio there)", "\xBFMoverlas con sus hilos y pedidos? (all\xE1 reciben folio nuevo)")}`, { yes: v.yes, retry });
|
|
12515
|
+
const r = await api(path, { method: "POST", body });
|
|
12516
|
+
return out(r, () => `${lavender("\u2713")} ${t(`Moved ${r.moved} card(s) (${r.messages} message(s), ${r.orders} order(s)) to \xAB${r.to}\xBB.`, `Se movieron ${r.moved} tarjeta(s) (${r.messages} mensaje(s), ${r.orders} pedido(s)) a \xAB${r.to}\xBB.`)}${r.skipped.length ? dim(t(` Skipped ${r.skipped.length}.`, ` Se omitieron ${r.skipped.length}.`)) : ""}`);
|
|
12517
|
+
}
|
|
12518
|
+
// Quién ve un tablero: lista «sólo estas personas» o todo el espacio (feedback del revisor de Meta).
|
|
12519
|
+
case "access": {
|
|
12520
|
+
if (!a1) throw usage(t("Missing workspace.", "Falta el espacio."), t("Example", "Ejemplo") + ': ghosty boards access <workspace> "Siiqtec - Ixmiquilpan" --add ana@x.com --until 14d');
|
|
12521
|
+
const board = a2 ?? "main";
|
|
12522
|
+
const split = (xs) => (xs ?? []).flatMap((x) => x.split(",")).map((x) => x.trim()).filter(Boolean);
|
|
12523
|
+
const add = split(v.add);
|
|
12524
|
+
const remove = split(v.remove);
|
|
12525
|
+
const edit = add.length || remove.length || v.everyone;
|
|
12526
|
+
const r = edit ? await api(`/api/v2/workspaces/${enc10(a1)}/boards/access`, { method: "POST", body: { board, add, remove, ...v.everyone ? { everyone: true } : {}, ...v.restrict ? { restrict: true } : {}, ...v.until ? { until: v.until } : {} } }) : await api(`/api/v2/workspaces/${enc10(a1)}/boards/access?board=${enc10(board)}`);
|
|
12527
|
+
return out(r, () => {
|
|
12528
|
+
const head = `\xAB${r.board}\xBB (${r.workspace}): ${r.everyone ? t("the whole workspace sees it", "lo ve todo el espacio") : t("only these people (plus owner and staff)", "s\xF3lo estas personas (m\xE1s due\xF1o y staff)")}`;
|
|
12529
|
+
const people = r.everyone ? "" : `
|
|
12530
|
+
${table(r.people.map((p) => ({ email: p.email, until: fmtUntil(p.until) })), ["email", "until"])}`;
|
|
12531
|
+
const changes = [
|
|
12532
|
+
...(r.added ?? []).map((e) => `${lavender("+")} ${e}`),
|
|
12533
|
+
...(r.removed ?? []).map((e) => `${lavender("\u2212")} ${e}`),
|
|
12534
|
+
...(r.skipped ?? []).map((s2) => dim(`\xB7 ${s2.email}: ${serverText(s2.reason)}`))
|
|
12535
|
+
];
|
|
12536
|
+
return [head + people, ...changes].join("\n");
|
|
12537
|
+
});
|
|
12538
|
+
}
|
|
12539
|
+
default:
|
|
12540
|
+
throw usage(t(`Unknown boards subcommand: ${sub}.`, `Subcomando de boards desconocido: ${sub}.`), t("Try", "Prueba") + ": ghosty boards ls | create | assign | move-cards | access | rm");
|
|
12541
|
+
}
|
|
12542
|
+
}
|
|
12543
|
+
|
|
12544
|
+
// src/commands/access.ts
|
|
12545
|
+
async function accessCmd(sub, email, agent, v, context) {
|
|
12546
|
+
const ex = "ghosty access why <email> <agent-id> \xB7 ghosty access why <email> --workspace <ws> [--board <board|main>]";
|
|
12547
|
+
if (sub !== "why") throw usage(t(`Unknown access subcommand: ${sub ?? "(none)"}.`, `Subcomando de access desconocido: ${sub ?? "(ninguno)"}.`), ex);
|
|
12548
|
+
if (!email) throw usage(t("Missing email.", "Falta el correo."), ex);
|
|
12549
|
+
const q = new URLSearchParams({ email });
|
|
12550
|
+
if (agent) q.set("agent", agent);
|
|
12551
|
+
else {
|
|
12552
|
+
const ws = v.workspace ?? context;
|
|
12553
|
+
if (!ws) throw usage(t("Missing agent or --workspace.", "Falta el agente o --workspace."), ex);
|
|
12554
|
+
q.set("workspace", ws);
|
|
12555
|
+
q.set("board", v.board ?? "main");
|
|
12556
|
+
}
|
|
12557
|
+
const r = await api(`/api/v2/access/why?${q}`);
|
|
12558
|
+
const what = r.target.kind === "agent" ? `${r.target.name ?? r.target.id}` : `${t("board", "tablero")} \xAB${r.target.name}\xBB (${r.target.workspace})`;
|
|
12559
|
+
return out(r, () => {
|
|
12560
|
+
const head = `${bold(r.email)} \u2192 ${what}: ${r.access ? lavender(r.access) : t("no access", "sin acceso")}`;
|
|
12561
|
+
if (!r.lines.length) return `${head}
|
|
12562
|
+
${dim(serverText(r.note ?? t("No reason found.", "Ninguna raz\xF3n.")))}`;
|
|
12563
|
+
return `${head}
|
|
12564
|
+
${table(r.lines.map((l) => ({ via: l.via, detail: serverText(l.detail), until: fmtUntil(l.until) })), ["via", "detail", "until"])}`;
|
|
12565
|
+
});
|
|
12566
|
+
}
|
|
12567
|
+
|
|
12568
|
+
// src/help.es.ts
|
|
12569
|
+
var HELPS_ES = {
|
|
12570
|
+
agents: {
|
|
12571
|
+
summary: "Crea, revisa, cambia, diagnostica y borra agentes.",
|
|
12572
|
+
replace: [
|
|
12573
|
+
["# the agent as a file; see ghosty apply --help", "# el agente como archivo; ver ghosty apply --help"],
|
|
12574
|
+
["# its look", "# su apariencia"],
|
|
12575
|
+
["# its theme", "# su tema"],
|
|
12576
|
+
["# export the theme as JSON (edit it, apply it back with --style-file)", "# exporta el tema en JSON (ed\xEDtalo y vuelve a aplicarlo con --style-file)"],
|
|
12577
|
+
["--style-file theme.json", "--style-file tema.json"],
|
|
12578
|
+
["# what it says while it works", "# lo que dice mientras trabaja"],
|
|
12579
|
+
["--copy-file texts.json", "--copy-file textos.json"],
|
|
12580
|
+
["# who is @build in Teams (that workspace, or all of yours)", "# qui\xE9n es @build en Teams (en ese espacio, o en todos los tuyos)"],
|
|
12581
|
+
["# change one piece of the prompt, on the server's current one", "# cambia un pedazo del prompt, sobre el actual del servidor"],
|
|
12582
|
+
["# your account: merge copies with the same content", "# tu cuenta: une las copias con el mismo contenido"],
|
|
12583
|
+
["# staff: their agents, latest turns, plan and boxes", "# staff: sus agentes, \xFAltimos turnos, plan y cajas"],
|
|
12584
|
+
["# what it really has: effective toolsets, connectors connected + granted", "# lo que de verdad tiene: toolsets efectivos, conectores conectados + concedidos"],
|
|
12585
|
+
["# Teams workspaces you administer: where it answers, is paused, and with which @handle", "# los equipos de Teams que administras: d\xF3nde contesta, d\xF3nde est\xE1 en pausa y con qu\xE9 @handle"],
|
|
12586
|
+
["# turn it on there (or change its @handle)", "# lo prende ah\xED (o le cambia el @handle)"],
|
|
12587
|
+
["# pause it there; it keeps its @handle", "# lo pausa ah\xED; conserva su @handle"],
|
|
12588
|
+
["# archive: stops answering everywhere, hidden, deleted after 7 days unless restored", "# archivar: deja de contestar en todos lados, se oculta y se borra a los 7 d\xEDas si no lo restauras"],
|
|
12589
|
+
["# archived agents and when they get deleted", "# los archivados y cu\xE1ndo se borran"],
|
|
12590
|
+
["# --json: model and workspace on every row", "# --json: modelo y espacio en cada fila"],
|
|
12591
|
+
["# also: model, effort, native subagents, answers /c, box size (staff)", "# tambi\xE9n: modelo, effort, subagentes nativos, si atiende /c, tama\xF1o de caja (staff)"],
|
|
12592
|
+
["# remove it from there; the agent stays", "# lo quita de ah\xED; el agente sigue"],
|
|
12593
|
+
["# web widget: chat bubble on your site, only on those domains", "# widget web: burbuja de chat en tu sitio, s\xF3lo en esos dominios"],
|
|
12594
|
+
["# state + the <script> to paste", "# su estado + el <script> para pegar"]
|
|
12595
|
+
],
|
|
12596
|
+
flags: [
|
|
12597
|
+
["--fields a,b", "get: regresa s\xF3lo estos campos"],
|
|
12598
|
+
["--prompt-out FILE", "get: escribe el prompt en FILE (ed\xEDtalo y vuelve con set --prompt-file)"],
|
|
12599
|
+
["--like AGENT", "create: copia la configuraci\xF3n de ese agente (skills y sus switches, toolsets, conectores, voz, bases de datos, documentos, tablero, compartidos) \u2014 no su prompt, env ni canales. docs grant: los mismos documentos"],
|
|
12600
|
+
["--copy-dbs", "create --like: duplica sus bases de datos con sus filas en vez de conceder las mismas"],
|
|
12601
|
+
["--board B", "create --like: same (el tablero del origen, default) \xB7 main \xB7 new (un tablero con el nombre del agente y las columnas del origen: un tablero por n\xFAmero) \xB7 o un tablero existente"],
|
|
12602
|
+
["--no-notify", "create --like: lo comparte con las mismas personas SIN mandarles correo"],
|
|
12603
|
+
["--workspace SLUG", "create: nace en ese espacio (del que eres due\xF1o o admin), a nombre de su due\xF1o y activo en su Teams"],
|
|
12604
|
+
["--channels k=on|off,\u2026", "create/set: prende/apaga canales: teams, web, whatsapp, messenger, wa (WhatsApp personal)"],
|
|
12605
|
+
["--engine E --dry-run", "set: qu\xE9 hace cambiar de motor (sesiones que se olvidan, caja que se levanta y cu\xE1l se destruye, si est\xE1 trabajando) sin cambiarlo; cada hilo conserva su conversaci\xF3n"],
|
|
12606
|
+
["--toolsets LIST", "set: grupos de tools de gs que recibe (crm, sales\u2026): una lista reemplaza; +x / -x agrega o quita"],
|
|
12607
|
+
["--prompt-base ID", "set: el prompt de este agente = el prompt de ese agente + --prompt-overlay; se regenera cuando cambia la base. none = desliga (conserva el prompt de hoy)"],
|
|
12608
|
+
["--prompt-overlay FILE", 'set: JSON {"edits":[{"what","find","replace","regex"?,"all"?}]}, aplicados en orden; cada uno debe encontrar su lugar o no cambia nada. {"edits":[]} = espejo exacto: un solo prompt y una sola memoria para los dos'],
|
|
12609
|
+
["--prompt-patch FILE", 'set: el mismo formato {"edits":[\u2026]}, aplicado UNA vez sobre el prompt actual del agente en el servidor (no sobre una copia local: nunca pisa el cambio de alguien m\xE1s). Si una edici\xF3n no encuentra su lugar, no cambia nada. --dry-run imprime el diff'],
|
|
12610
|
+
["--prompt-append FILE", "set: agrega ese texto al final del prompt (con --prompt-patch tambi\xE9n: primero las ediciones, luego el texto)"],
|
|
12611
|
+
["--voice E:ID", "set: voz de las notas de voz: elevenlabs:<voiceId> o kokoro:em_santa|em_alex|ef_dora"],
|
|
12612
|
+
["--voice-replies M", "set: auto = contesta con nota de voz cuando el cliente manda o pide audio; off = siempre texto"],
|
|
12613
|
+
["--auto-stage on|off", "set: mueve solo las tarjetas del tablero tras cada turno del cliente (una llamada extra al modelo por turno)"],
|
|
12614
|
+
["--quote k=v,\u2026", "set: config de la tool de casa `cotizar` \u2014 iva (0-100), iva-incluido=true (los precios del cat\xE1logo ya traen IVA), iva.CATEGORIA=16 (IVA de esa categor\xEDa del cat\xE1logo; iva.CATEGORIA= la quita), solo-factura=true (IVA s\xF3lo si el cliente pide factura), vigencia (d\xEDas), prefix (folio), moneda, empresa, rfc, telefono, correo, direccion, notas, color. Vac\xEDo lo borra (rfc=). El contador de folio no se toca"],
|
|
12615
|
+
["--catalog FILE", "set: el cat\xE1logo de la tool de casa `cotizar` desde un CSV (sku,nombre,precio[,unidad,categoria,descripcion]) o una lista JSON; reemplaza al anterior. Su `categoria` decide las reglas de IVA"],
|
|
12616
|
+
["--verbose", "doctor: lista tambi\xE9n las revisiones que pasaron"],
|
|
12617
|
+
["--user EMAIL", "doctor (staff de Ghosty): los agentes de esa persona \u2014 doctor, \xFAltimos turnos (estado, segundos, error y \xABfetched\xBB: si su app pidi\xF3 el hilo despu\xE9s de que termin\xF3 el turno), plan/bolsa y cajas (marca duplicadas); queda en bit\xE1cora"],
|
|
12618
|
+
["--turns N", "doctor --user: cu\xE1ntos turnos recientes por agente (default 8, m\xE1x. 50)"],
|
|
12619
|
+
["--write", "docs grant: el agente puede reemplazar el documento (default: s\xF3lo lectura)"],
|
|
12620
|
+
["--no-deliver", "docs grant/add: puede leerlo pero nunca mand\xE1rselo a quien escribe"],
|
|
12621
|
+
["--url URL | --file PATH", "docs add: de d\xF3nde sale el documento (URL p\xFAblica, hasta 25 MB, o un archivo local)"],
|
|
12622
|
+
["--grant read|write|no", "docs add: acceso de este agente (default read; no = s\xF3lo subirlo a la cuenta)"],
|
|
12623
|
+
["--note TEXT", "docs replace/restore: por qu\xE9 cambi\xF3 (sale en docs history)"],
|
|
12624
|
+
["--role R", "share: editor (lo configura y lo usa) o admin (adem\xE1s lo comparte); repetirlo sobre un correo ya compartido cambia el rol"],
|
|
12625
|
+
["--handle NAME", "teams on: su @handle en ese equipo (default: sacado de su nombre, con sufijo si est\xE1 ocupado; @ghosty est\xE1 reservado). Sobre un equipo donde ya est\xE1, le cambia el handle. ls: qui\xE9n contesta a ese @handle"],
|
|
12626
|
+
["--factory ROLES", "teams on: le pasa esos roles de la Software Factory del equipo (plan, build, check, eval; separados por comas) \u2014 lo mismo que \xABEquipo\xBB en /factory. Cada rol conserva su nombre y avatar; su siguiente turno ya corre en \xE9l. La f\xE1brica tiene que estar instalada ah\xED"],
|
|
12627
|
+
["--yes", "rm: se salta la confirmaci\xF3n (obligatorio sin terminal)"],
|
|
12628
|
+
["--slug NAME", "demo: nombre de la liga; se le agrega un c\xF3digo de 6 caracteres (/p/NAME-CODE)"],
|
|
12629
|
+
["--expires DATE|no", 'demo: caducidad fija en la hora de tu m\xE1quina ("2026-10-15T20:00"); no = nunca'],
|
|
12630
|
+
["--turns N", "demo: mensajes por visitante (default 150)"],
|
|
12631
|
+
["--per-ip N", "demo: mensajes por IP al d\xEDa (default 30)"],
|
|
12632
|
+
["--welcome TEXT", "demo: saludo del chat (vac\xEDo = el de siempre)"],
|
|
12633
|
+
["--starter TEXT", 'demo: primera sugerencia destacada ("" la quita)'],
|
|
12634
|
+
['--chips "a|b|c"', "demo: sugerencias, separadas por |"],
|
|
12635
|
+
["--sponsor on|off", "demo: las copias que la gente se queda corren con TU llave del motor"],
|
|
12636
|
+
["--rotate", "demo: c\xF3digo nuevo; la liga vieja deja de servir"],
|
|
12637
|
+
["--domains a.com,*.b.com", "embed: d\xF3nde puede cargarse el widget (vac\xEDo = en ning\xFAn lado)"],
|
|
12638
|
+
["--welcome TEXT", "embed: el primer mensaje que ve el visitante (vac\xEDo = \xAB\xA1Hola! \xBFEn qu\xE9 te ayudo?\xBB)"],
|
|
12639
|
+
["--title T / --subtitle T", "embed: nombre en el encabezado del widget (default: el del agente) y un rengl\xF3n chico debajo (\xABResponde en minutos\xBB)"],
|
|
12640
|
+
["--avatar URL|none", "embed: tu imagen (https JPEG/PNG/WebP, se rehospeda en img.ghosty.studio); none = el fantasma del agente"],
|
|
12641
|
+
["--icon chat|avatar|ghost", "embed: qu\xE9 lleva el bot\xF3n flotante"],
|
|
12642
|
+
["--placeholder T", "embed: el texto gris de la caja para escribir"],
|
|
12643
|
+
["--position right|left / --offset X[,Y]", "embed: esquina de la p\xE1gina y separaci\xF3n en px del lado y de abajo (0-200, default 20)"],
|
|
12644
|
+
["--theme light|dark|auto", "embed: tema del panel del chat (auto = el del visitante)"],
|
|
12645
|
+
["--bubble-text T", "embed: etiqueta junto al bot\xF3n (\xAB\xBFDudas?\xBB)"],
|
|
12646
|
+
["--auto-open S|off", "embed: se abre solo a los S segundos (1-120), una vez por visita, nunca en el tel\xE9fono"],
|
|
12647
|
+
['--starters "a|b|c"', 'embed: hasta 4 sugerencias TUYAS ("" las quita; nunca salen las de Ghosty)'],
|
|
12648
|
+
["--style '{json}'|none", "embed: estilo fino, s\xF3lo llaves conocidas: fontFamily, radius, headerBg, headerText, titleUppercase, statusDot, headerAvatar, panelBg, userBubbleBg/Text, agentBubbleBg/Text, inputBg, sendBg, sendIcon, sendArrow (up|right), launcherBg, launcherIcon, typing (bounce|flow|flashing|shimmer), typingColor. PATCH por llave (null resetea una); none resetea todo"],
|
|
12649
|
+
["--font NAME / --radius 0-24", "embed: atajos de style.fontFamily (lista de Google Fonts: Barlow, Inter, Poppins\u2026) y style.radius"],
|
|
12650
|
+
["--typing STYLE / --typing-color #rrggbb|none", "embed: el indicador de \xABescribiendo\xBB mientras responde: bounce (el de siempre), flow, flashing o shimmer (\xABPensando\u2026\xBB con brillo), y su color (por defecto, el de la marca)"],
|
|
12651
|
+
["--theme-source custom|teams|site", "embed: importa el tema de la marca de tu espacio de Ghosty Teams (--workspace SLUG para elegir) o de tu sitio (--site-url); queda editable"],
|
|
12652
|
+
["--site-url URL", "embed: el sitio del que se sacan los colores (implica --theme-source site)"],
|
|
12653
|
+
["--style-file FILE", "embed: aplica un tema exportado con `agents embed <id> theme` (o s\xF3lo el objeto style)"],
|
|
12654
|
+
["--copy '{json}'|none", "embed: las frases mientras el agente trabaja, texto plano \u2264 80 car.: waking, connecting, thinking (lista de 1 a 8 que rotan), stillWorking, cantStart, interrupted, retryLabel, showDuration, showCopyButton (true|false). PATCH por llave (null = la frase de Ghosty); none las regresa todas"],
|
|
12655
|
+
["--copy-file FILE", "embed: aplica el objeto copy desde un archivo (o el `copy` de un tema exportado)"],
|
|
12656
|
+
["--out FILE.tsx|.jsx [--force]", "embed: escribe en tu proyecto un componente de React COMPLETO y editable (sin depender de ning\xFAn paquete) con tu token y tu tema horneados arriba; no pisa un archivo que ya existe sin --force"],
|
|
12657
|
+
["--check PATH", "box: este archivo debe existir en la m\xE1quina (repetible), p. ej. un archivo que trae la imagen nueva"],
|
|
12658
|
+
["--contains PATH=TEXT", "box: ese archivo debe contener TEXT (un cambio que no agrega archivos)"],
|
|
12659
|
+
["--recycle", "box: reemplaza sus m\xE1quinas (nunca a media respuesta); pool: la nueva nace en el siguiente turno; ACP (goose, lite) igual, con el historial del \xFAltimo respaldo"],
|
|
12660
|
+
["--start", "box: levanta (o despierta) su caja ya, sin gastar un turno; dentro de las cajas del plan (503 si el espacio est\xE1 lleno)"],
|
|
12661
|
+
["--reenv / --force", "box --recycle en ACP: --reenv s\xF3lo re-hornea el env en la misma caja; --force la recrea aunque est\xE9 ocupada (due\xF1o o staff)"],
|
|
12662
|
+
["--unset-env K1,K2", "set: borra esas variables del env (--env K= tambi\xE9n borra K)"],
|
|
12663
|
+
["--tool [ch:]tool=on|off", "set: prende/apaga una tool en un canal (wa:actualizar_identidad=off) o en todos (crm_buscar=off); separadas por comas"],
|
|
12664
|
+
["--bag NAME|none", "set: de qu\xE9 bolsa de tokens de su espacio gasta; none = el saldo del espacio (s\xF3lo staff)"],
|
|
12665
|
+
["--box MB[:N]", "set: RAM de su caja (1024, 2048, 4096, 8192) y conversaciones a la vez, p. ej. 4096:10; recicla sus cajas (s\xF3lo staff)"],
|
|
12666
|
+
["--avatar URL|FILE", "set: su cara en Teams: una liga https o un JPEG/PNG/WebP local (se guarda en img.ghosty.studio)"],
|
|
12667
|
+
["--from-workspace", "rm: lo desactiva en cada Teams donde est\xE9 y luego lo borra (due\xF1o o staff)"],
|
|
12668
|
+
["--prompt-mode M", "set: append (default: su prompt + la persona de Ghosty) o replace (s\xF3lo su prompt)"],
|
|
12669
|
+
["--sponsor/--owner EMAIL", "ls: agentes de CUALQUIER cuenta que paga / de quien es ese correo (staff de Ghosty); luego se operan por id"],
|
|
12670
|
+
["--ids", "ls: s\xF3lo los ids, uno por rengl\xF3n (para xargs)"],
|
|
12671
|
+
["--user EMAIL --app A", "ls (staff de Ghosty): la lista de esa persona tal como la recibe su app (tono, espacio, \xFAltimo uso) y sus tel\xE9fonos con la build de la app; A = all|android|ios|desktop"]
|
|
12672
|
+
],
|
|
12673
|
+
notes: [
|
|
12674
|
+
"doctor sale con 1 cuando encuentra un problema, as\xED puede frenar un script o un CI.",
|
|
12675
|
+
"Un prompt derivado no se edita directo (409): cambia la base o el overlay, o desenl\xE1zalo con --prompt-base none.",
|
|
12676
|
+
"demo sin flags s\xF3lo imprime su estado: liga, caducidad, topes y n\xFAmeros."
|
|
12677
|
+
]
|
|
12678
|
+
},
|
|
12679
|
+
skills: {
|
|
12680
|
+
summary: "Skills de un agente (formato agentskills.io: una carpeta con SKILL.md).",
|
|
12681
|
+
replace: [
|
|
12682
|
+
["# from the community catalog", "# del cat\xE1logo de la comunidad"],
|
|
12683
|
+
["# keeps a local copy first", "# antes guarda una copia local"]
|
|
12684
|
+
],
|
|
12685
|
+
flags: [
|
|
12686
|
+
["--out DIR", "get: carpeta donde escribir; sin ella, get s\xF3lo lista los archivos"],
|
|
12687
|
+
["--only a,b", "house: deja prendidas S\xD3LO estas skills de Ghosty (las dem\xE1s apagadas)"],
|
|
12688
|
+
["--enable / --disable a,b", "house: prende / apaga estas skills de Ghosty"],
|
|
12689
|
+
["--file FILE", "add: sube un SKILL.md"],
|
|
12690
|
+
["--dir FOLDER", "add: sube la carpeta entera de una skill (SKILL.md + archivos); restaura un respaldo"],
|
|
12691
|
+
["--yes", "rm: se salta la confirmaci\xF3n (obligatorio sin terminal)"]
|
|
12692
|
+
],
|
|
12693
|
+
notes: [
|
|
12694
|
+
"rm guarda una copia en ~/.config/ghosty/trash/ e imprime el comando que la restaura.",
|
|
12695
|
+
"templates lee una m\xE1quina viva (corre un turno antes). La plantilla propia de un agente es <skill>/pdf-templates/<name>.html en cualquiera de sus skills; le gana a una de casa con el mismo nombre."
|
|
12696
|
+
]
|
|
12697
|
+
},
|
|
12698
|
+
dbs: {
|
|
12699
|
+
summary: "Bases de datos que un agente puede usar, y qu\xE9 puede escribir desde canales de clientes.",
|
|
12700
|
+
replace: [
|
|
12301
12701
|
["# reads $EASYBITS_API_KEY", "# lee $EASYBITS_API_KEY"],
|
|
12302
12702
|
["# totequim-productos.csv (Excel)", "# totequim-productos.csv (Excel)"]
|
|
12303
12703
|
],
|
|
@@ -12527,6 +12927,10 @@ var HELPS_ES = {
|
|
|
12527
12927
|
summary: "Los tableros de ventas de un ESPACIO: listarlos, crear uno (copiando las columnas de otro), elegir a d\xF3nde manda sus tarjetas un agente y mover tarjetas entre tableros.",
|
|
12528
12928
|
replace: [['"Name"', '"Nombre"']],
|
|
12529
12929
|
flags: [
|
|
12930
|
+
["--add / --remove EMAIL", "access: agrega o quita de la lista \xABs\xF3lo estas personas\xBB del tablero (repetible o separado por comas; s\xF3lo miembros del espacio)"],
|
|
12931
|
+
["--restrict", "access: vuelve de lista un tablero que ve todo el espacio (con quienes agregues con --add)"],
|
|
12932
|
+
["--everyone", "access: regresa a \xABlo ve todo el espacio\xBB"],
|
|
12933
|
+
["--until D", "access: temporal \u2014 se retira solo en esa fecha (fin del d\xEDa, CDMX) o tras 14d / 12h"],
|
|
12530
12934
|
["--columns-from B", "create: copia las columnas de ese tablero (main, un nombre o un id) en vez de las de siempre"],
|
|
12531
12935
|
["--from / --to B", "move-cards: tableros por nombre, id o main"],
|
|
12532
12936
|
["--integration ID | --phone N | --all", "move-cards: qu\xE9 tarjetas (el filtro es obligatorio)"],
|
|
@@ -12536,7 +12940,8 @@ var HELPS_ES = {
|
|
|
12536
12940
|
notes: [
|
|
12537
12941
|
"assign cambia a d\xF3nde van las tarjetas NUEVAS; move-cards trae las que ya existen (hilo, pedidos, actividad) con folio nuevo. Una tarjeta cuya conversaci\xF3n ya est\xE1 en el tablero destino se salta.",
|
|
12538
12942
|
"Leer requiere ser miembro; cambiar requiere ser due\xF1o o staff del espacio.",
|
|
12539
|
-
"rm s\xF3lo borra un tablero vac\xEDo que no sea el principal."
|
|
12943
|
+
"rm s\xF3lo borra un tablero vac\xEDo que no sea el principal.",
|
|
12944
|
+
"access sin flags dice qui\xE9n ve el tablero; due\xF1o y staff ven todos. Por qu\xE9 alguien lo ve: ghosty access why <correo> --workspace <espacio> --board <tablero>."
|
|
12540
12945
|
]
|
|
12541
12946
|
},
|
|
12542
12947
|
cards: {
|
|
@@ -12645,11 +13050,21 @@ var HELPS_ES = {
|
|
|
12645
13050
|
"Errores de slug: slug_invalid, slug_taken, slug_unsupported (exit 1, no cambia nada)."
|
|
12646
13051
|
]
|
|
12647
13052
|
},
|
|
13053
|
+
access: {
|
|
13054
|
+
summary: "Por qu\xE9 alguien ve un agente o un tablero: todas las razones, no s\xF3lo la que gana (due\xF1o, asiento en el espacio, compartido, staff asignado, la lista del tablero) y cu\xE1ndo vence lo temporal.",
|
|
13055
|
+
flags: [
|
|
13056
|
+
["--workspace W", "el espacio del tablero (o ghosty use <espacio>)"],
|
|
13057
|
+
["--board B", "tablero por nombre, id o main (default)"]
|
|
13058
|
+
],
|
|
13059
|
+
notes: ["Lo pregunta quien administra lo preguntado: el due\xF1o del agente o del espacio, un admin del espacio, o staff.", "Dar o quitar acceso: ghosty spaces members add|rm, ghosty boards access."]
|
|
13060
|
+
},
|
|
12648
13061
|
spaces: {
|
|
12649
13062
|
summary: "Espacios: crea uno a tu nombre (prueba), lista los tuyos (o, staff, los de cualquiera) y operaciones del staff de Ghosty \u2014 entrar/salir del espacio de un cliente, cambiar su combo, mover \xABpagado hasta\xBB, renombrar su slug, cambiar de due\xF1o \u2014 y, due\xF1o o staff, archivarlo o restaurarlo. Cada cambio queda en la bit\xE1cora del espacio.",
|
|
12650
13063
|
flags: [
|
|
12651
13064
|
["--user EMAIL", "ls (staff): los espacios de esa persona"],
|
|
12652
|
-
["--
|
|
13065
|
+
["--role R", "members add: member (default: tableros + editor de los agentes del espacio, sin llaves, cobro ni traspasos) | admin (adem\xE1s invita y quita gente)"],
|
|
13066
|
+
["--until D", "members add: asiento temporal que se retira solo en esa fecha (fin del d\xEDa, CDMX) o tras 14d / 12h \u2014 cuentas de revisor (Meta, Google, Apple). A quien ya est\xE1, le pone o mueve la fecha"],
|
|
13067
|
+
["--combo C", "set (staff): teams | sales | both | none (ni Teams ni Ventas) \u2014 sin Ventas sus tableros existen pero nadie los ve; create: distinto de teams, s\xF3lo staff"],
|
|
12653
13068
|
["--model-cap X", "set (staff): el modelo m\xE1s caro que puede elegir el espacio \u2014 0.25 econ\xF3micos, 1 est\xE1ndar (Sonnet), 4 todos; none = el de su plan"],
|
|
12654
13069
|
["--house-claude on|off", "set (staff): sus agentes corren con la Claude de Ghosty si el due\xF1o no trae llave; recicla sus cajas de Claude"],
|
|
12655
13070
|
["--until DATE", "renew: el nuevo \xABpagado hasta\xBB (AAAA-MM-DD)"],
|
|
@@ -12720,7 +13135,7 @@ var HELPS_ES = {
|
|
|
12720
13135
|
"Qui\xE9n es @plan o @build: ghosty agents ls --handle plan --workspace SLUG.",
|
|
12721
13136
|
"stats: pedidos, % mezclados, mediana de minutos hasta el PR y hasta el merge, vueltas @check\u2192@build y CI rojo por pedido, y costo por pedido y por PR mezclado. El costo incluye el primer turno de @plan en el hilo, antes de que naciera el pedido.",
|
|
12722
13137
|
"--timing lee la transcripci\xF3n de cada rol: los motores sin una (ACP) salen con minutos y costo, pero sin comandos. Tambi\xE9n lista los atascos: un comando abierto 8+ min, el mismo comando 4 veces, el mismo error 3 veces, ir y venir entre dos acciones, o apt install dentro de una caja.",
|
|
12723
|
-
"why: si el pedido no fue sano (atascos, @build de m\xE1s de 30 min, vueltas, CI rojo, escalado), una categor\xEDa (missing_service, unresolved_build_or_tests, fixed_strategy\u2026), el paso cr\xEDtico con su evidencia y qu\xE9 cambiar la pr\xF3xima vez. Un pedido sano no llama al modelo. Cuando un pedido cierra sin ser sano, el room recibe este resumen en su hilo.",
|
|
13138
|
+
"why: si el pedido no fue sano (atascos, @build de m\xE1s de 30 min, vueltas, CI rojo, escalado), una categor\xEDa (missing_service, unresolved_build_or_tests, fixed_strategy\u2026), el paso cr\xEDtico con su evidencia y qu\xE9 cambiar la pr\xF3xima vez. Primero cruza los criterios del plan aprobado con la evidencia: aprobado sin la preview que ped\xEDa un criterio, mezclado sin preview, smoke rojo sobre el commit mezclado o criterio de CI con CI none \u2192 approved_unmet_criterion, arriba de cualquier atasco. Un pedido sano no llama al modelo. Cuando un pedido cierra sin ser sano, el room recibe este resumen en su hilo.",
|
|
12724
13139
|
"Mientras un rol trabaja, si se atora el room recibe un \u23F3 en el hilo y al rol se le dice qu\xE9 revisar; desde la segunda vez en el mismo pedido, quien lo pidi\xF3 recibe un push."
|
|
12725
13140
|
]
|
|
12726
13141
|
}
|
|
@@ -13275,9 +13690,14 @@ HELPS.boards = {
|
|
|
13275
13690
|
'ghosty boards create <workspace> "Name" [--columns-from main|<board>]',
|
|
13276
13691
|
"ghosty boards assign <agent-id> <board|main>",
|
|
13277
13692
|
"ghosty boards move-cards <workspace> --from <board> --to <board> [--integration ID | --phone N | --all] [--dry-run] [--yes]",
|
|
13278
|
-
'ghosty boards rm <workspace> "Name" [--yes]'
|
|
13693
|
+
'ghosty boards rm <workspace> "Name" [--yes]',
|
|
13694
|
+
"ghosty boards access <workspace> [board|main] [--add EMAIL] [--remove EMAIL] [--restrict] [--everyone] [--until 2026-10-28|14d]"
|
|
13279
13695
|
],
|
|
13280
13696
|
flags: [
|
|
13697
|
+
["--add / --remove EMAIL", "access: add to or take off the board's \xABonly these people\xBB list (repeatable or comma-separated; only workspace members)"],
|
|
13698
|
+
["--restrict", "access: turn a whole-workspace board into a list (with the people you --add)"],
|
|
13699
|
+
["--everyone", "access: back to \xABthe whole workspace sees it\xBB"],
|
|
13700
|
+
["--until D", "access: temporary \u2014 removed automatically on that date (end of day, CDMX) or after 14d / 12h"],
|
|
13281
13701
|
["--columns-from B", "create: copy the columns of that board (main, a name or an id) instead of the default ones"],
|
|
13282
13702
|
["--from / --to B", "move-cards: boards by name, id or main"],
|
|
13283
13703
|
["--integration ID | --phone N | --all", "move-cards: which cards (a filter is required)"],
|
|
@@ -13285,7 +13705,7 @@ HELPS.boards = {
|
|
|
13285
13705
|
["--yes", "move-cards: skip the confirmation (required without a terminal)"]
|
|
13286
13706
|
],
|
|
13287
13707
|
examples: ["ghosty boards ls siiqtec", 'ghosty boards create siiqtec "Siiqtec - Ixmiquilpan" --columns-from main', 'ghosty boards assign <agent-id> "Siiqtec - Ixmiquilpan"', 'ghosty boards move-cards siiqtec --from main --to "Siiqtec - Ixmiquilpan" --integration 6a3b02ad\u2026 --dry-run'],
|
|
13288
|
-
notes: ["assign changes where NEW cards go; move-cards brings the existing ones (thread, orders, activity) with a new folio. A card whose conversation is already on the target board is skipped.", "Reading needs membership; changing needs owner or staff of the workspace.", "rm only deletes an empty board that is not the main one."],
|
|
13708
|
+
notes: ["assign changes where NEW cards go; move-cards brings the existing ones (thread, orders, activity) with a new folio. A card whose conversation is already on the target board is skipped.", "Reading needs membership; changing needs owner or staff of the workspace.", "rm only deletes an empty board that is not the main one.", "access without flags shows who sees the board; owner and staff always see every board. Why someone sees it: ghosty access why <email> --workspace <ws> --board <board>."],
|
|
13289
13709
|
learn: `${REF}#tablero`
|
|
13290
13710
|
};
|
|
13291
13711
|
HELPS.cards = {
|
|
@@ -13423,10 +13843,12 @@ HELPS.novedades = {
|
|
|
13423
13843
|
};
|
|
13424
13844
|
HELPS.spaces = {
|
|
13425
13845
|
summary: "Workspaces: create one of your own (trial), list yours (or, staff, anyone's), and Ghosty staff operations \u2014 join/leave a client's workspace, change its combo, move \xABpaid until\xBB, rename its slug, change its owner \u2014 and, owner or staff, archive or restore it. Each change is logged in the workspace's audit.",
|
|
13426
|
-
usage: ["ghosty spaces ls [--user EMAIL]", "ghosty spaces create <slug> [--combo teams|sales|both] [--dry-run]", "ghosty spaces join|leave <workspace>", "ghosty spaces set <workspace> --combo teams|sales|both | --model-cap 0.25|1|4|none | --house-claude on|off [--dry-run]", "ghosty spaces renew <workspace> --until YYYY-MM-DD [--note TEXT] [--dry-run] [--yes]", "ghosty spaces rename <old> <new> [--dry-run] [--yes]", "ghosty spaces archive|restore <workspace> [--dry-run] [--yes]", "ghosty spaces transfer <workspace> --to EMAIL [--keep-as admin|member|none] [--copy-keys] [--dry-run] [--yes]", "ghosty spaces log <workspace> [--since 30d] [--action workspace] [--limit N]"],
|
|
13846
|
+
usage: ["ghosty spaces ls [--user EMAIL]", "ghosty spaces create <slug> [--combo teams|sales|both|none] [--dry-run]", "ghosty spaces join|leave <workspace>", "ghosty spaces set <workspace> --combo teams|sales|both|none | --model-cap 0.25|1|4|none | --house-claude on|off [--dry-run]", "ghosty spaces renew <workspace> --until YYYY-MM-DD [--note TEXT] [--dry-run] [--yes]", "ghosty spaces rename <old> <new> [--dry-run] [--yes]", "ghosty spaces archive|restore <workspace> [--dry-run] [--yes]", "ghosty spaces transfer <workspace> --to EMAIL [--keep-as admin|member|none] [--copy-keys] [--dry-run] [--yes]", "ghosty spaces log <workspace> [--since 30d] [--action workspace] [--limit N]", "ghosty spaces members ls|add|rm <workspace> [email,\u2026] [--role member|admin] [--until 2026-10-28|14d] [--yes]"],
|
|
13427
13847
|
flags: [
|
|
13428
13848
|
["--user EMAIL", "ls (staff): that person's workspaces"],
|
|
13429
|
-
["--
|
|
13849
|
+
["--role R", "members add: member (default: boards + editor of the workspace's agents, no keys, billing or transfers) | admin (also invites and removes people)"],
|
|
13850
|
+
["--until D", "members add: temporary seat, removed automatically on that date (end of day, CDMX) or after 14d / 12h \u2014 reviewer accounts (Meta, Google, Apple). On someone already in, it sets or moves the date"],
|
|
13851
|
+
["--combo C", "set (staff): teams | sales | both | none (neither Teams nor Sales) \u2014 without Sales its boards exist but nobody sees them; create: other than teams, staff only"],
|
|
13430
13852
|
["--model-cap X", "set (staff): the most expensive model the workspace can pick \u2014 0.25 economy, 1 standard (Sonnet), 4 everything; none = its plan's"],
|
|
13431
13853
|
["--house-claude on|off", "set (staff): its agents run on Ghosty's Claude when the owner brings no key; recycles their Claude boxes"],
|
|
13432
13854
|
["--until DATE", "renew: the new \xABpaid until\xBB (YYYY-MM-DD)"],
|
|
@@ -13438,11 +13860,22 @@ HELPS.spaces = {
|
|
|
13438
13860
|
["-n, --dry-run", "show what changes, change nothing"],
|
|
13439
13861
|
["--yes", "skip the confirmation (required without a terminal)"]
|
|
13440
13862
|
],
|
|
13441
|
-
examples: ["ghosty spaces ls", "ghosty spaces create mailmask --dry-run", "ghosty spaces ls --user brenda@siiqtec.com", "ghosty spaces join denik", "ghosty spaces set denik --combo sales --dry-run", "ghosty spaces set mailmask --model-cap 4 --house-claude on", 'ghosty spaces renew descti --until 2026-11-01 --note "pag\xF3 octubre"', "ghosty spaces rename totequim siiqtec --dry-run", "ghosty spaces archive box-xfer-test --dry-run", "ghosty spaces transfer siiqtec --to siiqtec@gmail.com --keep-as admin --copy-keys --dry-run", "ghosty spaces log siiqtec --since 30d"],
|
|
13863
|
+
examples: ["ghosty spaces ls", "ghosty spaces create mailmask --dry-run", "ghosty spaces ls --user brenda@siiqtec.com", "ghosty spaces join denik", "ghosty spaces set denik --combo sales --dry-run", "ghosty spaces set mailmask --model-cap 4 --house-claude on", 'ghosty spaces renew descti --until 2026-11-01 --note "pag\xF3 octubre"', "ghosty spaces rename totequim siiqtec --dry-run", "ghosty spaces archive box-xfer-test --dry-run", "ghosty spaces transfer siiqtec --to siiqtec@gmail.com --keep-as admin --copy-keys --dry-run", "ghosty spaces log siiqtec --since 30d", "ghosty spaces members add business chrome-review@ghosty.studio --until 14d", "ghosty spaces members rm business chrome-review@ghosty.studio --yes"],
|
|
13442
13864
|
notes: ["create follows the same rules as the web: you own it, it starts as a 30-day trial, your email must be confirmed, and your plan caps how many you own. Next: ghosty partner enable <slug>.", "With a Stripe subscription renew refuses: the paid invoice moves the date.", "rename changes only the slug (id and namespace stay, so board, Stripe and WhatsApp keep working); old <slug>.sales links stop working.", "archive does what Settings \u2192 Archive does: the workspace leaves /app and spaces ls, its agents and data stay; it asks you to type the slug. Undo: ghosty spaces restore <slug>. Logged as workspace.archive / workspace.restore.", "transfer moves the agents with the workspace: ACP boxes move to the new owner with their /data, pool boxes are recycled (the owner is baked into the box); without --copy-keys the dry run lists which keys the new owner lacks \u2014 those agents would stop answering."],
|
|
13443
13865
|
learn: `${REF}#espacios`
|
|
13444
13866
|
};
|
|
13445
13867
|
HELPS.workspaces = HELPS.spaces;
|
|
13868
|
+
HELPS.access = {
|
|
13869
|
+
summary: "Why someone sees an agent or a board: every reason, not only the winning one (owner, workspace seat, share, assigned staff, the board's list) and when temporary access expires.",
|
|
13870
|
+
usage: ["ghosty access why <email> <agent-id>", "ghosty access why <email> --workspace <workspace> [--board <board|main>]"],
|
|
13871
|
+
flags: [
|
|
13872
|
+
["--workspace W", "the board's workspace (or ghosty use <workspace>)"],
|
|
13873
|
+
["--board B", "board by name, id or main (default)"]
|
|
13874
|
+
],
|
|
13875
|
+
examples: ["ghosty access why chrome-review@ghosty.studio cmu7pgbyr0001gee3ruk172mm", 'ghosty access why ana@siiqtec.com --workspace siiqtec --board "Siiqtec - Ixmiquilpan"'],
|
|
13876
|
+
notes: ["Asked by whoever administers the target: the agent's or workspace's owner, a workspace admin, or staff.", "Give or take access: ghosty spaces members add|rm, ghosty boards access."],
|
|
13877
|
+
learn: `${REF}#acceso`
|
|
13878
|
+
};
|
|
13446
13879
|
HELPS.sites = {
|
|
13447
13880
|
summary: "Sites your agents publish at <slug>.ghosty.page. On the Free plan a site PAUSES after 30 days without changes (nothing is deleted; it comes back as-is when pinned). \xABPinned sites\xBB ($49 USD/yr or $5 USD/mo \u2014 $990 / $99 MXN \u2014 includes up to 3 sites; add 3 more for the same price) never pause and carry no \xABMade with Ghosty\xBB banner. Staff also publish Ghosty's own house sites and change any site's slug.",
|
|
13448
13881
|
usage: [
|
|
@@ -13547,7 +13980,7 @@ HELPS.factory = {
|
|
|
13547
13980
|
["--yes", "rename: skip the confirmation (required without a terminal)"]
|
|
13548
13981
|
],
|
|
13549
13982
|
examples: ["ghosty factory runs ls --workspace business --room mailmask", "ghosty factory runs show 15 --workspace business", "ghosty factory runs show 13 --timing --workspace mercadito-verde", "ghosty factory runs why 13 --workspace mercadito-verde", "ghosty factory runs stats --since 7d --workspace mercadito-verde", 'ghosty factory runs rename 15 "Docs del CLI al d\xEDa" --workspace business --dry-run'],
|
|
13550
|
-
notes: ["Reading needs membership in the workspace; rename needs owner, admin or Ghosty staff, and is logged (factory.run_rename). The room's card picks the new title up on its next refresh.", "Who is @plan or @build: ghosty agents ls --handle plan --workspace SLUG.", "stats: runs, % merged, median minutes to PR and to merge, @check\u2192@build loops and red CI per run, and cost per run and per merged PR. The cost counts @plan's first turn in the thread, before the run existed.", "--timing reads each role's transcript: engines without one (ACP) show minutes and cost but no commands. It also lists stuck patterns: a command open 8+ min, the same command 4 times, the same error 3 times, going back and forth, or apt install inside a box.", "why: if the run wasn't healthy (stuck patterns, @build over 30 min, loops, red CI, escalated), a category (missing_service, unresolved_build_or_tests, fixed_strategy\u2026), the critical step with its evidence and what to change next time. A healthy run doesn't call the model. When a run closes unhealthy, the room gets this summary in its thread.", "While a role works, if it gets stuck the room gets a \u23F3 message in the thread and the role is told what to check; from the second time in the same run, whoever asked gets a push."],
|
|
13983
|
+
notes: ["Reading needs membership in the workspace; rename needs owner, admin or Ghosty staff, and is logged (factory.run_rename). The room's card picks the new title up on its next refresh.", "Who is @plan or @build: ghosty agents ls --handle plan --workspace SLUG.", "stats: runs, % merged, median minutes to PR and to merge, @check\u2192@build loops and red CI per run, and cost per run and per merged PR. The cost counts @plan's first turn in the thread, before the run existed.", "--timing reads each role's transcript: engines without one (ACP) show minutes and cost but no commands. It also lists stuck patterns: a command open 8+ min, the same command 4 times, the same error 3 times, going back and forth, or apt install inside a box.", "why: if the run wasn't healthy (stuck patterns, @build over 30 min, loops, red CI, escalated), a category (missing_service, unresolved_build_or_tests, fixed_strategy\u2026), the critical step with its evidence and what to change next time. First it checks the approved plan's criteria against the evidence: approved without the preview a criterion asked for, merged without preview, smoke failed on the merged commit, or a CI criterion with CI none \u2192 approved_unmet_criterion, above any stuck pattern. A healthy run doesn't call the model. When a run closes unhealthy, the room gets this summary in its thread.", "While a role works, if it gets stuck the room gets a \u23F3 message in the thread and the role is told what to check; from the second time in the same run, whoever asked gets a push."],
|
|
13551
13984
|
learn: `${REF}#fabrica`
|
|
13552
13985
|
};
|
|
13553
13986
|
function helpText(cmd) {
|
|
@@ -13564,688 +13997,378 @@ function helpText(cmd) {
|
|
|
13564
13997
|
"",
|
|
13565
13998
|
...section(es ? "USO" : "USAGE", h.usage.map(fix)),
|
|
13566
13999
|
...h.flags?.length ? section(es ? "OPCIONES" : "FLAGS", h.flags.map(([f, d]) => `${f.padEnd(w)}${d}`)) : [],
|
|
13567
|
-
...section(es ? "EJEMPLOS" : "EXAMPLES", h.examples.map((e) => `$ ${fix(e)}`)),
|
|
13568
|
-
...h.notes?.length ? section(es ? "NOTAS" : "NOTES", h.notes) : [],
|
|
13569
|
-
bold(es ? "M\xC1S INFORMACI\xD3N" : "LEARN MORE"),
|
|
13570
|
-
es ? ` Agrega --json para salida para m\xE1quinas. C\xF3digos de salida: 0 bien \xB7 1 error de la API \xB7 2 uso \xB7 3 sin sesi\xF3n.` : ` Add --json for machine output. Exit codes: 0 ok \xB7 1 API error \xB7 2 usage \xB7 3 not signed in.`,
|
|
13571
|
-
` ${dim(h.learn ?? DOCS)}`
|
|
13572
|
-
].join("\n");
|
|
13573
|
-
}
|
|
13574
|
-
|
|
13575
|
-
// src/update.ts
|
|
13576
|
-
import { mkdir as mkdir5, readFile as readFile9, writeFile as writeFile7 } from "node:fs/promises";
|
|
13577
|
-
import { homedir as homedir3 } from "node:os";
|
|
13578
|
-
import { dirname as dirname3, join as join7 } from "node:path";
|
|
13579
|
-
var FILE = join7(process.env.XDG_CONFIG_HOME || join7(homedir3(), ".config"), "ghosty", "update.json");
|
|
13580
|
-
var TTL = 60 * 60 * 1e3;
|
|
13581
|
-
var UPGRADE = "npm i -g @ghostystudio/cli@latest";
|
|
13582
|
-
function newer(a, b) {
|
|
13583
|
-
const pa = a.split(".").map(Number);
|
|
13584
|
-
const pb = b.split(".").map(Number);
|
|
13585
|
-
for (let i = 0; i < 3; i++) if ((pa[i] ?? 0) !== (pb[i] ?? 0)) return (pa[i] ?? 0) > (pb[i] ?? 0);
|
|
13586
|
-
return false;
|
|
13587
|
-
}
|
|
13588
|
-
async function latestVersion(current2) {
|
|
13589
|
-
if (process.env.GHOSTY_NO_UPDATE_CHECK || process.env.CI) return null;
|
|
13590
|
-
let cache2 = {};
|
|
13591
|
-
try {
|
|
13592
|
-
cache2 = JSON.parse(await readFile9(FILE, "utf8"));
|
|
13593
|
-
} catch {
|
|
13594
|
-
}
|
|
13595
|
-
if (current2 && cache2.latest && newer(current2, cache2.latest)) cache2.checkedAt = 0;
|
|
13596
|
-
if (!cache2.checkedAt || Date.now() - cache2.checkedAt > TTL) {
|
|
13597
|
-
try {
|
|
13598
|
-
const r = await fetch("https://registry.npmjs.org/@ghostystudio/cli/latest", { signal: AbortSignal.timeout(1500) });
|
|
13599
|
-
const latest = (await r.json()).version;
|
|
13600
|
-
if (latest) cache2 = { latest, checkedAt: Date.now() };
|
|
13601
|
-
await mkdir5(dirname3(FILE), { recursive: true });
|
|
13602
|
-
await writeFile7(FILE, JSON.stringify(cache2));
|
|
13603
|
-
} catch {
|
|
13604
|
-
}
|
|
13605
|
-
}
|
|
13606
|
-
return cache2.latest ?? null;
|
|
13607
|
-
}
|
|
13608
|
-
async function updateNotice(current2) {
|
|
13609
|
-
const latest = await latestVersion(current2);
|
|
13610
|
-
return latest && newer(latest, current2) ? t(`Update available: ${current2} \u2192 ${latest}. Run: ${UPGRADE}`, `Hay versi\xF3n nueva: ${current2} \u2192 ${latest}. Corre: ${UPGRADE}`) : null;
|
|
13611
|
-
}
|
|
13612
|
-
|
|
13613
|
-
// src/resolve.ts
|
|
13614
|
-
var looksLikeId = (s2) => /^c[a-z0-9]{20,}$/.test(s2) || /^[0-9a-f]{24}$/.test(s2);
|
|
13615
|
-
function pickAgent(list, ref, workspace) {
|
|
13616
|
-
const want = ref.trim().toLowerCase();
|
|
13617
|
-
let hits = list.filter((a) => a.nombre.trim().toLowerCase() === want);
|
|
13618
|
-
if (hits.length > 1 && workspace) {
|
|
13619
|
-
const here = hits.filter((a) => a.espacio?.nombre === workspace);
|
|
13620
|
-
if (here.length) hits = here;
|
|
13621
|
-
}
|
|
13622
|
-
if (hits.length === 1) return hits[0].id;
|
|
13623
|
-
if (!hits.length) {
|
|
13624
|
-
const near = list.filter((a) => a.nombre.toLowerCase().includes(want)).slice(0, 5);
|
|
13625
|
-
const names2 = near.map((a) => `${a.nombre} (${a.id})`).join(", ");
|
|
13626
|
-
throw new CliError(t(`No agent named "${ref}".`, `No hay ning\xFAn agente llamado "${ref}".`), EXIT.USAGE, near.length ? t(`Did you mean: ${names2}?`, `\xBFQuisiste decir: ${names2}?`) : t("List them: ghosty agents ls", "L\xEDstalos: ghosty agents ls"));
|
|
13627
|
-
}
|
|
13628
|
-
const where = (a) => a.espacio?.tipo === "workspace" ? a.espacio.nombre : a.espacio?.tipo ?? "?";
|
|
13629
|
-
const ids = hits.map((a) => ` ${a.id} ${a.motor ?? ""} ${where(a)}`).join("\n");
|
|
13630
|
-
throw new CliError(t(`${hits.length} agents are named "${ref}".`, `${hits.length} agentes se llaman "${ref}".`), EXIT.USAGE, t(`Use the id:
|
|
13631
|
-
${ids}`, `Usa el id:
|
|
13632
|
-
${ids}`));
|
|
13633
|
-
}
|
|
13634
|
-
var cache = null;
|
|
13635
|
-
function listAgents() {
|
|
13636
|
-
cache ??= api("/api/v2/me/agents?client=cli").then((r) => r.agentes);
|
|
13637
|
-
return cache;
|
|
13638
|
-
}
|
|
13639
|
-
async function resolveAgent(ref, workspace) {
|
|
13640
|
-
if (!ref || looksLikeId(ref)) return ref;
|
|
13641
|
-
return pickAgent(await listAgents(), ref, workspace);
|
|
13642
|
-
}
|
|
13643
|
-
function agentArgIndex(pos) {
|
|
13644
|
-
const [cmd, sub] = pos;
|
|
13645
|
-
switch (cmd) {
|
|
13646
|
-
case "agents":
|
|
13647
|
-
if (sub === "docs" || sub === "documents" || sub === "teams") return 3;
|
|
13648
|
-
return sub && !["ls", "list", "create", "new"].includes(sub) ? 2 : null;
|
|
13649
|
-
case "files":
|
|
13650
|
-
case "skills":
|
|
13651
|
-
case "mcp":
|
|
13652
|
-
case "dbs":
|
|
13653
|
-
case "db":
|
|
13654
|
-
return sub === "photos" ? 3 : 2;
|
|
13655
|
-
case "turns":
|
|
13656
|
-
return pos[1] === "stats" ? null : 2;
|
|
13657
|
-
case "board":
|
|
13658
|
-
case "conversations":
|
|
13659
|
-
case "schedule":
|
|
13660
|
-
return 2;
|
|
13661
|
-
case "try":
|
|
13662
|
-
case "chat":
|
|
13663
|
-
return 1;
|
|
13664
|
-
case "channels":
|
|
13665
|
-
return pos[2] === "groups" ? 4 : 3;
|
|
13666
|
-
case "boards":
|
|
13667
|
-
return sub === "assign" ? 2 : null;
|
|
13668
|
-
case "demos":
|
|
13669
|
-
case "demo":
|
|
13670
|
-
return sub === "history" ? 2 : null;
|
|
13671
|
-
default:
|
|
13672
|
-
return null;
|
|
13673
|
-
}
|
|
13674
|
-
}
|
|
13675
|
-
|
|
13676
|
-
// src/completion.ts
|
|
13677
|
-
import { mkdir as mkdir6, readFile as readFile10, writeFile as writeFile8 } from "node:fs/promises";
|
|
13678
|
-
import { homedir as homedir4 } from "node:os";
|
|
13679
|
-
import { join as join8 } from "node:path";
|
|
13680
|
-
var GLOBAL_FLAGS = ["--json", "--token", "--profile", "--yes", "--help", "--version", "--lang", "--dry-run"];
|
|
13681
|
-
var AGENT_FLAGS = /* @__PURE__ */ new Set(["--like", "--agent", "--prompt-base"]);
|
|
13682
|
-
var WORKSPACE_FLAGS = /* @__PURE__ */ new Set(["--workspace"]);
|
|
13683
|
-
function subcommandsOf(cmd) {
|
|
13684
|
-
const subs = /* @__PURE__ */ new Set();
|
|
13685
|
-
for (const u of HELPS[cmd]?.usage ?? []) {
|
|
13686
|
-
const m = new RegExp(`^ghosty ${cmd} ([a-z][a-z|-]*)`).exec(u);
|
|
13687
|
-
if (m) {
|
|
13688
|
-
for (const s2 of m[1].split("|")) if (!s2.includes("-") || /^[a-z]+-[a-z]+$/.test(s2)) subs.add(s2);
|
|
13689
|
-
}
|
|
13690
|
-
}
|
|
13691
|
-
return [...subs];
|
|
13692
|
-
}
|
|
13693
|
-
function flagsOf(cmd) {
|
|
13694
|
-
const own = /* @__PURE__ */ new Set();
|
|
13695
|
-
for (const [f] of HELPS[cmd]?.flags ?? []) for (const m of f.matchAll(/--[a-z][a-z-]*/g)) own.add(m[0]);
|
|
13696
|
-
for (const u of HELPS[cmd]?.usage ?? []) for (const m of u.matchAll(/--[a-z][a-z-]*/g)) own.add(m[0]);
|
|
13697
|
-
return [...own, ...GLOBAL_FLAGS];
|
|
13698
|
-
}
|
|
13699
|
-
function completionFor(words, current2, commands) {
|
|
13700
|
-
const prev = words[words.length - 1];
|
|
13701
|
-
if (prev && AGENT_FLAGS.has(prev)) return { kind: "agents" };
|
|
13702
|
-
if (prev && WORKSPACE_FLAGS.has(prev)) return { kind: "workspaces" };
|
|
13703
|
-
if (!words.length) return { kind: "words", words: commands };
|
|
13704
|
-
const [cmd, sub] = words;
|
|
13705
|
-
if (current2.startsWith("-")) return { kind: "words", words: flagsOf(cmd) };
|
|
13706
|
-
const pos = words.filter((w) => !w.startsWith("-"));
|
|
13707
|
-
if (cmd === "use" && pos.length === 1) return { kind: "workspaces" };
|
|
13708
|
-
if (cmd === "boards" && pos.length === 2 && sub !== "assign") return { kind: "workspaces" };
|
|
13709
|
-
if (cmd === "help" && pos.length === 1) return { kind: "words", words: commands };
|
|
13710
|
-
if (pos.length === 1 && cmd !== "try" && cmd !== "chat") {
|
|
13711
|
-
const subs = subcommandsOf(cmd);
|
|
13712
|
-
if (subs.length) return { kind: "words", words: subs };
|
|
13713
|
-
}
|
|
13714
|
-
if (agentArgIndex([...pos, current2]) === pos.length) return { kind: "agents" };
|
|
13715
|
-
return { kind: "words", words: [] };
|
|
13716
|
-
}
|
|
13717
|
-
var cacheFile = () => join8(process.env.XDG_CACHE_HOME || join8(homedir4(), ".cache"), "ghosty", `complete${process.env.GHOSTY_PROFILE ? `.${process.env.GHOSTY_PROFILE}` : ""}.json`);
|
|
13718
|
-
async function names() {
|
|
13719
|
-
try {
|
|
13720
|
-
const c = JSON.parse(await readFile10(cacheFile(), "utf8"));
|
|
13721
|
-
if (Date.now() - c.at < 5 * 6e4) return c;
|
|
13722
|
-
} catch {
|
|
13723
|
-
}
|
|
13724
|
-
const list = await listAgents();
|
|
13725
|
-
const agents = [...new Set(list.map((a) => a.nombre))];
|
|
13726
|
-
const workspaces = [...new Set(list.map((a) => a.espacio?.tipo === "workspace" ? a.espacio.nombre : void 0).filter((x) => !!x))];
|
|
13727
|
-
await mkdir6(join8(cacheFile(), ".."), { recursive: true }).catch(() => {
|
|
13728
|
-
});
|
|
13729
|
-
await writeFile8(cacheFile(), JSON.stringify({ at: Date.now(), agents, workspaces })).catch(() => {
|
|
13730
|
-
});
|
|
13731
|
-
return { agents, workspaces };
|
|
13732
|
-
}
|
|
13733
|
-
async function completeCmd(args, commands) {
|
|
13734
|
-
const current2 = args.length ? args[args.length - 1] : "";
|
|
13735
|
-
const words = args.slice(0, -1);
|
|
13736
|
-
const want = completionFor(words, current2, commands);
|
|
13737
|
-
let out2 = [];
|
|
13738
|
-
try {
|
|
13739
|
-
if (want.kind === "words") out2 = want.words;
|
|
13740
|
-
else out2 = (await names())[want.kind];
|
|
13741
|
-
} catch {
|
|
13742
|
-
out2 = [];
|
|
13743
|
-
}
|
|
13744
|
-
process.stdout.write(out2.filter((w) => w.toLowerCase().startsWith(current2.toLowerCase())).join("\n") + "\n");
|
|
13745
|
-
}
|
|
13746
|
-
function completionScript(shell) {
|
|
13747
|
-
if (shell === "bash") {
|
|
13748
|
-
return `# ghosty \u2014 bash completion: eval "$(ghosty completion bash)" en ~/.bashrc
|
|
13749
|
-
_ghosty() {
|
|
13750
|
-
# Las palabras ANTES de cambiar IFS: el bash 3.2 de macOS junta \${arr[@]:1:n} con un IFS propio.
|
|
13751
|
-
local words=("\${COMP_WORDS[@]:1:COMP_CWORD-1}") cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
13752
|
-
local IFS=$'\\n'
|
|
13753
|
-
COMPREPLY=( $(ghosty __complete -- "\${words[@]}" "$cur" 2>/dev/null) )
|
|
13754
|
-
}
|
|
13755
|
-
complete -o default -F _ghosty ghosty
|
|
13756
|
-
`;
|
|
13757
|
-
}
|
|
13758
|
-
if (shell === "zsh") {
|
|
13759
|
-
return `#compdef ghosty
|
|
13760
|
-
# ghosty \u2014 zsh completion: source <(ghosty completion zsh) en ~/.zshrc (despu\xE9s de compinit)
|
|
13761
|
-
_ghosty() {
|
|
13762
|
-
local -a opts
|
|
13763
|
-
opts=("\${(@f)$(ghosty __complete -- "\${(@)words[2,CURRENT-1]}" "\${words[CURRENT]}" 2>/dev/null)}")
|
|
13764
|
-
compadd -a opts
|
|
13765
|
-
}
|
|
13766
|
-
compdef _ghosty ghosty
|
|
13767
|
-
`;
|
|
13768
|
-
}
|
|
13769
|
-
if (shell === "fish") {
|
|
13770
|
-
return `# ghosty \u2014 fish completion: ghosty completion fish > ~/.config/fish/completions/ghosty.fish
|
|
13771
|
-
complete -c ghosty -f -a "(ghosty __complete -- (commandline -opc)[2..-1] (commandline -ct) 2>/dev/null)"
|
|
13772
|
-
`;
|
|
13773
|
-
}
|
|
13774
|
-
return null;
|
|
14000
|
+
...section(es ? "EJEMPLOS" : "EXAMPLES", h.examples.map((e) => `$ ${fix(e)}`)),
|
|
14001
|
+
...h.notes?.length ? section(es ? "NOTAS" : "NOTES", h.notes) : [],
|
|
14002
|
+
bold(es ? "M\xC1S INFORMACI\xD3N" : "LEARN MORE"),
|
|
14003
|
+
es ? ` Agrega --json para salida para m\xE1quinas. C\xF3digos de salida: 0 bien \xB7 1 error de la API \xB7 2 uso \xB7 3 sin sesi\xF3n.` : ` Add --json for machine output. Exit codes: 0 ok \xB7 1 API error \xB7 2 usage \xB7 3 not signed in.`,
|
|
14004
|
+
` ${dim(h.learn ?? DOCS)}`
|
|
14005
|
+
].join("\n");
|
|
13775
14006
|
}
|
|
13776
14007
|
|
|
13777
|
-
// src/
|
|
13778
|
-
|
|
13779
|
-
|
|
13780
|
-
|
|
13781
|
-
|
|
13782
|
-
|
|
13783
|
-
|
|
13784
|
-
|
|
13785
|
-
|
|
13786
|
-
|
|
13787
|
-
|
|
13788
|
-
|
|
13789
|
-
if (pos[2] === "enable" || pos[2] === "disable") {
|
|
13790
|
-
v[pos[2] === "enable" ? "on" : "off"] = true;
|
|
13791
|
-
pos.splice(2, 1);
|
|
13792
|
-
} else if (v.on || v.off) notes.push(t(`\`agents demo <agent> --${v.on ? "on" : "off"}\` is now \`agents demo ${v.on ? "enable" : "disable"} <agent>\`.`, `\`agents demo <agente> --${v.on ? "on" : "off"}\` ahora es \`agents demo ${v.on ? "enable" : "disable"} <agente>\`.`));
|
|
13793
|
-
if (v.expires !== void 0) v.vence = v.expires;
|
|
13794
|
-
else if (v.vence !== void 0) notes.push(t("`--vence` is now `--expires`.", "`--vence` ahora es `--expires`."));
|
|
13795
|
-
}
|
|
13796
|
-
if (cmd === "agents" && (sub === "embed" || sub === "widget") && (pos[2] === "enable" || pos[2] === "disable")) {
|
|
13797
|
-
v[pos[2] === "enable" ? "on" : "off"] = true;
|
|
13798
|
-
pos.splice(2, 1);
|
|
13799
|
-
}
|
|
13800
|
-
if (cmd === "channels" && pos[2] === "groups") {
|
|
13801
|
-
if (pos[3] === "enable" || pos[3] === "disable") {
|
|
13802
|
-
v[pos[3] === "enable" ? "on" : "off"] = true;
|
|
13803
|
-
pos[3] = "set";
|
|
13804
|
-
} else if (pos[3] === "set" && (v.on || v.off)) notes.push(t(`\`groups set \u2026 --${v.on ? "on" : "off"}\` is now \`groups ${v.on ? "enable" : "disable"} <agent> <group>\` (set keeps --role).`, `\`groups set \u2026 --${v.on ? "on" : "off"}\` ahora es \`groups ${v.on ? "enable" : "disable"} <agente> <grupo>\` (set se queda para --role).`));
|
|
13805
|
-
}
|
|
13806
|
-
return notes;
|
|
14008
|
+
// src/update.ts
|
|
14009
|
+
import { mkdir as mkdir5, readFile as readFile9, writeFile as writeFile7 } from "node:fs/promises";
|
|
14010
|
+
import { homedir as homedir3 } from "node:os";
|
|
14011
|
+
import { dirname as dirname3, join as join7 } from "node:path";
|
|
14012
|
+
var FILE = join7(process.env.XDG_CONFIG_HOME || join7(homedir3(), ".config"), "ghosty", "update.json");
|
|
14013
|
+
var TTL = 60 * 60 * 1e3;
|
|
14014
|
+
var UPGRADE = "npm i -g @ghostystudio/cli@latest";
|
|
14015
|
+
function newer(a, b) {
|
|
14016
|
+
const pa = a.split(".").map(Number);
|
|
14017
|
+
const pb = b.split(".").map(Number);
|
|
14018
|
+
for (let i = 0; i < 3; i++) if ((pa[i] ?? 0) !== (pb[i] ?? 0)) return (pa[i] ?? 0) > (pb[i] ?? 0);
|
|
14019
|
+
return false;
|
|
13807
14020
|
}
|
|
13808
|
-
|
|
13809
|
-
|
|
13810
|
-
|
|
13811
|
-
|
|
13812
|
-
|
|
13813
|
-
|
|
13814
|
-
async function agentsExport(id, v) {
|
|
13815
|
-
if (!id) throw usage(t("Missing agent.", "Falta el agente."), t("Example", "Ejemplo") + ": ghosty agents export pia-0 > pia.yaml \xB7 ghosty agents export pia-0 --out ./pia");
|
|
13816
|
-
const yaml = await (await request(`/api/v2/agents/${enc10(id)}/export`)).text();
|
|
13817
|
-
if (!v.out) {
|
|
13818
|
-
if (globals.json) return out((0, import_yaml.parse)(yaml));
|
|
13819
|
-
return void process.stdout.write(yaml);
|
|
13820
|
-
}
|
|
13821
|
-
const dir = resolve2(v.out);
|
|
13822
|
-
await mkdir7(dir, { recursive: true });
|
|
13823
|
-
await writeFile9(join9(dir, "agent.yaml"), yaml);
|
|
13824
|
-
const own = (0, import_yaml.parse)(yaml)["x-ghosty"]?.skills?.own ?? [];
|
|
13825
|
-
for (const slug of own) {
|
|
13826
|
-
const sk = await api(`/api/v2/agents/${enc10(id)}/skills/${enc10(slug)}`);
|
|
13827
|
-
await writeSkill(join9(dir, "skills", slug), sk);
|
|
14021
|
+
async function latestVersion(current2) {
|
|
14022
|
+
if (process.env.GHOSTY_NO_UPDATE_CHECK || process.env.CI) return null;
|
|
14023
|
+
let cache2 = {};
|
|
14024
|
+
try {
|
|
14025
|
+
cache2 = JSON.parse(await readFile9(FILE, "utf8"));
|
|
14026
|
+
} catch {
|
|
13828
14027
|
}
|
|
13829
|
-
|
|
13830
|
-
|
|
13831
|
-
|
|
13832
|
-
|
|
13833
|
-
|
|
13834
|
-
|
|
13835
|
-
|
|
13836
|
-
|
|
13837
|
-
|
|
13838
|
-
if (process.env[m[1]] !== void 0) o[k] = process.env[m[1]];
|
|
13839
|
-
else missing.push(m[1]);
|
|
14028
|
+
if (current2 && cache2.latest && newer(current2, cache2.latest)) cache2.checkedAt = 0;
|
|
14029
|
+
if (!cache2.checkedAt || Date.now() - cache2.checkedAt > TTL) {
|
|
14030
|
+
try {
|
|
14031
|
+
const r = await fetch("https://registry.npmjs.org/@ghostystudio/cli/latest", { signal: AbortSignal.timeout(1500) });
|
|
14032
|
+
const latest = (await r.json()).version;
|
|
14033
|
+
if (latest) cache2 = { latest, checkedAt: Date.now() };
|
|
14034
|
+
await mkdir5(dirname3(FILE), { recursive: true });
|
|
14035
|
+
await writeFile7(FILE, JSON.stringify(cache2));
|
|
14036
|
+
} catch {
|
|
13840
14037
|
}
|
|
13841
|
-
};
|
|
13842
|
-
const x = file["x-ghosty"];
|
|
13843
|
-
fill(x?.env);
|
|
13844
|
-
for (const s2 of x?.mcp ?? []) fill(s2.env), fill(s2.headers);
|
|
13845
|
-
return missing;
|
|
13846
|
-
}
|
|
13847
|
-
async function readSkills(dir) {
|
|
13848
|
-
const root = join9(dir, "skills");
|
|
13849
|
-
const out2 = {};
|
|
13850
|
-
const slugs = await readdir4(root, { withFileTypes: true }).catch(() => []);
|
|
13851
|
-
for (const e of slugs) {
|
|
13852
|
-
if (!e.isDirectory() || e.name.startsWith(".")) continue;
|
|
13853
|
-
const { markdown, assets } = await readSkillDir(join9(root, e.name));
|
|
13854
|
-
out2[e.name] = [{ path: "SKILL.md", contentBase64: Buffer.from(markdown).toString("base64") }, ...assets.map((a) => ({ path: a.name, contentBase64: a.contentBase64 }))];
|
|
13855
|
-
}
|
|
13856
|
-
return out2;
|
|
13857
|
-
}
|
|
13858
|
-
var line = (c) => c.op === "!" ? dim(`! ${c.what}`) : `${c.op === "+" ? lavender("+") : c.op === "-" ? red("-") : "~"} ${c.what}`;
|
|
13859
|
-
async function applyCmd(target, v) {
|
|
13860
|
-
if (!target) throw usage(t("Missing file or directory.", "Falta el archivo o el directorio."), t("Example: ghosty apply pia.yaml --dry-run \xB7 ghosty apply ./pia (from agents export --out)", "Ejemplo: ghosty apply pia.yaml --dry-run \xB7 ghosty apply ./pia (de agents export --out)"));
|
|
13861
|
-
const isDir = (await stat2(target).catch(() => null))?.isDirectory() ?? false;
|
|
13862
|
-
const text = await readFile11(isDir ? join9(target, "agent.yaml") : target, "utf8");
|
|
13863
|
-
const file = (0, import_yaml.parse)(text);
|
|
13864
|
-
if (!file || typeof file !== "object") throw usage(t(`${target} is not a YAML/JSON agent file.`, `${target} no es un archivo de agente YAML/JSON.`));
|
|
13865
|
-
const missing = fillSecrets(file);
|
|
13866
|
-
if (missing.length && !globals.json) info(dim(t(`Secrets not in your environment keep their current value: ${missing.join(", ")}`, `Los secretos que no est\xE1n en tu entorno conservan su valor actual: ${missing.join(", ")}`)));
|
|
13867
|
-
const files = isDir ? await readSkills(target) : void 0;
|
|
13868
|
-
let id = v.agent ?? file["x-ghosty"]?.id;
|
|
13869
|
-
if (v.create) {
|
|
13870
|
-
const x = file["x-ghosty"] ?? {};
|
|
13871
|
-
const name = v.name ?? file.title;
|
|
13872
|
-
if (!name) throw usage(t("The file has no title: pass --name.", "El archivo no tiene t\xEDtulo: pasa --name."));
|
|
13873
|
-
if (v["dry-run"]) return out({ create: true, name, engine: x.engine, workspace: x.workspace ?? null }, () => `${lavender("+")} ${t("agent", "agente")} ${name} (${x.engine ?? t("default engine", "motor por default")}${x.workspace ? t(` in ${x.workspace}`, ` en ${x.workspace}`) : ""})
|
|
13874
|
-
${dim(t("Then every setting of the file is applied. Dry run: nothing created.", "Despu\xE9s se aplica cada ajuste del archivo. Simulaci\xF3n: no se cre\xF3 nada."))}`);
|
|
13875
|
-
requireYesIfHeadless(v.yes, `ghosty apply ${target} --create`);
|
|
13876
|
-
const created = await api("/api/v2/me/agents", { method: "POST", body: { name, ...x.engine ? { engine: x.engine } : {}, ...x.model ? { model: x.model } : {}, ...x.workspace ? { workspace: x.workspace } : {}, ...x.channels ? { channels: x.channels } : {} } });
|
|
13877
|
-
id = created.id;
|
|
13878
|
-
info(dim(t(`Created ${name} (${id}); applying the rest\u2026`, `${name} creado (${id}); aplicando lo dem\xE1s\u2026`)));
|
|
13879
|
-
} else {
|
|
13880
|
-
id = await resolveAgent(id);
|
|
13881
|
-
if (!id) throw usage(t("The file has no agent id.", "El archivo no trae id de agente."), t("Point it at one with --agent <name|id>, or make a new one with --create.", "Ap\xFAntalo a uno con --agent <nombre|id>, o crea uno nuevo con --create."));
|
|
13882
14038
|
}
|
|
13883
|
-
|
|
13884
|
-
const body = { spec, ...files ? { files } : {}, ...v.prune ? { prune: true } : {}, ...v["no-notify"] ? { notify: false } : {} };
|
|
13885
|
-
const path = `/api/v2/agents/${enc10(id)}/apply`;
|
|
13886
|
-
const plan = await api(path, { method: "POST", body: { ...body, dryRun: true } });
|
|
13887
|
-
const actionable = plan.plan.filter((c) => c.op !== "!");
|
|
13888
|
-
const text2 = plan.plan.map(line).join("\n") || dim(t("No changes: the agent already matches the file.", "Sin cambios: el agente ya coincide con el archivo."));
|
|
13889
|
-
if (v["dry-run"] || !actionable.length) return out(plan, () => `${bold(id)}
|
|
13890
|
-
${text2}${actionable.length ? `
|
|
13891
|
-
${dim(t("Dry run: nothing changed.", "Simulaci\xF3n: no cambi\xF3 nada."))}` : ""}`);
|
|
13892
|
-
const retry = `ghosty apply ${target}${v.agent ? ` --agent ${v.agent}` : ""}${v.prune ? " --prune" : ""}`;
|
|
13893
|
-
if (!v.create) requireYesIfHeadless(v.yes, retry);
|
|
13894
|
-
if (!v.create) await confirm(`${text2}
|
|
13895
|
-
${t(`Apply ${actionable.length} change(s) to ${id}?`, `\xBFAplicar ${actionable.length} cambio(s) a ${id}?`)}`, { yes: v.yes, retry });
|
|
13896
|
-
const r = await api(path, { method: "POST", body });
|
|
13897
|
-
out(r, () => `${lavender("\u2713")} ${t(`${r.applied?.length ?? 0} change(s) applied to ${id}.`, `${r.applied?.length ?? 0} cambio(s) aplicados a ${id}.`)}${r.failed ? `
|
|
13898
|
-
${red(t(`Stopped at \xAB${r.failed.what}\xBB: ${serverText(r.failed.error)}`, `Se detuvo en \xAB${r.failed.what}\xBB: ${r.failed.error}`))}` : ""}`);
|
|
13899
|
-
}
|
|
13900
|
-
|
|
13901
|
-
// src/commands/plan.ts
|
|
13902
|
-
async function planCmd(sub, slug, v, context) {
|
|
13903
|
-
if (sub !== "apply") throw usage(t(`Unknown plan subcommand: ${sub ?? "(none)"}.`, `Subcomando desconocido de plan: ${sub ?? "(ninguno)"}.`), "ghosty plan apply <workspace> [--dry-run]");
|
|
13904
|
-
slug ??= context;
|
|
13905
|
-
if (!slug) throw usage(t("Missing workspace.", "Falta el espacio."), "ghosty plan apply <workspace> [--dry-run] (or ghosty use <workspace>)");
|
|
13906
|
-
const path = `/api/v2/workspaces/${encodeURIComponent(slug)}/plan/apply`;
|
|
13907
|
-
const plan = await api(path, { method: "POST", body: { dryRun: true } });
|
|
13908
|
-
const money2 = (n) => `$${n.toLocaleString("es-MX")} MXN`;
|
|
13909
|
-
const text = [
|
|
13910
|
-
`${bold(plan.workspace)} ${dim(plan.scheduledFor ? t(`scheduled for ${plan.scheduledFor.slice(0, 10)}`, `programado para el ${plan.scheduledFor.slice(0, 10)}`) : "")}`,
|
|
13911
|
-
...plan.changes.map((c) => ` ~ ${c.label}: ${String(c.from)} \u2192 ${String(c.to)}`),
|
|
13912
|
-
` ${t("monthly", "al mes")}: ${money2(plan.monthlyTotal.from)} \u2192 ${money2(plan.monthlyTotal.to)}`
|
|
13913
|
-
].join("\n");
|
|
13914
|
-
if (v["dry-run"]) return out(plan, () => `${text}
|
|
13915
|
-
${dim(t("Dry run: nothing applied.", "Simulaci\xF3n: no se aplic\xF3 nada."))}`);
|
|
13916
|
-
requireYesIfHeadless(v.yes, `ghosty plan apply ${slug}`);
|
|
13917
|
-
await confirm(`${text}
|
|
13918
|
-
${t("Apply this plan now?", "\xBFAplicar este plan ya?")}`, { yes: v.yes, retry: `ghosty plan apply ${slug}` });
|
|
13919
|
-
const r = await api(path, { method: "POST", body: {} });
|
|
13920
|
-
out(r, () => `${lavender("\u2713")} ${r.applied ? t(`Plan applied to ${r.workspace}.`, `Plan aplicado a ${r.workspace}.`) : t("Nothing applied.", "No se aplic\xF3 nada.")}`);
|
|
14039
|
+
return cache2.latest ?? null;
|
|
13921
14040
|
}
|
|
13922
|
-
async function
|
|
13923
|
-
|
|
13924
|
-
|
|
13925
|
-
const rows = r.agents.map((a) => ({ agent: a.name ?? a.id, engine: a.engine, "per box": a.conversationsPerBox ?? "", boxes: a.boxes ?? "", on: a.boxesOn ?? "", spares: a.spares ?? "", "running now": a.activeTurns ?? "", ...a.error ? { note: a.error } : {} }));
|
|
13926
|
-
const head = `${bold(r.workspace)} ${dim(t(`plan: ${r.plan.parallel} in parallel \xB7 up to ${r.plan.maxBoxes} box(es) \xB7 ${r.plan.hotBoxes} always-on spare(s)`, `plan: ${r.plan.parallel} en paralelo \xB7 hasta ${r.plan.maxBoxes} caja(s) \xB7 ${r.plan.hotBoxes} spare(s) siempre encendido(s)`))}`;
|
|
13927
|
-
const space = r.space ? (r.space.used > r.space.limit ? (s2) => s2 : dim)(
|
|
13928
|
-
t(
|
|
13929
|
-
`${r.space.used} of ${r.space.limit} box(es) in use \xB7 ${r.space.spares} spare \xB7 ${r.space.asleep} asleep${r.space.used > r.space.limit ? " \xB7 OVER the limit" : ""}`,
|
|
13930
|
-
`${r.space.used} de ${r.space.limit} caja(s) \xB7 ${r.space.spares} spare \xB7 ${r.space.asleep} dormida(s)${r.space.used > r.space.limit ? " \xB7 SOBRE el tope" : ""}`
|
|
13931
|
-
)
|
|
13932
|
-
) : dim(t("(could not read the host)", "(no pude leer el host)"));
|
|
13933
|
-
out(r, () => `${head}
|
|
13934
|
-
${space}
|
|
13935
|
-
${table(rows, ["agent", "engine", "per box", "boxes", "on", "spares", "running now"])}
|
|
13936
|
-
${dim(t(`${r.totals.activeTurns} turn(s) running`, `${r.totals.activeTurns} turno(s) corriendo`))}`);
|
|
14041
|
+
async function updateNotice(current2) {
|
|
14042
|
+
const latest = await latestVersion(current2);
|
|
14043
|
+
return latest && newer(latest, current2) ? t(`Update available: ${current2} \u2192 ${latest}. Run: ${UPGRADE}`, `Hay versi\xF3n nueva: ${current2} \u2192 ${latest}. Corre: ${UPGRADE}`) : null;
|
|
13937
14044
|
}
|
|
13938
14045
|
|
|
13939
|
-
// src/
|
|
13940
|
-
var
|
|
13941
|
-
|
|
13942
|
-
|
|
13943
|
-
|
|
13944
|
-
|
|
13945
|
-
|
|
13946
|
-
|
|
13947
|
-
|
|
13948
|
-
if (
|
|
13949
|
-
|
|
13950
|
-
|
|
13951
|
-
}
|
|
13952
|
-
|
|
13953
|
-
|
|
13954
|
-
|
|
13955
|
-
|
|
13956
|
-
}
|
|
13957
|
-
|
|
13958
|
-
|
|
13959
|
-
if (/^(on|true|yes|s[ií])$/i.test(raw)) return true;
|
|
13960
|
-
if (/^(off|false|no)$/i.test(raw)) return false;
|
|
13961
|
-
throw usage(t(`${flag} takes on or off.`, `${flag} acepta on u off.`));
|
|
13962
|
-
}
|
|
13963
|
-
async function enginesCmd(sub, v) {
|
|
13964
|
-
if (sub && sub !== "ls" && sub !== "list") throw usage(t(`Unknown engines subcommand: ${sub}.`, `Subcomando de engines desconocido: ${sub}.`), "ghosty engines ls [--models]");
|
|
13965
|
-
const r = await api("/api/v2/engines");
|
|
13966
|
-
out(r, () => {
|
|
13967
|
-
if (!v.models) {
|
|
13968
|
-
const rows = r.engines.map((e) => ({ engine: e.id, provider: e.provider, default: e.defaultModel ?? "", models: e.models.map((m) => m.id).join(", ") }));
|
|
13969
|
-
return `${table(rows, ["engine", "provider", "default"])}
|
|
13970
|
-
${dim(t("Models per engine: ghosty engines ls --models", "Modelos de cada motor: ghosty engines ls --models"))}`;
|
|
13971
|
-
}
|
|
13972
|
-
return r.engines.map((e) => {
|
|
13973
|
-
const rows = e.models.map((m) => ({ model: m.id + (m.id === e.defaultModel ? " *" : ""), label: m.label, cost: `${m.multiplier}\xD7`, note: m.ownKeyOnly ? t("your own key only", "s\xF3lo con llave propia") : "" }));
|
|
13974
|
-
return `${bold(e.id)} ${dim(`${e.provider} \xB7 ${e.protocol}${e.vision ? t(" \xB7 sees images", " \xB7 ve im\xE1genes") : ""}`)}
|
|
13975
|
-
${table(rows, ["model", "label", "cost", "note"])}`;
|
|
13976
|
-
}).join("\n\n") + `
|
|
13977
|
-
${dim(t("* default \xB7 cost = balance multiplier per turn", "* por default \xB7 costo = multiplicador de saldo por turno"))}`;
|
|
13978
|
-
});
|
|
13979
|
-
}
|
|
13980
|
-
function bagsText(r) {
|
|
13981
|
-
const rows = r.bags.map((b) => ({
|
|
13982
|
-
bag: b.name,
|
|
13983
|
-
tokens: fmtTokens(b.tokens),
|
|
13984
|
-
used: `${fmtTokens(b.used)} (${Math.round(b.ratio * 100)}%)`,
|
|
13985
|
-
kind: b.recurring ? t("monthly", "mensual") : t(`one-time since ${b.since?.slice(0, 10)}`, `carga \xFAnica desde ${b.since?.slice(0, 10)}`),
|
|
13986
|
-
cap: b.hardCap ? t("cuts", "corta") : t("warns", "avisa"),
|
|
13987
|
-
agents: b.agents.map((a) => a.name ?? a.id).join(", ") || "\u2014"
|
|
13988
|
-
}));
|
|
13989
|
-
const free = r.unbagged.length ? `
|
|
13990
|
-
${dim(t(`Workspace balance (no bag): ${r.unbagged.map((a) => a.name ?? a.id).join(", ")}`, `Saldo del espacio (sin bolsa): ${r.unbagged.map((a) => a.name ?? a.id).join(", ")}`))}` : "";
|
|
13991
|
-
return `${bold(r.workspace)}
|
|
13992
|
-
${r.bags.length ? table(rows, ["bag", "tokens", "used", "kind", "cap", "agents"]) : dim(t("No bags: every agent uses the workspace balance.", "Sin bolsas: todos los agentes usan el saldo del espacio."))}${free}`;
|
|
14046
|
+
// src/resolve.ts
|
|
14047
|
+
var looksLikeId = (s2) => /^c[a-z0-9]{20,}$/.test(s2) || /^[0-9a-f]{24}$/.test(s2);
|
|
14048
|
+
function pickAgent(list, ref, workspace) {
|
|
14049
|
+
const want = ref.trim().toLowerCase();
|
|
14050
|
+
let hits = list.filter((a) => a.nombre.trim().toLowerCase() === want);
|
|
14051
|
+
if (hits.length > 1 && workspace) {
|
|
14052
|
+
const here = hits.filter((a) => a.espacio?.nombre === workspace);
|
|
14053
|
+
if (here.length) hits = here;
|
|
14054
|
+
}
|
|
14055
|
+
if (hits.length === 1) return hits[0].id;
|
|
14056
|
+
if (!hits.length) {
|
|
14057
|
+
const near = list.filter((a) => a.nombre.toLowerCase().includes(want)).slice(0, 5);
|
|
14058
|
+
const names2 = near.map((a) => `${a.nombre} (${a.id})`).join(", ");
|
|
14059
|
+
throw new CliError(t(`No agent named "${ref}".`, `No hay ning\xFAn agente llamado "${ref}".`), EXIT.USAGE, near.length ? t(`Did you mean: ${names2}?`, `\xBFQuisiste decir: ${names2}?`) : t("List them: ghosty agents ls", "L\xEDstalos: ghosty agents ls"));
|
|
14060
|
+
}
|
|
14061
|
+
const where = (a) => a.espacio?.tipo === "workspace" ? a.espacio.nombre : a.espacio?.tipo ?? "?";
|
|
14062
|
+
const ids = hits.map((a) => ` ${a.id} ${a.motor ?? ""} ${where(a)}`).join("\n");
|
|
14063
|
+
throw new CliError(t(`${hits.length} agents are named "${ref}".`, `${hits.length} agentes se llaman "${ref}".`), EXIT.USAGE, t(`Use the id:
|
|
14064
|
+
${ids}`, `Usa el id:
|
|
14065
|
+
${ids}`));
|
|
13993
14066
|
}
|
|
13994
|
-
|
|
13995
|
-
|
|
13996
|
-
|
|
13997
|
-
|
|
13998
|
-
|
|
13999
|
-
|
|
14067
|
+
var cache = null;
|
|
14068
|
+
function listAgents() {
|
|
14069
|
+
cache ??= api("/api/v2/me/agents?client=cli").then((r) => r.agentes);
|
|
14070
|
+
return cache;
|
|
14071
|
+
}
|
|
14072
|
+
async function resolveAgent(ref, workspace) {
|
|
14073
|
+
if (!ref || looksLikeId(ref)) return ref;
|
|
14074
|
+
return pickAgent(await listAgents(), ref, workspace);
|
|
14075
|
+
}
|
|
14076
|
+
function agentArgIndex(pos) {
|
|
14077
|
+
const [cmd, sub] = pos;
|
|
14078
|
+
switch (cmd) {
|
|
14079
|
+
case "agents":
|
|
14080
|
+
if (sub === "docs" || sub === "documents" || sub === "teams") return 3;
|
|
14081
|
+
return sub && !["ls", "list", "create", "new"].includes(sub) ? 2 : null;
|
|
14082
|
+
case "files":
|
|
14083
|
+
case "skills":
|
|
14084
|
+
case "mcp":
|
|
14085
|
+
case "dbs":
|
|
14086
|
+
case "db":
|
|
14087
|
+
return sub === "photos" ? 3 : 2;
|
|
14088
|
+
case "turns":
|
|
14089
|
+
return pos[1] === "stats" ? null : 2;
|
|
14090
|
+
case "board":
|
|
14091
|
+
case "conversations":
|
|
14092
|
+
case "schedule":
|
|
14093
|
+
return 2;
|
|
14094
|
+
case "try":
|
|
14095
|
+
case "chat":
|
|
14096
|
+
return 1;
|
|
14097
|
+
case "channels":
|
|
14098
|
+
return pos[2] === "groups" ? 4 : 3;
|
|
14099
|
+
case "boards":
|
|
14100
|
+
return sub === "assign" ? 2 : null;
|
|
14101
|
+
case "access":
|
|
14102
|
+
return sub === "why" && pos[3] ? 3 : null;
|
|
14103
|
+
case "demos":
|
|
14104
|
+
case "demo":
|
|
14105
|
+
return sub === "history" ? 2 : null;
|
|
14106
|
+
default:
|
|
14107
|
+
return null;
|
|
14000
14108
|
}
|
|
14001
|
-
|
|
14002
|
-
|
|
14003
|
-
|
|
14004
|
-
|
|
14005
|
-
|
|
14006
|
-
|
|
14007
|
-
|
|
14008
|
-
|
|
14009
|
-
|
|
14010
|
-
|
|
14011
|
-
|
|
14012
|
-
|
|
14013
|
-
|
|
14014
|
-
|
|
14015
|
-
|
|
14016
|
-
${bagsText(r)}`);
|
|
14017
|
-
}
|
|
14018
|
-
case "set": {
|
|
14019
|
-
if (!name) throw usage(t("Missing the bag's name.", "Falta el nombre de la bolsa."), ex);
|
|
14020
|
-
const body = { ...v.tokens ? { tokens: parseTokens(v.tokens) } : {}, ...recurring !== void 0 ? { recurring } : {}, ...hardCap !== void 0 ? { hardCap } : {}, ...v.note !== void 0 ? { note: v.note } : {}, ...v.name ? { name: v.name } : {} };
|
|
14021
|
-
if (!Object.keys(body).length) throw usage(t("Nothing to change.", "Nada que cambiar."), "--tokens 30M | --recurring on|off | --hard-cap on|off | --note TEXT | --name NEW");
|
|
14022
|
-
const r = await api(wsPath(slug, `/bags/${enc11(name)}`), { method: "PATCH", body });
|
|
14023
|
-
return out(r, () => `${lavender("\u2713")} ${t(`Bag \xAB${r.updated}\xBB updated.`, `Bolsa \xAB${r.updated}\xBB actualizada.`)}
|
|
14024
|
-
${bagsText(r)}`);
|
|
14025
|
-
}
|
|
14026
|
-
case "rm":
|
|
14027
|
-
case "delete": {
|
|
14028
|
-
if (!name) throw usage(t("Missing the bag's name.", "Falta el nombre de la bolsa."), ex);
|
|
14029
|
-
requireYesIfHeadless(v.yes, `ghosty bags rm ${slug} "${name}"`);
|
|
14030
|
-
await confirm(t(`Delete bag \xAB${name}\xBB from ${slug}? (only if no agent uses it)`, `\xBFBorrar la bolsa \xAB${name}\xBB de ${slug}? (s\xF3lo si ning\xFAn agente la usa)`), { yes: v.yes, retry: `ghosty bags rm ${slug} "${name}"` });
|
|
14031
|
-
const r = await api(wsPath(slug, `/bags/${enc11(name)}`), { method: "DELETE" });
|
|
14032
|
-
return out(r, () => `${lavender("\u2713")} ${t(`Bag \xAB${r.deleted}\xBB deleted.`, `Bolsa \xAB${r.deleted}\xBB borrada.`)}
|
|
14033
|
-
${bagsText(r)}`);
|
|
14109
|
+
}
|
|
14110
|
+
|
|
14111
|
+
// src/completion.ts
|
|
14112
|
+
import { mkdir as mkdir6, readFile as readFile10, writeFile as writeFile8 } from "node:fs/promises";
|
|
14113
|
+
import { homedir as homedir4 } from "node:os";
|
|
14114
|
+
import { join as join8 } from "node:path";
|
|
14115
|
+
var GLOBAL_FLAGS = ["--json", "--token", "--profile", "--yes", "--help", "--version", "--lang", "--dry-run"];
|
|
14116
|
+
var AGENT_FLAGS = /* @__PURE__ */ new Set(["--like", "--agent", "--prompt-base"]);
|
|
14117
|
+
var WORKSPACE_FLAGS = /* @__PURE__ */ new Set(["--workspace"]);
|
|
14118
|
+
function subcommandsOf(cmd) {
|
|
14119
|
+
const subs = /* @__PURE__ */ new Set();
|
|
14120
|
+
for (const u of HELPS[cmd]?.usage ?? []) {
|
|
14121
|
+
const m = new RegExp(`^ghosty ${cmd} ([a-z][a-z|-]*)`).exec(u);
|
|
14122
|
+
if (m) {
|
|
14123
|
+
for (const s2 of m[1].split("|")) if (!s2.includes("-") || /^[a-z]+-[a-z]+$/.test(s2)) subs.add(s2);
|
|
14034
14124
|
}
|
|
14035
14125
|
}
|
|
14126
|
+
return [...subs];
|
|
14036
14127
|
}
|
|
14037
|
-
|
|
14038
|
-
const
|
|
14039
|
-
|
|
14040
|
-
|
|
14041
|
-
|
|
14042
|
-
|
|
14043
|
-
|
|
14128
|
+
function flagsOf(cmd) {
|
|
14129
|
+
const own = /* @__PURE__ */ new Set();
|
|
14130
|
+
for (const [f] of HELPS[cmd]?.flags ?? []) for (const m of f.matchAll(/--[a-z][a-z-]*/g)) own.add(m[0]);
|
|
14131
|
+
for (const u of HELPS[cmd]?.usage ?? []) for (const m of u.matchAll(/--[a-z][a-z-]*/g)) own.add(m[0]);
|
|
14132
|
+
return [...own, ...GLOBAL_FLAGS];
|
|
14133
|
+
}
|
|
14134
|
+
function completionFor(words, current2, commands) {
|
|
14135
|
+
const prev = words[words.length - 1];
|
|
14136
|
+
if (prev && AGENT_FLAGS.has(prev)) return { kind: "agents" };
|
|
14137
|
+
if (prev && WORKSPACE_FLAGS.has(prev)) return { kind: "workspaces" };
|
|
14138
|
+
if (!words.length) return { kind: "words", words: commands };
|
|
14139
|
+
const [cmd, sub] = words;
|
|
14140
|
+
if (current2.startsWith("-")) return { kind: "words", words: flagsOf(cmd) };
|
|
14141
|
+
const pos = words.filter((w) => !w.startsWith("-"));
|
|
14142
|
+
if (cmd === "use" && pos.length === 1) return { kind: "workspaces" };
|
|
14143
|
+
if (cmd === "boards" && pos.length === 2 && sub !== "assign") return { kind: "workspaces" };
|
|
14144
|
+
if (cmd === "help" && pos.length === 1) return { kind: "words", words: commands };
|
|
14145
|
+
if (pos.length === 1 && cmd !== "try" && cmd !== "chat") {
|
|
14146
|
+
const subs = subcommandsOf(cmd);
|
|
14147
|
+
if (subs.length) return { kind: "words", words: subs };
|
|
14044
14148
|
}
|
|
14045
|
-
if (
|
|
14046
|
-
|
|
14047
|
-
|
|
14048
|
-
|
|
14049
|
-
|
|
14050
|
-
|
|
14051
|
-
|
|
14052
|
-
|
|
14149
|
+
if (agentArgIndex([...pos, current2]) === pos.length) return { kind: "agents" };
|
|
14150
|
+
return { kind: "words", words: [] };
|
|
14151
|
+
}
|
|
14152
|
+
var cacheFile = () => join8(process.env.XDG_CACHE_HOME || join8(homedir4(), ".cache"), "ghosty", `complete${process.env.GHOSTY_PROFILE ? `.${process.env.GHOSTY_PROFILE}` : ""}.json`);
|
|
14153
|
+
async function names() {
|
|
14154
|
+
try {
|
|
14155
|
+
const c = JSON.parse(await readFile10(cacheFile(), "utf8"));
|
|
14156
|
+
if (Date.now() - c.at < 5 * 6e4) return c;
|
|
14157
|
+
} catch {
|
|
14053
14158
|
}
|
|
14054
|
-
|
|
14055
|
-
|
|
14056
|
-
|
|
14057
|
-
|
|
14058
|
-
|
|
14059
|
-
|
|
14060
|
-
|
|
14061
|
-
|
|
14159
|
+
const list = await listAgents();
|
|
14160
|
+
const agents = [...new Set(list.map((a) => a.nombre))];
|
|
14161
|
+
const workspaces = [...new Set(list.map((a) => a.espacio?.tipo === "workspace" ? a.espacio.nombre : void 0).filter((x) => !!x))];
|
|
14162
|
+
await mkdir6(join8(cacheFile(), ".."), { recursive: true }).catch(() => {
|
|
14163
|
+
});
|
|
14164
|
+
await writeFile8(cacheFile(), JSON.stringify({ at: Date.now(), agents, workspaces })).catch(() => {
|
|
14165
|
+
});
|
|
14166
|
+
return { agents, workspaces };
|
|
14167
|
+
}
|
|
14168
|
+
async function completeCmd(args, commands) {
|
|
14169
|
+
const current2 = args.length ? args[args.length - 1] : "";
|
|
14170
|
+
const words = args.slice(0, -1);
|
|
14171
|
+
const want = completionFor(words, current2, commands);
|
|
14172
|
+
let out2 = [];
|
|
14173
|
+
try {
|
|
14174
|
+
if (want.kind === "words") out2 = want.words;
|
|
14175
|
+
else out2 = (await names())[want.kind];
|
|
14176
|
+
} catch {
|
|
14177
|
+
out2 = [];
|
|
14062
14178
|
}
|
|
14063
|
-
|
|
14064
|
-
|
|
14065
|
-
|
|
14066
|
-
|
|
14179
|
+
process.stdout.write(out2.filter((w) => w.toLowerCase().startsWith(current2.toLowerCase())).join("\n") + "\n");
|
|
14180
|
+
}
|
|
14181
|
+
function completionScript(shell) {
|
|
14182
|
+
if (shell === "bash") {
|
|
14183
|
+
return `# ghosty \u2014 bash completion: eval "$(ghosty completion bash)" en ~/.bashrc
|
|
14184
|
+
_ghosty() {
|
|
14185
|
+
# Las palabras ANTES de cambiar IFS: el bash 3.2 de macOS junta \${arr[@]:1:n} con un IFS propio.
|
|
14186
|
+
local words=("\${COMP_WORDS[@]:1:COMP_CWORD-1}") cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
14187
|
+
local IFS=$'\\n'
|
|
14188
|
+
COMPREPLY=( $(ghosty __complete -- "\${words[@]}" "$cur" 2>/dev/null) )
|
|
14189
|
+
}
|
|
14190
|
+
complete -o default -F _ghosty ghosty
|
|
14191
|
+
`;
|
|
14067
14192
|
}
|
|
14068
|
-
if (
|
|
14069
|
-
|
|
14070
|
-
|
|
14071
|
-
|
|
14072
|
-
|
|
14073
|
-
|
|
14074
|
-
|
|
14075
|
-
|
|
14076
|
-
|
|
14077
|
-
|
|
14078
|
-
const plans = await Promise.all(steps.map(async (st) => ({ ...st, plan: await api(st.path, { method: "POST", body: { ...st.body, dryRun: true } }) })));
|
|
14079
|
-
const lines = plans.map((p) => `${p.plan.workspace}: ${p.label} ${show2(p.plan.from)} \u2192 ${show2(p.plan.to)}`);
|
|
14080
|
-
const pending = plans.filter((p) => p.plan.changed);
|
|
14081
|
-
if (!pending.length) return out(plans.map((p) => p.plan), () => dim(t(`Nothing to do: ${slug} already has that.`, `Nada que hacer: ${slug} ya lo tiene.`)));
|
|
14082
|
-
if (v["dry-run"]) return out(plans.map((p) => p.plan), () => `${lines.join("\n")}
|
|
14083
|
-
${dim(t("Dry run: nothing changed.", "Simulaci\xF3n: no cambi\xF3 nada."))}`);
|
|
14084
|
-
const retry = `ghosty spaces set ${slug}${v.combo ? ` --combo ${v.combo}` : ""}${cap !== void 0 ? ` --model-cap ${cap}` : ""}${house !== void 0 ? ` --house-claude ${house ? "on" : "off"}` : ""}`;
|
|
14085
|
-
requireYesIfHeadless(v.yes, retry);
|
|
14086
|
-
await confirm(`${lines.join("\n")}
|
|
14087
|
-
${t("Change it?", "\xBFCambiarlo?")}`, { yes: v.yes, retry });
|
|
14088
|
-
const done = [];
|
|
14089
|
-
for (const p of pending) done.push(await api(p.path, { method: "POST", body: p.body }));
|
|
14090
|
-
return out(done, () => done.map((r, i) => `${lavender("\u2713")} ${r.workspace}: ${pending[i].label} ${show2(r.to)}`).join("\n"));
|
|
14193
|
+
if (shell === "zsh") {
|
|
14194
|
+
return `#compdef ghosty
|
|
14195
|
+
# ghosty \u2014 zsh completion: source <(ghosty completion zsh) en ~/.zshrc (despu\xE9s de compinit)
|
|
14196
|
+
_ghosty() {
|
|
14197
|
+
local -a opts
|
|
14198
|
+
opts=("\${(@f)$(ghosty __complete -- "\${(@)words[2,CURRENT-1]}" "\${words[CURRENT]}" 2>/dev/null)}")
|
|
14199
|
+
compadd -a opts
|
|
14200
|
+
}
|
|
14201
|
+
compdef _ghosty ghosty
|
|
14202
|
+
`;
|
|
14091
14203
|
}
|
|
14092
|
-
if (
|
|
14093
|
-
|
|
14094
|
-
|
|
14095
|
-
|
|
14096
|
-
const plan = await api(path, { method: "POST", body: { until: v.until, dryRun: true } });
|
|
14097
|
-
const line2 = t(`${plan.workspace} (${plan.plan}): paid until ${plan.from ?? "\u2014"} \u2192 ${plan.to}`, `${plan.workspace} (${plan.plan}): pagado hasta ${plan.from ?? "\u2014"} \u2192 ${plan.to}`);
|
|
14098
|
-
if (v["dry-run"]) return out(plan, () => `${line2}
|
|
14099
|
-
${dim(t("Dry run: nothing changed.", "Simulaci\xF3n: no cambi\xF3 nada."))}`);
|
|
14100
|
-
requireYesIfHeadless(v.yes, `ghosty spaces renew ${slug} --until ${v.until}`);
|
|
14101
|
-
await confirm(`${line2}
|
|
14102
|
-
${t("Renew?", "\xBFRenovar?")}`, { yes: v.yes, retry: `ghosty spaces renew ${slug} --until ${v.until}` });
|
|
14103
|
-
const r = await api(path, { method: "POST", body: { until: v.until, ...v.note ? { note: v.note } : {} } });
|
|
14104
|
-
return out(r, () => `${lavender("\u2713")} ${line2} ${dim(t("(logged in the workspace's audit)", "(queda en la bit\xE1cora del espacio)"))}`);
|
|
14204
|
+
if (shell === "fish") {
|
|
14205
|
+
return `# ghosty \u2014 fish completion: ghosty completion fish > ~/.config/fish/completions/ghosty.fish
|
|
14206
|
+
complete -c ghosty -f -a "(ghosty __complete -- (commandline -opc)[2..-1] (commandline -ct) 2>/dev/null)"
|
|
14207
|
+
`;
|
|
14105
14208
|
}
|
|
14106
|
-
|
|
14107
|
-
|
|
14108
|
-
|
|
14109
|
-
|
|
14110
|
-
|
|
14111
|
-
|
|
14112
|
-
|
|
14113
|
-
|
|
14114
|
-
|
|
14115
|
-
|
|
14116
|
-
|
|
14117
|
-
|
|
14118
|
-
|
|
14119
|
-
return out(r, () => `${lavender("\u2713")} ${t(`Renamed: ${r.from} \u2192 ${r.to}. Undo: ghosty spaces rename ${r.to} ${r.from}`, `Renombrado: ${r.from} \u2192 ${r.to}. Deshacer: ghosty spaces rename ${r.to} ${r.from}`)}`);
|
|
14209
|
+
return null;
|
|
14210
|
+
}
|
|
14211
|
+
|
|
14212
|
+
// src/aliases.ts
|
|
14213
|
+
function normalizeArgs(pos, v) {
|
|
14214
|
+
const notes = [];
|
|
14215
|
+
const [cmd, sub] = pos;
|
|
14216
|
+
if (cmd === "cards") pos[0] = "board";
|
|
14217
|
+
else if (cmd === "board") notes.push(t("`ghosty board` is now `ghosty cards` (same subcommands).", "`ghosty board` ahora es `ghosty cards` (mismos subcomandos)."));
|
|
14218
|
+
if (cmd === "skills") {
|
|
14219
|
+
if (sub === "enable") pos[1] = "on";
|
|
14220
|
+
else if (sub === "disable") pos[1] = "off";
|
|
14221
|
+
else if (sub === "on" || sub === "off") notes.push(t(`\`skills ${sub}\` is now \`skills ${sub === "on" ? "enable" : "disable"}\`.`, `\`skills ${sub}\` ahora es \`skills ${sub === "on" ? "enable" : "disable"}\`.`));
|
|
14120
14222
|
}
|
|
14121
|
-
if (
|
|
14122
|
-
|
|
14123
|
-
|
|
14124
|
-
|
|
14125
|
-
|
|
14126
|
-
|
|
14127
|
-
if (
|
|
14128
|
-
if (v["dry-run"]) return out(plan, () => `${line2}
|
|
14129
|
-
${dim(t("Dry run: nothing changed.", "Simulaci\xF3n: no cambi\xF3 nada."))}`);
|
|
14130
|
-
const retry = `ghosty spaces ${sub} ${slug}`;
|
|
14131
|
-
requireYesIfHeadless(v.yes, retry);
|
|
14132
|
-
await confirm(`${line2}
|
|
14133
|
-
${archive ? t("Archive it?", "\xBFArchivarlo?") : t("Restore it?", "\xBFRestaurarlo?")}`, { yes: v.yes, retry, ...archive ? { expect: plan.slug } : {} });
|
|
14134
|
-
const r = await api(path, { method: "POST", body: { archive } });
|
|
14135
|
-
return out(r, () => archive ? `${lavender("\u2713")} ${t(`Archived: ${r.slug}. Undo: ghosty spaces restore ${r.slug}`, `Archivado: ${r.slug}. Deshacer: ghosty spaces restore ${r.slug}`)}` : `${lavender("\u2713")} ${t(`Restored: ${r.slug}.`, `Restaurado: ${r.slug}.`)}`);
|
|
14223
|
+
if (cmd === "agents" && sub === "demo") {
|
|
14224
|
+
if (pos[2] === "enable" || pos[2] === "disable") {
|
|
14225
|
+
v[pos[2] === "enable" ? "on" : "off"] = true;
|
|
14226
|
+
pos.splice(2, 1);
|
|
14227
|
+
} else if (v.on || v.off) notes.push(t(`\`agents demo <agent> --${v.on ? "on" : "off"}\` is now \`agents demo ${v.on ? "enable" : "disable"} <agent>\`.`, `\`agents demo <agente> --${v.on ? "on" : "off"}\` ahora es \`agents demo ${v.on ? "enable" : "disable"} <agente>\`.`));
|
|
14228
|
+
if (v.expires !== void 0) v.vence = v.expires;
|
|
14229
|
+
else if (v.vence !== void 0) notes.push(t("`--vence` is now `--expires`.", "`--vence` ahora es `--expires`."));
|
|
14136
14230
|
}
|
|
14137
|
-
if (sub === "
|
|
14138
|
-
|
|
14139
|
-
|
|
14140
|
-
if (!toEmail) throw usage(t("Missing --to EMAIL.", "Falta --to CORREO."), `ghosty spaces transfer ${slug} --to new@owner.com --keep-as admin --copy-keys --dry-run`);
|
|
14141
|
-
const body = { to: toEmail, ...v["keep-as"] ? { keepAs: v["keep-as"] } : {}, ...v["copy-keys"] ? { copyKeys: true } : {} };
|
|
14142
|
-
const path = wsPath(slug, "/transfer");
|
|
14143
|
-
const plan = await api(path, { method: "POST", body: { ...body, dryRun: true } });
|
|
14144
|
-
const text = [
|
|
14145
|
-
`${plan.workspace}: ${plan.from ?? "\u2014"} \u2192 ${bold(plan.to)} ${dim(t(`(previous owner stays as ${plan.keepAs})`, `(el anterior queda como ${plan.keepAs})`))}`,
|
|
14146
|
-
`${t("agents", "agentes")}: ${plan.agents.join(", ") || "\u2014"}`,
|
|
14147
|
-
`${t("keys", "llaves")}: ${plan.keys.copy.length ? t(`copies ${plan.keys.copy.join(", ")}`, `copia ${plan.keys.copy.join(", ")}`) : t("copies none", "no copia")}${plan.keys.alreadyHas.length ? dim(t(` \xB7 already has ${plan.keys.alreadyHas.join(", ")}`, ` \xB7 ya tiene ${plan.keys.alreadyHas.join(", ")}`)) : ""}`,
|
|
14148
|
-
...plan.warnings.map((w) => red(` \xB7 ${serverText(w)}`))
|
|
14149
|
-
].join("\n");
|
|
14150
|
-
if (v["dry-run"]) return out(plan, () => `${text}
|
|
14151
|
-
${dim(t("Dry run: nothing changed.", "Simulaci\xF3n: no cambi\xF3 nada."))}`);
|
|
14152
|
-
const retry = `ghosty spaces transfer ${slug} --to ${toEmail}${v["keep-as"] ? ` --keep-as ${v["keep-as"]}` : ""}${v["copy-keys"] ? " --copy-keys" : ""}`;
|
|
14153
|
-
requireYesIfHeadless(v.yes, retry);
|
|
14154
|
-
await confirm(`${text}
|
|
14155
|
-
${t("Transfer it? Its agents' boxes are recycled (a turn in flight finishes first).", "\xBFTraspasarlo? Se reciclan las cajas de sus agentes (un turno en vuelo termina antes).")}`, { yes: v.yes, expect: plan.workspace, retry });
|
|
14156
|
-
const r = await api(path, { method: "POST", body });
|
|
14157
|
-
return out(r, () => `${lavender("\u2713")} ${t(`${r.workspace} now belongs to ${r.to}; ${r.from ?? "\u2014"} stays as ${r.keepAs}. ${r.recycled} agent(s) recycled.`, `${r.workspace} ya es de ${r.to}; ${r.from ?? "\u2014"} queda como ${r.keepAs}. ${r.recycled} agente(s) reciclado(s).`)}${r.warnings.length ? `
|
|
14158
|
-
${r.warnings.map((w) => red(` \xB7 ${serverText(w)}`)).join("\n")}` : ""}`);
|
|
14231
|
+
if (cmd === "agents" && (sub === "embed" || sub === "widget") && (pos[2] === "enable" || pos[2] === "disable")) {
|
|
14232
|
+
v[pos[2] === "enable" ? "on" : "off"] = true;
|
|
14233
|
+
pos.splice(2, 1);
|
|
14159
14234
|
}
|
|
14160
|
-
|
|
14235
|
+
if (cmd === "channels" && pos[2] === "groups") {
|
|
14236
|
+
if (pos[3] === "enable" || pos[3] === "disable") {
|
|
14237
|
+
v[pos[3] === "enable" ? "on" : "off"] = true;
|
|
14238
|
+
pos[3] = "set";
|
|
14239
|
+
} else if (pos[3] === "set" && (v.on || v.off)) notes.push(t(`\`groups set \u2026 --${v.on ? "on" : "off"}\` is now \`groups ${v.on ? "enable" : "disable"} <agent> <group>\` (set keeps --role).`, `\`groups set \u2026 --${v.on ? "on" : "off"}\` ahora es \`groups ${v.on ? "enable" : "disable"} <agente> <grupo>\` (set se queda para --role).`));
|
|
14240
|
+
}
|
|
14241
|
+
return notes;
|
|
14161
14242
|
}
|
|
14162
|
-
|
|
14163
|
-
|
|
14164
|
-
|
|
14165
|
-
|
|
14166
|
-
|
|
14167
|
-
|
|
14168
|
-
|
|
14169
|
-
|
|
14170
|
-
|
|
14243
|
+
|
|
14244
|
+
// src/commands/spec.ts
|
|
14245
|
+
var import_yaml = __toESM(require_dist(), 1);
|
|
14246
|
+
import { mkdir as mkdir7, readdir as readdir4, readFile as readFile11, stat as stat2, writeFile as writeFile9 } from "node:fs/promises";
|
|
14247
|
+
import { join as join9, resolve as resolve2 } from "node:path";
|
|
14248
|
+
var enc11 = encodeURIComponent;
|
|
14249
|
+
async function agentsExport(id, v) {
|
|
14250
|
+
if (!id) throw usage(t("Missing agent.", "Falta el agente."), t("Example", "Ejemplo") + ": ghosty agents export pia-0 > pia.yaml \xB7 ghosty agents export pia-0 --out ./pia");
|
|
14251
|
+
const yaml = await (await request(`/api/v2/agents/${enc11(id)}/export`)).text();
|
|
14252
|
+
if (!v.out) {
|
|
14253
|
+
if (globals.json) return out((0, import_yaml.parse)(yaml));
|
|
14254
|
+
return void process.stdout.write(yaml);
|
|
14171
14255
|
}
|
|
14172
|
-
const
|
|
14173
|
-
|
|
14174
|
-
|
|
14175
|
-
const
|
|
14176
|
-
|
|
14177
|
-
|
|
14178
|
-
|
|
14179
|
-
|
|
14180
|
-
|
|
14181
|
-
|
|
14182
|
-
|
|
14183
|
-
|
|
14184
|
-
|
|
14185
|
-
|
|
14256
|
+
const dir = resolve2(v.out);
|
|
14257
|
+
await mkdir7(dir, { recursive: true });
|
|
14258
|
+
await writeFile9(join9(dir, "agent.yaml"), yaml);
|
|
14259
|
+
const own = (0, import_yaml.parse)(yaml)["x-ghosty"]?.skills?.own ?? [];
|
|
14260
|
+
for (const slug of own) {
|
|
14261
|
+
const sk = await api(`/api/v2/agents/${enc11(id)}/skills/${enc11(slug)}`);
|
|
14262
|
+
await writeSkill(join9(dir, "skills", slug), sk);
|
|
14263
|
+
}
|
|
14264
|
+
out({ saved: dir, skills: own }, () => `${lavender("\u2713")} ${dir}/agent.yaml${own.length ? ` + skills/ (${own.join(", ")})` : ""}
|
|
14265
|
+
${dim(t(`Edit it, then: ghosty apply ${v.out} --dry-run`, `Ed\xEDtalo y luego: ghosty apply ${v.out} --dry-run`))}`);
|
|
14266
|
+
}
|
|
14267
|
+
function fillSecrets(file) {
|
|
14268
|
+
const missing = [];
|
|
14269
|
+
const fill = (o) => {
|
|
14270
|
+
for (const [k, val] of Object.entries(o ?? {})) {
|
|
14271
|
+
const m = typeof val === "string" ? /^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$/.exec(val) : null;
|
|
14272
|
+
if (!m) continue;
|
|
14273
|
+
if (process.env[m[1]] !== void 0) o[k] = process.env[m[1]];
|
|
14274
|
+
else missing.push(m[1]);
|
|
14186
14275
|
}
|
|
14187
|
-
|
|
14188
|
-
|
|
14189
|
-
|
|
14190
|
-
const
|
|
14191
|
-
|
|
14192
|
-
${table(rows, cols)}
|
|
14193
|
-
${dim(t(`${fmtTokens(total)} billable tokens \xB7 failed = error or stopped \xB7 no balance: ghosty turns ls --workspace ${r.workspace} --quota-hits`, `${fmtTokens(total)} tokens facturables \xB7 failed = error o detenido \xB7 sin saldo: ghosty turns ls --workspace ${r.workspace} --quota-hits`))}`);
|
|
14276
|
+
};
|
|
14277
|
+
const x = file["x-ghosty"];
|
|
14278
|
+
fill(x?.env);
|
|
14279
|
+
for (const s2 of x?.mcp ?? []) fill(s2.env), fill(s2.headers);
|
|
14280
|
+
return missing;
|
|
14194
14281
|
}
|
|
14195
|
-
|
|
14196
|
-
|
|
14197
|
-
const
|
|
14198
|
-
|
|
14199
|
-
|
|
14200
|
-
|
|
14201
|
-
|
|
14202
|
-
|
|
14203
|
-
g.outputTokens += r.outputTokens;
|
|
14204
|
-
g.cacheRead += r.cacheRead;
|
|
14205
|
-
g.cacheCreation += r.cacheCreation;
|
|
14206
|
-
g.billable += r.billable;
|
|
14207
|
-
g.usd += r.usd;
|
|
14208
|
-
groups.set(k, g);
|
|
14282
|
+
async function readSkills(dir) {
|
|
14283
|
+
const root = join9(dir, "skills");
|
|
14284
|
+
const out2 = {};
|
|
14285
|
+
const slugs = await readdir4(root, { withFileTypes: true }).catch(() => []);
|
|
14286
|
+
for (const e of slugs) {
|
|
14287
|
+
if (!e.isDirectory() || e.name.startsWith(".")) continue;
|
|
14288
|
+
const { markdown, assets } = await readSkillDir(join9(root, e.name));
|
|
14289
|
+
out2[e.name] = [{ path: "SKILL.md", contentBase64: Buffer.from(markdown).toString("base64") }, ...assets.map((a) => ({ path: a.name, contentBase64: a.contentBase64 }))];
|
|
14209
14290
|
}
|
|
14210
|
-
return
|
|
14291
|
+
return out2;
|
|
14211
14292
|
}
|
|
14212
|
-
|
|
14213
|
-
|
|
14214
|
-
|
|
14215
|
-
|
|
14216
|
-
const
|
|
14217
|
-
const
|
|
14218
|
-
|
|
14219
|
-
const
|
|
14220
|
-
|
|
14221
|
-
const
|
|
14222
|
-
|
|
14223
|
-
|
|
14224
|
-
|
|
14293
|
+
var line = (c) => c.op === "!" ? dim(`! ${c.what}`) : `${c.op === "+" ? lavender("+") : c.op === "-" ? red("-") : "~"} ${c.what}`;
|
|
14294
|
+
async function applyCmd(target, v) {
|
|
14295
|
+
if (!target) throw usage(t("Missing file or directory.", "Falta el archivo o el directorio."), t("Example: ghosty apply pia.yaml --dry-run \xB7 ghosty apply ./pia (from agents export --out)", "Ejemplo: ghosty apply pia.yaml --dry-run \xB7 ghosty apply ./pia (de agents export --out)"));
|
|
14296
|
+
const isDir = (await stat2(target).catch(() => null))?.isDirectory() ?? false;
|
|
14297
|
+
const text = await readFile11(isDir ? join9(target, "agent.yaml") : target, "utf8");
|
|
14298
|
+
const file = (0, import_yaml.parse)(text);
|
|
14299
|
+
if (!file || typeof file !== "object") throw usage(t(`${target} is not a YAML/JSON agent file.`, `${target} no es un archivo de agente YAML/JSON.`));
|
|
14300
|
+
const missing = fillSecrets(file);
|
|
14301
|
+
if (missing.length && !globals.json) info(dim(t(`Secrets not in your environment keep their current value: ${missing.join(", ")}`, `Los secretos que no est\xE1n en tu entorno conservan su valor actual: ${missing.join(", ")}`)));
|
|
14302
|
+
const files = isDir ? await readSkills(target) : void 0;
|
|
14303
|
+
let id = v.agent ?? file["x-ghosty"]?.id;
|
|
14304
|
+
if (v.create) {
|
|
14305
|
+
const x = file["x-ghosty"] ?? {};
|
|
14306
|
+
const name = v.name ?? file.title;
|
|
14307
|
+
if (!name) throw usage(t("The file has no title: pass --name.", "El archivo no tiene t\xEDtulo: pasa --name."));
|
|
14308
|
+
if (v["dry-run"]) return out({ create: true, name, engine: x.engine, workspace: x.workspace ?? null }, () => `${lavender("+")} ${t("agent", "agente")} ${name} (${x.engine ?? t("default engine", "motor por default")}${x.workspace ? t(` in ${x.workspace}`, ` en ${x.workspace}`) : ""})
|
|
14309
|
+
${dim(t("Then every setting of the file is applied. Dry run: nothing created.", "Despu\xE9s se aplica cada ajuste del archivo. Simulaci\xF3n: no se cre\xF3 nada."))}`);
|
|
14310
|
+
requireYesIfHeadless(v.yes, `ghosty apply ${target} --create`);
|
|
14311
|
+
const created = await api("/api/v2/me/agents", { method: "POST", body: { name, ...x.engine ? { engine: x.engine } : {}, ...x.model ? { model: x.model } : {}, ...x.workspace ? { workspace: x.workspace } : {}, ...x.channels ? { channels: x.channels } : {} } });
|
|
14312
|
+
id = created.id;
|
|
14313
|
+
info(dim(t(`Created ${name} (${id}); applying the rest\u2026`, `${name} creado (${id}); aplicando lo dem\xE1s\u2026`)));
|
|
14314
|
+
} else {
|
|
14315
|
+
id = await resolveAgent(id);
|
|
14316
|
+
if (!id) throw usage(t("The file has no agent id.", "El archivo no trae id de agente."), t("Point it at one with --agent <name|id>, or make a new one with --create.", "Ap\xFAntalo a uno con --agent <nombre|id>, o crea uno nuevo con --create."));
|
|
14317
|
+
}
|
|
14318
|
+
const spec = JSON.stringify(v.create ? { ...file, title: void 0 } : file);
|
|
14319
|
+
const body = { spec, ...files ? { files } : {}, ...v.prune ? { prune: true } : {}, ...v["no-notify"] ? { notify: false } : {} };
|
|
14320
|
+
const path = `/api/v2/agents/${enc11(id)}/apply`;
|
|
14321
|
+
const plan = await api(path, { method: "POST", body: { ...body, dryRun: true } });
|
|
14322
|
+
const actionable = plan.plan.filter((c) => c.op !== "!");
|
|
14323
|
+
const text2 = plan.plan.map(line).join("\n") || dim(t("No changes: the agent already matches the file.", "Sin cambios: el agente ya coincide con el archivo."));
|
|
14324
|
+
if (v["dry-run"] || !actionable.length) return out(plan, () => `${bold(id)}
|
|
14325
|
+
${text2}${actionable.length ? `
|
|
14326
|
+
${dim(t("Dry run: nothing changed.", "Simulaci\xF3n: no cambi\xF3 nada."))}` : ""}`);
|
|
14327
|
+
const retry = `ghosty apply ${target}${v.agent ? ` --agent ${v.agent}` : ""}${v.prune ? " --prune" : ""}`;
|
|
14328
|
+
if (!v.create) requireYesIfHeadless(v.yes, retry);
|
|
14329
|
+
if (!v.create) await confirm(`${text2}
|
|
14330
|
+
${t(`Apply ${actionable.length} change(s) to ${id}?`, `\xBFAplicar ${actionable.length} cambio(s) a ${id}?`)}`, { yes: v.yes, retry });
|
|
14331
|
+
const r = await api(path, { method: "POST", body });
|
|
14332
|
+
out(r, () => `${lavender("\u2713")} ${t(`${r.applied?.length ?? 0} change(s) applied to ${id}.`, `${r.applied?.length ?? 0} cambio(s) aplicados a ${id}.`)}${r.failed ? `
|
|
14333
|
+
${red(t(`Stopped at \xAB${r.failed.what}\xBB: ${serverText(r.failed.error)}`, `Se detuvo en \xAB${r.failed.what}\xBB: ${r.failed.error}`))}` : ""}`);
|
|
14225
14334
|
}
|
|
14226
|
-
|
|
14227
|
-
|
|
14228
|
-
|
|
14229
|
-
|
|
14230
|
-
|
|
14231
|
-
|
|
14232
|
-
|
|
14233
|
-
|
|
14234
|
-
|
|
14235
|
-
|
|
14236
|
-
|
|
14237
|
-
|
|
14238
|
-
}))
|
|
14239
|
-
|
|
14240
|
-
|
|
14241
|
-
|
|
14242
|
-
|
|
14243
|
-
|
|
14244
|
-
|
|
14245
|
-
);
|
|
14246
|
-
out(r, () =>
|
|
14247
|
-
|
|
14248
|
-
|
|
14335
|
+
|
|
14336
|
+
// src/commands/plan.ts
|
|
14337
|
+
async function planCmd(sub, slug, v, context) {
|
|
14338
|
+
if (sub !== "apply") throw usage(t(`Unknown plan subcommand: ${sub ?? "(none)"}.`, `Subcomando desconocido de plan: ${sub ?? "(ninguno)"}.`), "ghosty plan apply <workspace> [--dry-run]");
|
|
14339
|
+
slug ??= context;
|
|
14340
|
+
if (!slug) throw usage(t("Missing workspace.", "Falta el espacio."), "ghosty plan apply <workspace> [--dry-run] (or ghosty use <workspace>)");
|
|
14341
|
+
const path = `/api/v2/workspaces/${encodeURIComponent(slug)}/plan/apply`;
|
|
14342
|
+
const plan = await api(path, { method: "POST", body: { dryRun: true } });
|
|
14343
|
+
const money2 = (n) => `$${n.toLocaleString("es-MX")} MXN`;
|
|
14344
|
+
const text = [
|
|
14345
|
+
`${bold(plan.workspace)} ${dim(plan.scheduledFor ? t(`scheduled for ${plan.scheduledFor.slice(0, 10)}`, `programado para el ${plan.scheduledFor.slice(0, 10)}`) : "")}`,
|
|
14346
|
+
...plan.changes.map((c) => ` ~ ${c.label}: ${String(c.from)} \u2192 ${String(c.to)}`),
|
|
14347
|
+
` ${t("monthly", "al mes")}: ${money2(plan.monthlyTotal.from)} \u2192 ${money2(plan.monthlyTotal.to)}`
|
|
14348
|
+
].join("\n");
|
|
14349
|
+
if (v["dry-run"]) return out(plan, () => `${text}
|
|
14350
|
+
${dim(t("Dry run: nothing applied.", "Simulaci\xF3n: no se aplic\xF3 nada."))}`);
|
|
14351
|
+
requireYesIfHeadless(v.yes, `ghosty plan apply ${slug}`);
|
|
14352
|
+
await confirm(`${text}
|
|
14353
|
+
${t("Apply this plan now?", "\xBFAplicar este plan ya?")}`, { yes: v.yes, retry: `ghosty plan apply ${slug}` });
|
|
14354
|
+
const r = await api(path, { method: "POST", body: {} });
|
|
14355
|
+
out(r, () => `${lavender("\u2713")} ${r.applied ? t(`Plan applied to ${r.workspace}.`, `Plan aplicado a ${r.workspace}.`) : t("Nothing applied.", "No se aplic\xF3 nada.")}`);
|
|
14356
|
+
}
|
|
14357
|
+
async function boxesUsage(slug) {
|
|
14358
|
+
if (!slug) throw usage(t("Which workspace?", "\xBFQu\xE9 espacio?"), "ghosty usage --boxes --workspace <slug> (or ghosty use <workspace>)");
|
|
14359
|
+
const r = await api(`/api/v2/workspaces/${encodeURIComponent(slug)}/boxes`);
|
|
14360
|
+
const rows = r.agents.map((a) => ({ agent: a.name ?? a.id, engine: a.engine, "per box": a.conversationsPerBox ?? "", boxes: a.boxes ?? "", on: a.boxesOn ?? "", spares: a.spares ?? "", "running now": a.activeTurns ?? "", ...a.error ? { note: a.error } : {} }));
|
|
14361
|
+
const head = `${bold(r.workspace)} ${dim(t(`plan: ${r.plan.parallel} in parallel \xB7 up to ${r.plan.maxBoxes} box(es) \xB7 ${r.plan.hotBoxes} always-on spare(s)`, `plan: ${r.plan.parallel} en paralelo \xB7 hasta ${r.plan.maxBoxes} caja(s) \xB7 ${r.plan.hotBoxes} spare(s) siempre encendido(s)`))}`;
|
|
14362
|
+
const space = r.space ? (r.space.used > r.space.limit ? (s2) => s2 : dim)(
|
|
14363
|
+
t(
|
|
14364
|
+
`${r.space.used} of ${r.space.limit} box(es) in use \xB7 ${r.space.spares} spare \xB7 ${r.space.asleep} asleep${r.space.used > r.space.limit ? " \xB7 OVER the limit" : ""}`,
|
|
14365
|
+
`${r.space.used} de ${r.space.limit} caja(s) \xB7 ${r.space.spares} spare \xB7 ${r.space.asleep} dormida(s)${r.space.used > r.space.limit ? " \xB7 SOBRE el tope" : ""}`
|
|
14366
|
+
)
|
|
14367
|
+
) : dim(t("(could not read the host)", "(no pude leer el host)"));
|
|
14368
|
+
out(r, () => `${head}
|
|
14369
|
+
${space}
|
|
14370
|
+
${table(rows, ["agent", "engine", "per box", "boxes", "on", "spares", "running now"])}
|
|
14371
|
+
${dim(t(`${r.totals.activeTurns} turn(s) running`, `${r.totals.activeTurns} turno(s) corriendo`))}`);
|
|
14249
14372
|
}
|
|
14250
14373
|
|
|
14251
14374
|
// src/commands/demos.ts
|
|
@@ -14580,6 +14703,8 @@ ${dim(`${t("Detail", "Detalle")}: ghosty factory runs show <run> --workspace ${r
|
|
|
14580
14703
|
const impact = { high: t("high", "alto"), medium: t("medium", "medio"), low: t("low", "bajo") }[w.impact] ?? w.impact;
|
|
14581
14704
|
return [
|
|
14582
14705
|
`${bold(`#${w.runId}`)} ${red(w.category)} ${dim(`\xB7 ${t("impact", "impacto")} ${impact} \xB7 ${w.source === "model" ? w.model ?? "model" : t("rules", "reglas")} \xB7 ${short2(w.createdAt)}`)}`,
|
|
14706
|
+
...w.acceptance?.length ? [bold(red(t("Unmet criterion, approved anyway", "Criterio incumplido y aprobado"))), ...w.acceptance.map((g) => ` ${g.at ? hhmm(g.at) : "\u2014"} ${red(g.rule)} \xAB${g.criterion}\xBB
|
|
14707
|
+
${dim(g.evidence)}`), ""] : [],
|
|
14583
14708
|
w.summary,
|
|
14584
14709
|
dim(`${t("signals", "se\xF1ales")}: ${w.reasons.join("; ")}`),
|
|
14585
14710
|
...w.criticalStep ? ["", bold(t("Critical step", "Paso cr\xEDtico")), ` ${w.criticalStep.at ? hhmm(w.criticalStep.at) : "\u2014"} @${w.criticalStep.role ?? "?"} ${dim(w.criticalStep.command ?? "")}`, ` ${w.criticalStep.evidence}`] : [],
|
|
@@ -14967,14 +15092,16 @@ ${bold("Session")}
|
|
|
14967
15092
|
${bold("Workspaces")} ${dim("(changing them: Ghosty staff)")}
|
|
14968
15093
|
bags ls|create|set|rm <workspace> ["bag"] Token bags its agents spend from [--tokens 20M] [--recurring on|off] [--hard-cap on|off] [--note]
|
|
14969
15094
|
spaces ls Your workspaces (role, plan, combo) [--user EMAIL: someone else's]
|
|
14970
|
-
spaces create <slug> New workspace owned by you (trial) [--combo teams|sales|both: staff] [--dry-run]
|
|
15095
|
+
spaces create <slug> New workspace owned by you (trial) [--combo teams|sales|both|none: staff] [--dry-run]
|
|
14971
15096
|
spaces join|leave <workspace> Enter or leave a client's workspace as staff (no seat; logged)
|
|
14972
|
-
spaces set <workspace> --combo sales teams | sales | both (without Sales its boards are invisible) [--model-cap 0.25|1|4|none: most expensive model] [--house-claude on|off]
|
|
15097
|
+
spaces set <workspace> --combo sales teams | sales | both | none (without Sales its boards are invisible) [--model-cap 0.25|1|4|none: most expensive model] [--house-claude on|off]
|
|
14973
15098
|
spaces renew <workspace> --until DATE Move \xABpaid until\xBB (logged) [--note] [--dry-run]
|
|
14974
15099
|
spaces rename <old> <new> Change its slug only [--dry-run]
|
|
14975
15100
|
spaces archive|restore <workspace> Archive it (out of /app and spaces ls; agents and data stay) or bring it back (owner or staff) [--dry-run]
|
|
14976
15101
|
spaces transfer <workspace> --to EMAIL New owner; agents go with it (ACP boxes move with their /data, pool boxes are recycled) [--keep-as admin|member|none] [--copy-keys] [--dry-run]
|
|
14977
15102
|
spaces log <workspace> Its log: transfers, staff in/out, renewals (owner or staff) [--since 30d] [--action workspace]
|
|
15103
|
+
spaces members ls|add|rm <workspace> [email] Its people, without the Members screen (owner, admin or staff) [--role member|admin] [--until 2026-10-28|14d: removed automatically]
|
|
15104
|
+
access why <email> <agent-id> Why someone sees an agent or a board (every reason, and when temporary access expires) [--workspace W --board B]
|
|
14978
15105
|
staff ls [staff-email] [client-email] Ghosty staff assigned to client accounts (staff) [--all: also revoked]
|
|
14979
15106
|
staff assign|unassign <staff> <client> Staff sees and runs that account's agents, documents, databases and boards as themselves (no keys, billing or transfers; logged) [--reason]
|
|
14980
15107
|
settings ls|set|unset <KEY> [value] Platform switches (staff): who answers /c without an account, native subagents\u2026 [+id/-id edits a list]
|
|
@@ -15045,7 +15172,7 @@ ${bold("Configure an agent")}
|
|
|
15045
15172
|
channels wa pair <id> --phone N Pair a personal WhatsApp by code (no QR)
|
|
15046
15173
|
channels wa status|pause <id> Personal WhatsApp: how it is / pause it (keeps the session)
|
|
15047
15174
|
channels wa groups ls|enable|disable|set|create <id> [group] Personal WhatsApp groups it answers, and as whom [--role equipo|cliente] [--wake mention|all] [--name "New name"] [--dry-run]
|
|
15048
|
-
boards ls|create|assign|move-cards|rm A workspace's boards: create (--columns-from), where an agent sends cards, move cards
|
|
15175
|
+
boards ls|create|assign|move-cards|access|rm A workspace's boards: create (--columns-from), where an agent sends cards, move cards, who sees each one
|
|
15049
15176
|
cards ls <id> Recent cards on its sales board [--q TEXT] [--paused] [--limit 20]
|
|
15050
15177
|
cards show <id> <card> A card's thread: who wrote, text, attachments and whether gs kept a copy (folio, phone or id)
|
|
15051
15178
|
cards archive <id> Archive cards in bulk (reversible) --integration X | --column X | --before 30d [--dry-run]
|
|
@@ -15145,14 +15272,16 @@ ${bold("Sesi\xF3n")}
|
|
|
15145
15272
|
${bold("Espacios")} ${dim("(cambiarlos: staff de Ghosty)")}
|
|
15146
15273
|
bags ls|create|set|rm <espacio> ["bolsa"] Bolsas de tokens de las que gastan sus agentes [--tokens 20M] [--recurring on|off] [--hard-cap on|off] [--note]
|
|
15147
15274
|
spaces ls Tus espacios (rol, plan, combo) [--user CORREO: los de alguien m\xE1s]
|
|
15148
|
-
spaces create <slug> Espacio nuevo a tu nombre (trial) [--combo teams|sales|both: staff] [--dry-run]
|
|
15275
|
+
spaces create <slug> Espacio nuevo a tu nombre (trial) [--combo teams|sales|both|none: staff] [--dry-run]
|
|
15149
15276
|
spaces join|leave <espacio> Entra o sal del espacio de un cliente como staff (sin asiento; queda en bit\xE1cora)
|
|
15150
|
-
spaces set <espacio> --combo sales teams | sales | both (sin Ventas sus tableros no se ven) [--model-cap 0.25|1|4|none: el modelo m\xE1s caro] [--house-claude on|off]
|
|
15277
|
+
spaces set <espacio> --combo sales teams | sales | both | none (sin Ventas sus tableros no se ven) [--model-cap 0.25|1|4|none: el modelo m\xE1s caro] [--house-claude on|off]
|
|
15151
15278
|
spaces renew <espacio> --until FECHA Mueve \xABpagado hasta\xBB (queda en bit\xE1cora) [--note] [--dry-run]
|
|
15152
15279
|
spaces rename <viejo> <nuevo> Cambia s\xF3lo su slug [--dry-run]
|
|
15153
15280
|
spaces archive|restore <espacio> Arch\xEDvalo (sale de /app y de spaces ls; agentes y datos se quedan) o tr\xE1elo de vuelta (due\xF1o o staff) [--dry-run]
|
|
15154
15281
|
spaces transfer <espacio> --to CORREO Due\xF1o nuevo; los agentes se van con \xE9l (las cajas ACP se mudan con su /data, las del pool se reciclan) [--keep-as admin|member|none] [--copy-keys] [--dry-run]
|
|
15155
15282
|
spaces log <espacio> Su bit\xE1cora: traspasos, staff que entra o sale, renovaciones (due\xF1o o staff) [--since 30d] [--action workspace]
|
|
15283
|
+
spaces members ls|add|rm <espacio> [correo] Su gente, sin la pantalla Miembros (due\xF1o, admin o staff) [--role member|admin] [--until 2026-10-28|14d: se retira solo]
|
|
15284
|
+
access why <correo> <agente> Por qu\xE9 alguien ve un agente o un tablero (todas las razones y cu\xE1ndo vence lo temporal) [--workspace W --board B]
|
|
15156
15285
|
staff ls [correo-staff] [correo-cliente] Staff de Ghosty asignado a cuentas cliente (staff) [--all: tambi\xE9n revocadas]
|
|
15157
15286
|
staff assign|unassign <staff> <cliente> El staff ve y opera agentes, documentos, bases y tableros de esa cuenta como s\xED mismo (sin llaves, cobro ni traspasos; queda en bit\xE1cora) [--reason]
|
|
15158
15287
|
settings ls|set|unset <CLAVE> [valor] Perillas de la plataforma (staff): qui\xE9n atiende /c sin cuenta, subagentes nativos\u2026 [+id/-id edita una lista]
|
|
@@ -15223,7 +15352,7 @@ ${bold("Configurar un agente")}
|
|
|
15223
15352
|
channels wa pair <id> --phone N Vincula un WhatsApp personal con c\xF3digo (sin QR)
|
|
15224
15353
|
channels wa status|pause <id> WhatsApp personal: c\xF3mo est\xE1 / pausarlo (conserva la sesi\xF3n)
|
|
15225
15354
|
channels wa groups ls|enable|disable|set|create <id> [grupo] Grupos de WhatsApp personal que contesta, y como qui\xE9n [--role equipo|cliente] [--wake mention|all] [--name "Nombre nuevo"] [--dry-run]
|
|
15226
|
-
boards ls|create|assign|move-cards|rm Los tableros de un espacio: crear (--columns-from), a d\xF3nde manda tarjetas un agente, mover tarjetas
|
|
15355
|
+
boards ls|create|assign|move-cards|access|rm Los tableros de un espacio: crear (--columns-from), a d\xF3nde manda tarjetas un agente, mover tarjetas, qui\xE9n ve cada uno
|
|
15227
15356
|
cards ls <id> Tarjetas recientes de su tablero de ventas [--q TEXTO] [--paused] [--limit 20]
|
|
15228
15357
|
cards show <id> <tarjeta> El hilo de una tarjeta: qui\xE9n escribi\xF3, texto, adjuntos y si gs guard\xF3 copia (folio, tel\xE9fono o id)
|
|
15229
15358
|
cards archive <id> Archiva tarjetas en bloque (reversible) --integration X | --column X | --before 30d [--dry-run]
|
|
@@ -15305,7 +15434,7 @@ ${bold("Opciones globales")}
|
|
|
15305
15434
|
${bold("C\xF3digos de salida")} 0 bien \xB7 1 error de la API \xB7 2 uso incorrecto \xB7 3 sin sesi\xF3n
|
|
15306
15435
|
${dim("Nota: `ghosty` puede chocar con otro binario en tu PATH (p. ej. la TUI de Ghosty). Rev\xEDsalo con `which -a ghosty`; corre `npx @ghostystudio/cli` para ir a la segura.")}
|
|
15307
15436
|
${dim("Documentaci\xF3n: https://www.ghosty.studio/docs/cli")}`;
|
|
15308
|
-
var COMMANDS = ["login", "logout", "whoami", "usage", "use", "apply", "plan", "engines", "bags", "spaces", "workspaces", "staff", "settings", "audit", "factory", "demos", "sites", "push", "novedades", "completion", "cards", "agents", "files", "skills", "mcp", "dbs", "turns", "try", "chat", "conversations", "schedule", "teams", "partner", "me", "channels", "board", "boards", "credentials", "connectors", "browser", "support", "docs", "help"];
|
|
15437
|
+
var COMMANDS = ["login", "logout", "whoami", "usage", "use", "apply", "plan", "engines", "bags", "spaces", "workspaces", "staff", "settings", "audit", "factory", "demos", "sites", "push", "novedades", "completion", "cards", "agents", "files", "skills", "mcp", "dbs", "turns", "try", "chat", "conversations", "schedule", "teams", "partner", "me", "channels", "board", "boards", "access", "credentials", "connectors", "browser", "support", "docs", "help"];
|
|
15309
15438
|
var AGENTS_SUBS = ["ls", "create", "get", "show", "set", "export", "doctor", "docs", "share", "unshare", "shares", "teams", "rm", "restart", "demo", "embed", "box"];
|
|
15310
15439
|
function unknown(what, input, known, helpCmd) {
|
|
15311
15440
|
const s2 = suggest(input, known);
|
|
@@ -15456,6 +15585,10 @@ async function main() {
|
|
|
15456
15585
|
enable: { type: "string" },
|
|
15457
15586
|
disable: { type: "string" },
|
|
15458
15587
|
"columns-from": { type: "string" },
|
|
15588
|
+
add: { type: "string", multiple: true },
|
|
15589
|
+
remove: { type: "string", multiple: true },
|
|
15590
|
+
everyone: { type: "boolean" },
|
|
15591
|
+
restrict: { type: "boolean" },
|
|
15459
15592
|
to: { type: "string" },
|
|
15460
15593
|
all: { type: "boolean" },
|
|
15461
15594
|
resolve: { type: "boolean" },
|
|
@@ -15581,7 +15714,7 @@ async function main() {
|
|
|
15581
15714
|
const tokens = splitTokens(pos, v);
|
|
15582
15715
|
globals.token = tokens.session;
|
|
15583
15716
|
globals.profile = v.profile;
|
|
15584
|
-
if (v.version) return out({ version: "0.
|
|
15717
|
+
if (v.version) return out({ version: "0.69.0" }, () => "0.69.0");
|
|
15585
15718
|
for (const n of normalizeArgs(pos, v)) if (!globals.json) info(dim(n));
|
|
15586
15719
|
const context = (await readConfig()).workspace;
|
|
15587
15720
|
if (!explicitToken()?.startsWith("gat_")) {
|
|
@@ -15729,7 +15862,10 @@ async function main() {
|
|
|
15729
15862
|
case "spaces":
|
|
15730
15863
|
case "space":
|
|
15731
15864
|
case "workspaces":
|
|
15865
|
+
if (sub === "members") return spacesMembers(a1, a2, pos[4], v, context);
|
|
15732
15866
|
return spacesCmd(sub, a1, a2, v, context);
|
|
15867
|
+
case "access":
|
|
15868
|
+
return accessCmd(sub, a1, a2, v, context);
|
|
15733
15869
|
case "staff":
|
|
15734
15870
|
return staffCmd(sub, a1, a2, v);
|
|
15735
15871
|
case "settings":
|
|
@@ -15755,7 +15891,7 @@ async function main() {
|
|
|
15755
15891
|
throw unknown(cmd, cmd, COMMANDS, "ghosty --help");
|
|
15756
15892
|
}
|
|
15757
15893
|
}
|
|
15758
|
-
var notice = updateNotice("0.
|
|
15894
|
+
var notice = updateNotice("0.69.0").catch(() => null);
|
|
15759
15895
|
main().then(
|
|
15760
15896
|
async () => {
|
|
15761
15897
|
const n = await notice;
|