replicas-cli 0.3.72 → 0.3.74
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/dist/index.cjs +283 -149
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -111,17 +111,17 @@ var require_visit = __commonJS({
|
|
|
111
111
|
visit.BREAK = BREAK;
|
|
112
112
|
visit.SKIP = SKIP;
|
|
113
113
|
visit.REMOVE = REMOVE;
|
|
114
|
-
function visit_(key, node, visitor,
|
|
115
|
-
const ctrl = callVisitor(key, node, visitor,
|
|
114
|
+
function visit_(key, node, visitor, path8) {
|
|
115
|
+
const ctrl = callVisitor(key, node, visitor, path8);
|
|
116
116
|
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
117
|
-
replaceNode(key,
|
|
118
|
-
return visit_(key, ctrl, visitor,
|
|
117
|
+
replaceNode(key, path8, ctrl);
|
|
118
|
+
return visit_(key, ctrl, visitor, path8);
|
|
119
119
|
}
|
|
120
120
|
if (typeof ctrl !== "symbol") {
|
|
121
121
|
if (identity.isCollection(node)) {
|
|
122
|
-
|
|
122
|
+
path8 = Object.freeze(path8.concat(node));
|
|
123
123
|
for (let i = 0; i < node.items.length; ++i) {
|
|
124
|
-
const ci = visit_(i, node.items[i], visitor,
|
|
124
|
+
const ci = visit_(i, node.items[i], visitor, path8);
|
|
125
125
|
if (typeof ci === "number")
|
|
126
126
|
i = ci - 1;
|
|
127
127
|
else if (ci === BREAK)
|
|
@@ -132,13 +132,13 @@ var require_visit = __commonJS({
|
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
134
|
} else if (identity.isPair(node)) {
|
|
135
|
-
|
|
136
|
-
const ck = visit_("key", node.key, visitor,
|
|
135
|
+
path8 = Object.freeze(path8.concat(node));
|
|
136
|
+
const ck = visit_("key", node.key, visitor, path8);
|
|
137
137
|
if (ck === BREAK)
|
|
138
138
|
return BREAK;
|
|
139
139
|
else if (ck === REMOVE)
|
|
140
140
|
node.key = null;
|
|
141
|
-
const cv = visit_("value", node.value, visitor,
|
|
141
|
+
const cv = visit_("value", node.value, visitor, path8);
|
|
142
142
|
if (cv === BREAK)
|
|
143
143
|
return BREAK;
|
|
144
144
|
else if (cv === REMOVE)
|
|
@@ -159,17 +159,17 @@ var require_visit = __commonJS({
|
|
|
159
159
|
visitAsync.BREAK = BREAK;
|
|
160
160
|
visitAsync.SKIP = SKIP;
|
|
161
161
|
visitAsync.REMOVE = REMOVE;
|
|
162
|
-
async function visitAsync_(key, node, visitor,
|
|
163
|
-
const ctrl = await callVisitor(key, node, visitor,
|
|
162
|
+
async function visitAsync_(key, node, visitor, path8) {
|
|
163
|
+
const ctrl = await callVisitor(key, node, visitor, path8);
|
|
164
164
|
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
165
|
-
replaceNode(key,
|
|
166
|
-
return visitAsync_(key, ctrl, visitor,
|
|
165
|
+
replaceNode(key, path8, ctrl);
|
|
166
|
+
return visitAsync_(key, ctrl, visitor, path8);
|
|
167
167
|
}
|
|
168
168
|
if (typeof ctrl !== "symbol") {
|
|
169
169
|
if (identity.isCollection(node)) {
|
|
170
|
-
|
|
170
|
+
path8 = Object.freeze(path8.concat(node));
|
|
171
171
|
for (let i = 0; i < node.items.length; ++i) {
|
|
172
|
-
const ci = await visitAsync_(i, node.items[i], visitor,
|
|
172
|
+
const ci = await visitAsync_(i, node.items[i], visitor, path8);
|
|
173
173
|
if (typeof ci === "number")
|
|
174
174
|
i = ci - 1;
|
|
175
175
|
else if (ci === BREAK)
|
|
@@ -180,13 +180,13 @@ var require_visit = __commonJS({
|
|
|
180
180
|
}
|
|
181
181
|
}
|
|
182
182
|
} else if (identity.isPair(node)) {
|
|
183
|
-
|
|
184
|
-
const ck = await visitAsync_("key", node.key, visitor,
|
|
183
|
+
path8 = Object.freeze(path8.concat(node));
|
|
184
|
+
const ck = await visitAsync_("key", node.key, visitor, path8);
|
|
185
185
|
if (ck === BREAK)
|
|
186
186
|
return BREAK;
|
|
187
187
|
else if (ck === REMOVE)
|
|
188
188
|
node.key = null;
|
|
189
|
-
const cv = await visitAsync_("value", node.value, visitor,
|
|
189
|
+
const cv = await visitAsync_("value", node.value, visitor, path8);
|
|
190
190
|
if (cv === BREAK)
|
|
191
191
|
return BREAK;
|
|
192
192
|
else if (cv === REMOVE)
|
|
@@ -213,23 +213,23 @@ var require_visit = __commonJS({
|
|
|
213
213
|
}
|
|
214
214
|
return visitor;
|
|
215
215
|
}
|
|
216
|
-
function callVisitor(key, node, visitor,
|
|
216
|
+
function callVisitor(key, node, visitor, path8) {
|
|
217
217
|
if (typeof visitor === "function")
|
|
218
|
-
return visitor(key, node,
|
|
218
|
+
return visitor(key, node, path8);
|
|
219
219
|
if (identity.isMap(node))
|
|
220
|
-
return visitor.Map?.(key, node,
|
|
220
|
+
return visitor.Map?.(key, node, path8);
|
|
221
221
|
if (identity.isSeq(node))
|
|
222
|
-
return visitor.Seq?.(key, node,
|
|
222
|
+
return visitor.Seq?.(key, node, path8);
|
|
223
223
|
if (identity.isPair(node))
|
|
224
|
-
return visitor.Pair?.(key, node,
|
|
224
|
+
return visitor.Pair?.(key, node, path8);
|
|
225
225
|
if (identity.isScalar(node))
|
|
226
|
-
return visitor.Scalar?.(key, node,
|
|
226
|
+
return visitor.Scalar?.(key, node, path8);
|
|
227
227
|
if (identity.isAlias(node))
|
|
228
|
-
return visitor.Alias?.(key, node,
|
|
228
|
+
return visitor.Alias?.(key, node, path8);
|
|
229
229
|
return void 0;
|
|
230
230
|
}
|
|
231
|
-
function replaceNode(key,
|
|
232
|
-
const parent =
|
|
231
|
+
function replaceNode(key, path8, node) {
|
|
232
|
+
const parent = path8[path8.length - 1];
|
|
233
233
|
if (identity.isCollection(parent)) {
|
|
234
234
|
parent.items[key] = node;
|
|
235
235
|
} else if (identity.isPair(parent)) {
|
|
@@ -839,10 +839,10 @@ var require_Collection = __commonJS({
|
|
|
839
839
|
var createNode = require_createNode();
|
|
840
840
|
var identity = require_identity();
|
|
841
841
|
var Node = require_Node();
|
|
842
|
-
function collectionFromPath(schema,
|
|
842
|
+
function collectionFromPath(schema, path8, value) {
|
|
843
843
|
let v = value;
|
|
844
|
-
for (let i =
|
|
845
|
-
const k =
|
|
844
|
+
for (let i = path8.length - 1; i >= 0; --i) {
|
|
845
|
+
const k = path8[i];
|
|
846
846
|
if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
|
|
847
847
|
const a = [];
|
|
848
848
|
a[k] = v;
|
|
@@ -861,7 +861,7 @@ var require_Collection = __commonJS({
|
|
|
861
861
|
sourceObjects: /* @__PURE__ */ new Map()
|
|
862
862
|
});
|
|
863
863
|
}
|
|
864
|
-
var isEmptyPath = (
|
|
864
|
+
var isEmptyPath = (path8) => path8 == null || typeof path8 === "object" && !!path8[Symbol.iterator]().next().done;
|
|
865
865
|
var Collection = class extends Node.NodeBase {
|
|
866
866
|
constructor(type, schema) {
|
|
867
867
|
super(type);
|
|
@@ -891,11 +891,11 @@ var require_Collection = __commonJS({
|
|
|
891
891
|
* be a Pair instance or a `{ key, value }` object, which may not have a key
|
|
892
892
|
* that already exists in the map.
|
|
893
893
|
*/
|
|
894
|
-
addIn(
|
|
895
|
-
if (isEmptyPath(
|
|
894
|
+
addIn(path8, value) {
|
|
895
|
+
if (isEmptyPath(path8))
|
|
896
896
|
this.add(value);
|
|
897
897
|
else {
|
|
898
|
-
const [key, ...rest] =
|
|
898
|
+
const [key, ...rest] = path8;
|
|
899
899
|
const node = this.get(key, true);
|
|
900
900
|
if (identity.isCollection(node))
|
|
901
901
|
node.addIn(rest, value);
|
|
@@ -909,8 +909,8 @@ var require_Collection = __commonJS({
|
|
|
909
909
|
* Removes a value from the collection.
|
|
910
910
|
* @returns `true` if the item was found and removed.
|
|
911
911
|
*/
|
|
912
|
-
deleteIn(
|
|
913
|
-
const [key, ...rest] =
|
|
912
|
+
deleteIn(path8) {
|
|
913
|
+
const [key, ...rest] = path8;
|
|
914
914
|
if (rest.length === 0)
|
|
915
915
|
return this.delete(key);
|
|
916
916
|
const node = this.get(key, true);
|
|
@@ -924,8 +924,8 @@ var require_Collection = __commonJS({
|
|
|
924
924
|
* scalar values from their surrounding node; to disable set `keepScalar` to
|
|
925
925
|
* `true` (collections are always returned intact).
|
|
926
926
|
*/
|
|
927
|
-
getIn(
|
|
928
|
-
const [key, ...rest] =
|
|
927
|
+
getIn(path8, keepScalar) {
|
|
928
|
+
const [key, ...rest] = path8;
|
|
929
929
|
const node = this.get(key, true);
|
|
930
930
|
if (rest.length === 0)
|
|
931
931
|
return !keepScalar && identity.isScalar(node) ? node.value : node;
|
|
@@ -943,8 +943,8 @@ var require_Collection = __commonJS({
|
|
|
943
943
|
/**
|
|
944
944
|
* Checks if the collection includes a value with the key `key`.
|
|
945
945
|
*/
|
|
946
|
-
hasIn(
|
|
947
|
-
const [key, ...rest] =
|
|
946
|
+
hasIn(path8) {
|
|
947
|
+
const [key, ...rest] = path8;
|
|
948
948
|
if (rest.length === 0)
|
|
949
949
|
return this.has(key);
|
|
950
950
|
const node = this.get(key, true);
|
|
@@ -954,8 +954,8 @@ var require_Collection = __commonJS({
|
|
|
954
954
|
* Sets a value in this collection. For `!!set`, `value` needs to be a
|
|
955
955
|
* boolean to add/remove the item from the set.
|
|
956
956
|
*/
|
|
957
|
-
setIn(
|
|
958
|
-
const [key, ...rest] =
|
|
957
|
+
setIn(path8, value) {
|
|
958
|
+
const [key, ...rest] = path8;
|
|
959
959
|
if (rest.length === 0) {
|
|
960
960
|
this.set(key, value);
|
|
961
961
|
} else {
|
|
@@ -3470,9 +3470,9 @@ var require_Document = __commonJS({
|
|
|
3470
3470
|
this.contents.add(value);
|
|
3471
3471
|
}
|
|
3472
3472
|
/** Adds a value to the document. */
|
|
3473
|
-
addIn(
|
|
3473
|
+
addIn(path8, value) {
|
|
3474
3474
|
if (assertCollection(this.contents))
|
|
3475
|
-
this.contents.addIn(
|
|
3475
|
+
this.contents.addIn(path8, value);
|
|
3476
3476
|
}
|
|
3477
3477
|
/**
|
|
3478
3478
|
* Create a new `Alias` node, ensuring that the target `node` has the required anchor.
|
|
@@ -3547,14 +3547,14 @@ var require_Document = __commonJS({
|
|
|
3547
3547
|
* Removes a value from the document.
|
|
3548
3548
|
* @returns `true` if the item was found and removed.
|
|
3549
3549
|
*/
|
|
3550
|
-
deleteIn(
|
|
3551
|
-
if (Collection.isEmptyPath(
|
|
3550
|
+
deleteIn(path8) {
|
|
3551
|
+
if (Collection.isEmptyPath(path8)) {
|
|
3552
3552
|
if (this.contents == null)
|
|
3553
3553
|
return false;
|
|
3554
3554
|
this.contents = null;
|
|
3555
3555
|
return true;
|
|
3556
3556
|
}
|
|
3557
|
-
return assertCollection(this.contents) ? this.contents.deleteIn(
|
|
3557
|
+
return assertCollection(this.contents) ? this.contents.deleteIn(path8) : false;
|
|
3558
3558
|
}
|
|
3559
3559
|
/**
|
|
3560
3560
|
* Returns item at `key`, or `undefined` if not found. By default unwraps
|
|
@@ -3569,10 +3569,10 @@ var require_Document = __commonJS({
|
|
|
3569
3569
|
* scalar values from their surrounding node; to disable set `keepScalar` to
|
|
3570
3570
|
* `true` (collections are always returned intact).
|
|
3571
3571
|
*/
|
|
3572
|
-
getIn(
|
|
3573
|
-
if (Collection.isEmptyPath(
|
|
3572
|
+
getIn(path8, keepScalar) {
|
|
3573
|
+
if (Collection.isEmptyPath(path8))
|
|
3574
3574
|
return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
|
|
3575
|
-
return identity.isCollection(this.contents) ? this.contents.getIn(
|
|
3575
|
+
return identity.isCollection(this.contents) ? this.contents.getIn(path8, keepScalar) : void 0;
|
|
3576
3576
|
}
|
|
3577
3577
|
/**
|
|
3578
3578
|
* Checks if the document includes a value with the key `key`.
|
|
@@ -3583,10 +3583,10 @@ var require_Document = __commonJS({
|
|
|
3583
3583
|
/**
|
|
3584
3584
|
* Checks if the document includes a value at `path`.
|
|
3585
3585
|
*/
|
|
3586
|
-
hasIn(
|
|
3587
|
-
if (Collection.isEmptyPath(
|
|
3586
|
+
hasIn(path8) {
|
|
3587
|
+
if (Collection.isEmptyPath(path8))
|
|
3588
3588
|
return this.contents !== void 0;
|
|
3589
|
-
return identity.isCollection(this.contents) ? this.contents.hasIn(
|
|
3589
|
+
return identity.isCollection(this.contents) ? this.contents.hasIn(path8) : false;
|
|
3590
3590
|
}
|
|
3591
3591
|
/**
|
|
3592
3592
|
* Sets a value in this document. For `!!set`, `value` needs to be a
|
|
@@ -3603,13 +3603,13 @@ var require_Document = __commonJS({
|
|
|
3603
3603
|
* Sets a value in this document. For `!!set`, `value` needs to be a
|
|
3604
3604
|
* boolean to add/remove the item from the set.
|
|
3605
3605
|
*/
|
|
3606
|
-
setIn(
|
|
3607
|
-
if (Collection.isEmptyPath(
|
|
3606
|
+
setIn(path8, value) {
|
|
3607
|
+
if (Collection.isEmptyPath(path8)) {
|
|
3608
3608
|
this.contents = value;
|
|
3609
3609
|
} else if (this.contents == null) {
|
|
3610
|
-
this.contents = Collection.collectionFromPath(this.schema, Array.from(
|
|
3610
|
+
this.contents = Collection.collectionFromPath(this.schema, Array.from(path8), value);
|
|
3611
3611
|
} else if (assertCollection(this.contents)) {
|
|
3612
|
-
this.contents.setIn(
|
|
3612
|
+
this.contents.setIn(path8, value);
|
|
3613
3613
|
}
|
|
3614
3614
|
}
|
|
3615
3615
|
/**
|
|
@@ -5569,9 +5569,9 @@ var require_cst_visit = __commonJS({
|
|
|
5569
5569
|
visit.BREAK = BREAK;
|
|
5570
5570
|
visit.SKIP = SKIP;
|
|
5571
5571
|
visit.REMOVE = REMOVE;
|
|
5572
|
-
visit.itemAtPath = (cst,
|
|
5572
|
+
visit.itemAtPath = (cst, path8) => {
|
|
5573
5573
|
let item = cst;
|
|
5574
|
-
for (const [field2, index] of
|
|
5574
|
+
for (const [field2, index] of path8) {
|
|
5575
5575
|
const tok = item?.[field2];
|
|
5576
5576
|
if (tok && "items" in tok) {
|
|
5577
5577
|
item = tok.items[index];
|
|
@@ -5580,23 +5580,23 @@ var require_cst_visit = __commonJS({
|
|
|
5580
5580
|
}
|
|
5581
5581
|
return item;
|
|
5582
5582
|
};
|
|
5583
|
-
visit.parentCollection = (cst,
|
|
5584
|
-
const parent = visit.itemAtPath(cst,
|
|
5585
|
-
const field2 =
|
|
5583
|
+
visit.parentCollection = (cst, path8) => {
|
|
5584
|
+
const parent = visit.itemAtPath(cst, path8.slice(0, -1));
|
|
5585
|
+
const field2 = path8[path8.length - 1][0];
|
|
5586
5586
|
const coll = parent?.[field2];
|
|
5587
5587
|
if (coll && "items" in coll)
|
|
5588
5588
|
return coll;
|
|
5589
5589
|
throw new Error("Parent collection not found");
|
|
5590
5590
|
};
|
|
5591
|
-
function _visit(
|
|
5592
|
-
let ctrl = visitor(item,
|
|
5591
|
+
function _visit(path8, item, visitor) {
|
|
5592
|
+
let ctrl = visitor(item, path8);
|
|
5593
5593
|
if (typeof ctrl === "symbol")
|
|
5594
5594
|
return ctrl;
|
|
5595
5595
|
for (const field2 of ["key", "value"]) {
|
|
5596
5596
|
const token = item[field2];
|
|
5597
5597
|
if (token && "items" in token) {
|
|
5598
5598
|
for (let i = 0; i < token.items.length; ++i) {
|
|
5599
|
-
const ci = _visit(Object.freeze(
|
|
5599
|
+
const ci = _visit(Object.freeze(path8.concat([[field2, i]])), token.items[i], visitor);
|
|
5600
5600
|
if (typeof ci === "number")
|
|
5601
5601
|
i = ci - 1;
|
|
5602
5602
|
else if (ci === BREAK)
|
|
@@ -5607,10 +5607,10 @@ var require_cst_visit = __commonJS({
|
|
|
5607
5607
|
}
|
|
5608
5608
|
}
|
|
5609
5609
|
if (typeof ctrl === "function" && field2 === "key")
|
|
5610
|
-
ctrl = ctrl(item,
|
|
5610
|
+
ctrl = ctrl(item, path8);
|
|
5611
5611
|
}
|
|
5612
5612
|
}
|
|
5613
|
-
return typeof ctrl === "function" ? ctrl(item,
|
|
5613
|
+
return typeof ctrl === "function" ? ctrl(item, path8) : ctrl;
|
|
5614
5614
|
}
|
|
5615
5615
|
exports2.visit = visit;
|
|
5616
5616
|
}
|
|
@@ -6912,14 +6912,14 @@ var require_parser = __commonJS({
|
|
|
6912
6912
|
case "scalar":
|
|
6913
6913
|
case "single-quoted-scalar":
|
|
6914
6914
|
case "double-quoted-scalar": {
|
|
6915
|
-
const
|
|
6915
|
+
const fs9 = this.flowScalar(this.type);
|
|
6916
6916
|
if (atNextItem || it.value) {
|
|
6917
|
-
map2.items.push({ start, key:
|
|
6917
|
+
map2.items.push({ start, key: fs9, sep: [] });
|
|
6918
6918
|
this.onKeyLine = true;
|
|
6919
6919
|
} else if (it.sep) {
|
|
6920
|
-
this.stack.push(
|
|
6920
|
+
this.stack.push(fs9);
|
|
6921
6921
|
} else {
|
|
6922
|
-
Object.assign(it, { key:
|
|
6922
|
+
Object.assign(it, { key: fs9, sep: [] });
|
|
6923
6923
|
this.onKeyLine = true;
|
|
6924
6924
|
}
|
|
6925
6925
|
return;
|
|
@@ -7047,13 +7047,13 @@ var require_parser = __commonJS({
|
|
|
7047
7047
|
case "scalar":
|
|
7048
7048
|
case "single-quoted-scalar":
|
|
7049
7049
|
case "double-quoted-scalar": {
|
|
7050
|
-
const
|
|
7050
|
+
const fs9 = this.flowScalar(this.type);
|
|
7051
7051
|
if (!it || it.value)
|
|
7052
|
-
fc.items.push({ start: [], key:
|
|
7052
|
+
fc.items.push({ start: [], key: fs9, sep: [] });
|
|
7053
7053
|
else if (it.sep)
|
|
7054
|
-
this.stack.push(
|
|
7054
|
+
this.stack.push(fs9);
|
|
7055
7055
|
else
|
|
7056
|
-
Object.assign(it, { key:
|
|
7056
|
+
Object.assign(it, { key: fs9, sep: [] });
|
|
7057
7057
|
return;
|
|
7058
7058
|
}
|
|
7059
7059
|
case "flow-map-end":
|
|
@@ -8577,10 +8577,10 @@ function mergeDefs(...defs) {
|
|
|
8577
8577
|
function cloneDef(schema) {
|
|
8578
8578
|
return mergeDefs(schema._zod.def);
|
|
8579
8579
|
}
|
|
8580
|
-
function getElementAtPath(obj,
|
|
8581
|
-
if (!
|
|
8580
|
+
function getElementAtPath(obj, path8) {
|
|
8581
|
+
if (!path8)
|
|
8582
8582
|
return obj;
|
|
8583
|
-
return
|
|
8583
|
+
return path8.reduce((acc, key) => acc?.[key], obj);
|
|
8584
8584
|
}
|
|
8585
8585
|
function promiseAllObject(promisesObj) {
|
|
8586
8586
|
const keys = Object.keys(promisesObj);
|
|
@@ -8989,11 +8989,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
8989
8989
|
}
|
|
8990
8990
|
return false;
|
|
8991
8991
|
}
|
|
8992
|
-
function prefixIssues(
|
|
8992
|
+
function prefixIssues(path8, issues) {
|
|
8993
8993
|
return issues.map((iss) => {
|
|
8994
8994
|
var _a3;
|
|
8995
8995
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
8996
|
-
iss.path.unshift(
|
|
8996
|
+
iss.path.unshift(path8);
|
|
8997
8997
|
return iss;
|
|
8998
8998
|
});
|
|
8999
8999
|
}
|
|
@@ -9140,16 +9140,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
9140
9140
|
}
|
|
9141
9141
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
9142
9142
|
const fieldErrors = { _errors: [] };
|
|
9143
|
-
const processError = (error52,
|
|
9143
|
+
const processError = (error52, path8 = []) => {
|
|
9144
9144
|
for (const issue2 of error52.issues) {
|
|
9145
9145
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
9146
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
9146
|
+
issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
|
|
9147
9147
|
} else if (issue2.code === "invalid_key") {
|
|
9148
|
-
processError({ issues: issue2.issues }, [...
|
|
9148
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
9149
9149
|
} else if (issue2.code === "invalid_element") {
|
|
9150
|
-
processError({ issues: issue2.issues }, [...
|
|
9150
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
9151
9151
|
} else {
|
|
9152
|
-
const fullpath = [...
|
|
9152
|
+
const fullpath = [...path8, ...issue2.path];
|
|
9153
9153
|
if (fullpath.length === 0) {
|
|
9154
9154
|
fieldErrors._errors.push(mapper(issue2));
|
|
9155
9155
|
} else {
|
|
@@ -9176,17 +9176,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
9176
9176
|
}
|
|
9177
9177
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
9178
9178
|
const result = { errors: [] };
|
|
9179
|
-
const processError = (error52,
|
|
9179
|
+
const processError = (error52, path8 = []) => {
|
|
9180
9180
|
var _a3, _b;
|
|
9181
9181
|
for (const issue2 of error52.issues) {
|
|
9182
9182
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
9183
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
9183
|
+
issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
|
|
9184
9184
|
} else if (issue2.code === "invalid_key") {
|
|
9185
|
-
processError({ issues: issue2.issues }, [...
|
|
9185
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
9186
9186
|
} else if (issue2.code === "invalid_element") {
|
|
9187
|
-
processError({ issues: issue2.issues }, [...
|
|
9187
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
9188
9188
|
} else {
|
|
9189
|
-
const fullpath = [...
|
|
9189
|
+
const fullpath = [...path8, ...issue2.path];
|
|
9190
9190
|
if (fullpath.length === 0) {
|
|
9191
9191
|
result.errors.push(mapper(issue2));
|
|
9192
9192
|
continue;
|
|
@@ -9218,8 +9218,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
9218
9218
|
}
|
|
9219
9219
|
function toDotPath(_path) {
|
|
9220
9220
|
const segs = [];
|
|
9221
|
-
const
|
|
9222
|
-
for (const seg of
|
|
9221
|
+
const path8 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
9222
|
+
for (const seg of path8) {
|
|
9223
9223
|
if (typeof seg === "number")
|
|
9224
9224
|
segs.push(`[${seg}]`);
|
|
9225
9225
|
else if (typeof seg === "symbol")
|
|
@@ -21911,13 +21911,13 @@ function resolveRef(ref, ctx) {
|
|
|
21911
21911
|
if (!ref.startsWith("#")) {
|
|
21912
21912
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
21913
21913
|
}
|
|
21914
|
-
const
|
|
21915
|
-
if (
|
|
21914
|
+
const path8 = ref.slice(1).split("/").filter(Boolean);
|
|
21915
|
+
if (path8.length === 0) {
|
|
21916
21916
|
return ctx.rootSchema;
|
|
21917
21917
|
}
|
|
21918
21918
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
21919
|
-
if (
|
|
21920
|
-
const key =
|
|
21919
|
+
if (path8[0] === defsKey) {
|
|
21920
|
+
const key = path8[1];
|
|
21921
21921
|
if (!key || !ctx.defs[key]) {
|
|
21922
21922
|
throw new Error(`Reference not found: ${ref}`);
|
|
21923
21923
|
}
|
|
@@ -23279,11 +23279,11 @@ function parseShellScript(script, cwd) {
|
|
|
23279
23279
|
parseUntil(scope, 0, false);
|
|
23280
23280
|
return scope.commands;
|
|
23281
23281
|
}
|
|
23282
|
-
function resolveShellPath(dir,
|
|
23283
|
-
if (
|
|
23284
|
-
if (!
|
|
23282
|
+
function resolveShellPath(dir, path8) {
|
|
23283
|
+
if (path8.includes(SHELL_OPAQUE) || path8.startsWith("~")) return null;
|
|
23284
|
+
if (!path8.startsWith("/") && dir === null) return null;
|
|
23285
23285
|
const parts = [];
|
|
23286
|
-
for (const part of (
|
|
23286
|
+
for (const part of (path8.startsWith("/") ? path8 : `${dir}/${path8}`).split("/")) {
|
|
23287
23287
|
if (part === "..") parts.pop();
|
|
23288
23288
|
else if (part && part !== ".") parts.push(part);
|
|
23289
23289
|
}
|
|
@@ -23637,8 +23637,8 @@ function parseSkillName(tool, input) {
|
|
|
23637
23637
|
const skillName = parsedInput.skill ?? parsedInput.name;
|
|
23638
23638
|
return typeof skillName === "string" && skillName ? skillName : null;
|
|
23639
23639
|
}
|
|
23640
|
-
function skillNameFromFilePath(
|
|
23641
|
-
const parts =
|
|
23640
|
+
function skillNameFromFilePath(path8) {
|
|
23641
|
+
const parts = path8.split(/[\\/]+/).filter(Boolean);
|
|
23642
23642
|
if (parts.length < 2 || parts[parts.length - 1].toLowerCase() !== "skill.md") return null;
|
|
23643
23643
|
const skillName = parts[parts.length - 2];
|
|
23644
23644
|
return /[*?[\]{}…$]/.test(skillName) || ["skills", ".system"].includes(skillName.toLowerCase()) ? null : skillName;
|
|
@@ -23648,19 +23648,19 @@ function skillFilePath(tool, input) {
|
|
|
23648
23648
|
if (!READ_TOOL_NAMES.has(tool.toLowerCase())) return null;
|
|
23649
23649
|
const parsedInput = typeof input === "string" ? safeJsonParse(input, null) : input;
|
|
23650
23650
|
if (!isRecord(parsedInput)) return null;
|
|
23651
|
-
const
|
|
23652
|
-
return
|
|
23651
|
+
const path8 = [parsedInput.path, parsedInput.filePath, parsedInput.file_path].find((value) => typeof value === "string" && value.length > 0);
|
|
23652
|
+
return path8 && skillNameFromFilePath(path8) ? path8 : null;
|
|
23653
23653
|
}
|
|
23654
23654
|
function createCallDisplayMessage(message2) {
|
|
23655
23655
|
if (message2.inputRequest) return { ...message2, type: "tool_call" };
|
|
23656
|
-
const
|
|
23657
|
-
const skillName = message2.server.toLowerCase() === "skills" ? message2.tool :
|
|
23656
|
+
const path8 = skillFilePath(message2.tool, message2.input);
|
|
23657
|
+
const skillName = message2.server.toLowerCase() === "skills" ? message2.tool : path8 ? skillNameFromFilePath(path8) : parseSkillName(message2.tool, message2.input);
|
|
23658
23658
|
if (skillName === null) return { ...message2, type: "tool_call" };
|
|
23659
23659
|
return {
|
|
23660
23660
|
id: message2.id,
|
|
23661
23661
|
type: "skill",
|
|
23662
23662
|
skillName,
|
|
23663
|
-
...
|
|
23663
|
+
...path8 ? { path: path8 } : {},
|
|
23664
23664
|
status: message2.status,
|
|
23665
23665
|
timestamp: message2.timestamp
|
|
23666
23666
|
};
|
|
@@ -23673,11 +23673,11 @@ function insertDisplayMessageByTimestamp(messages, message2) {
|
|
|
23673
23673
|
}
|
|
23674
23674
|
|
|
23675
23675
|
// ../shared/src/display-message/format.ts
|
|
23676
|
-
function fileContentDiff(
|
|
23676
|
+
function fileContentDiff(path8, content, action) {
|
|
23677
23677
|
const lines = content.replace(/\n$/, "").split("\n");
|
|
23678
23678
|
return [
|
|
23679
|
-
`--- ${action === "add" ? "/dev/null" : `a/${
|
|
23680
|
-
`+++ ${action === "add" ? `b/${
|
|
23679
|
+
`--- ${action === "add" ? "/dev/null" : `a/${path8}`}`,
|
|
23680
|
+
`+++ ${action === "add" ? `b/${path8}` : "/dev/null"}`,
|
|
23681
23681
|
action === "add" ? `@@ -0,0 +1,${lines.length} @@` : `@@ -1,${lines.length} +0,0 @@`,
|
|
23682
23682
|
...lines.map((line) => `${action === "add" ? "+" : "-"}${line}`)
|
|
23683
23683
|
].join("\n");
|
|
@@ -23704,7 +23704,7 @@ var LINE_COUNT_VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
|
23704
23704
|
]);
|
|
23705
23705
|
var SCRIPT_ROOT = "/";
|
|
23706
23706
|
var commandName = (argv) => argv[0].split("/").pop() ?? argv[0];
|
|
23707
|
-
var fileWrites = ({ writes }) => writes.filter(({ path:
|
|
23707
|
+
var fileWrites = ({ writes }) => writes.filter(({ path: path8 }) => path8 !== "/dev/null");
|
|
23708
23708
|
function shellCommands(command) {
|
|
23709
23709
|
return parseShellScript(command, SCRIPT_ROOT).filter(({ wrapper }) => !wrapper);
|
|
23710
23710
|
}
|
|
@@ -23716,8 +23716,8 @@ function skillNamesFromCommand(command) {
|
|
|
23716
23716
|
if (!SKILL_READ_COMMANDS.has(name) || writesFiles(name, argv) || fileWrites(shellCommand).length > 0) return [];
|
|
23717
23717
|
const paths = readCommandPaths(name, argv);
|
|
23718
23718
|
const stdinTarget = shellCommand.stdinTarget?.replaceAll(SHELL_OPAQUE, "\u2026");
|
|
23719
|
-
return (paths.length === 0 && stdinTarget ? [stdinTarget] : paths).flatMap((
|
|
23720
|
-
const resolved =
|
|
23719
|
+
return (paths.length === 0 && stdinTarget ? [stdinTarget] : paths).flatMap((path8) => {
|
|
23720
|
+
const resolved = path8.startsWith("~") ? path8 : resolveShellPath(shellCommand.dir, path8)?.replace(SCRIPT_ROOT, "");
|
|
23721
23721
|
const skillName = resolved && skillNameFromFilePath(resolved);
|
|
23722
23722
|
return skillName ? [skillName] : [];
|
|
23723
23723
|
});
|
|
@@ -24197,7 +24197,7 @@ Starts an ffmpeg screen recorder and returns only after ffmpeg has written the f
|
|
|
24197
24197
|
Only one recording at a time. Re-running \`start\` while one is active fails - call \`stop\` first.
|
|
24198
24198
|
|
|
24199
24199
|
### \`replicas computer record stop\`
|
|
24200
|
-
SIGINTs ffmpeg, verifies that the process has finalized the MP4, then prints the output path. A finalization timeout preserves the recording state so \`stop\` can be retried safely.
|
|
24200
|
+
SIGINTs ffmpeg, verifies that the process has finalized the MP4, then prints the output path. A finalization timeout preserves the recording state so \`stop\` can be retried safely. To show the interaction in a PR or message, turn it into a short looping GIF with \`replicas media gif <path>\`, then upload with \`replicas media upload <path> --name "<name>"\`.
|
|
24201
24201
|
|
|
24202
24202
|
## Patterns
|
|
24203
24203
|
|
|
@@ -24242,9 +24242,10 @@ For tasks the user wants proof of:
|
|
|
24242
24242
|
replicas computer record start /tmp/walkthrough.mp4
|
|
24243
24243
|
# ... your work ...
|
|
24244
24244
|
replicas computer record stop
|
|
24245
|
-
replicas media
|
|
24245
|
+
replicas media gif /tmp/walkthrough.mp4 --duration 8
|
|
24246
|
+
replicas media upload /tmp/walkthrough.gif /tmp/walkthrough.mp4 --name "Walkthrough" --name "Walkthrough recording"
|
|
24246
24247
|
\`\`\`
|
|
24247
|
-
Then embed the printed \`\`
|
|
24248
|
+
Then embed the printed \`\` lines in your chat reply and follow \`MEDIA.md\` for any external destination: the GIF goes inline in PRs, and a grid of extracted frames never does.
|
|
24248
24249
|
|
|
24249
24250
|
## Failure modes
|
|
24250
24251
|
|
|
@@ -24886,7 +24887,7 @@ gh pr review 123 --request-changes --body "Changes needed"
|
|
|
24886
24887
|
|
|
24887
24888
|
## Media in GitHub workflows
|
|
24888
24889
|
|
|
24889
|
-
Media delivery is owned by \`references/MEDIA.md\`. Read
|
|
24890
|
+
Media delivery is owned by \`references/MEDIA.md\`. Read it before adding screenshots, GIFs, recordings, diagrams, or HTML reports to a pull request, issue, review comment, or commit; it covers when to use a GIF instead of screenshots, the public links every image upload prints, recording previews, organization-only HTML links, and the required **View in Replicas** link.
|
|
24890
24891
|
`;
|
|
24891
24892
|
var GITHUB_ABILITY = {
|
|
24892
24893
|
label: "GitHub",
|
|
@@ -25069,24 +25070,74 @@ var LINEAR_ABILITY = {
|
|
|
25069
25070
|
|
|
25070
25071
|
// ../shared/src/default-skills/replicas-agent/abilities/media.ts
|
|
25071
25072
|
var SECTION7 = `### Media
|
|
25072
|
-
Deliver screenshots, screen recordings, generated diagrams, audio clips, and self-contained HTML pages to the Replicas dashboard and, when applicable, inline in the destination workflow.
|
|
25073
|
+
Deliver screenshots, GIFs, screen recordings, generated diagrams, audio clips, and self-contained HTML pages to the Replicas dashboard and, when applicable, inline in the destination workflow.
|
|
25073
25074
|
|
|
25074
25075
|
**Reference:** \`references/MEDIA.md\`
|
|
25075
25076
|
|
|
25076
25077
|
Use this when:
|
|
25077
25078
|
- You are about to run \`replicas media upload\`; this reference owns the complete Replicas-first, destination-second workflow
|
|
25078
25079
|
- You produce a screenshot, recording, generated image, or audio clip the user should see
|
|
25080
|
+
- You need to show motion or an interaction (an animation, a popup that moves, a flow) in a PR or message: make a short looping GIF with \`replicas media gif\`, never a grid of frames
|
|
25079
25081
|
- You produce a self-contained HTML report that should be linked from a pull request
|
|
25080
25082
|
- You record video output (browser automation, screen capture) \u2014 including the recommended aspect ratio and FPS
|
|
25081
25083
|
- You need to embed media in a Slack/Linear/GitHub/GitLab message AND keep a referenceable copy in the Replicas dashboard`;
|
|
25082
|
-
var REFERENCE7 = `# Media (Screenshots, Recordings, Audio, HTML)
|
|
25084
|
+
var REFERENCE7 = `# Media (Screenshots, GIFs, Recordings, Audio, HTML)
|
|
25083
25085
|
|
|
25084
|
-
This is the single source of truth for delivering screenshots, screen recordings, generated diagrams, audio clips, and self-contained HTML pages through Replicas and external surfaces (Slack, Linear, GitHub, GitLab).
|
|
25086
|
+
This is the single source of truth for delivering screenshots, GIFs, screen recordings, generated diagrams, audio clips, and self-contained HTML pages through Replicas and external surfaces (Slack, Linear, GitHub, GitLab).
|
|
25085
25087
|
|
|
25086
25088
|
## Prerequisites
|
|
25087
25089
|
|
|
25088
25090
|
The \`replicas\` CLI is pre-installed and authenticated in your workspace. No additional setup is needed.
|
|
25089
25091
|
|
|
25092
|
+
## Screenshot, GIF, or recording
|
|
25093
|
+
|
|
25094
|
+
Pick the format from what the reader has to see:
|
|
25095
|
+
|
|
25096
|
+
- **Static UI** (a layout, a new button, an error message): still screenshots.
|
|
25097
|
+
- **Motion or an interaction** (an animation, a popup that moves or flickers, a drag, a short multi-step flow): a short looping GIF. It plays inline in GitHub, Slack, Linear, GitLab, and Replicas chat, with no click and no sign-in.
|
|
25098
|
+
- **A long walkthrough, or anything with sound**: the MP4 recording, shown as a GIF or poster that links to it (see GitHub below).
|
|
25099
|
+
|
|
25100
|
+
Never paste a contact sheet or grid of frames extracted from a recording, and never paste a run of separate frame screenshots. At PR width each frame is a thumbnail, and the reader can't tell what moved. Make a GIF instead.
|
|
25101
|
+
|
|
25102
|
+
### Make a GIF from a recording
|
|
25103
|
+
|
|
25104
|
+
\`\`\`bash
|
|
25105
|
+
replicas computer record start /tmp/after.mp4 --fps 30
|
|
25106
|
+
# ... perform only the interaction ...
|
|
25107
|
+
replicas computer record stop
|
|
25108
|
+
replicas media gif /tmp/after.mp4 --start 1 --duration 6
|
|
25109
|
+
replicas media upload /tmp/after.gif --name "Language menu after fix"
|
|
25110
|
+
\`\`\`
|
|
25111
|
+
|
|
25112
|
+
\`replicas media gif <recording>\` takes any MP4, WebM, or MOV (desktop, Playwright, CDP screencast, or simulator recordings) and writes a looping GIF next to it (\`-o\` to choose the path). It starts at 12 fps and 960 px wide and lowers both until the file is under 5 MiB. GitHub's image proxy returns 404 for larger images, so a bigger GIF shows as a broken image in the PR.
|
|
25113
|
+
|
|
25114
|
+
- Keep it to the interaction, usually 3\u201310 seconds: \`--start\` and \`--duration\` (default 10, max 30).
|
|
25115
|
+
- When the change is small on a large screen, \`--crop w:h:x:y\` (recording pixels) to the area that changes so text stays readable. Use the same crop for the before and after GIFs.
|
|
25116
|
+
- If it reports the GIF is still too large, show less: a shorter \`--duration\` or a tighter \`--crop\`.
|
|
25117
|
+
- Upload the GIF like any image. Its printed \`\` line is public and renders inline everywhere.
|
|
25118
|
+
- Older workspaces may not have \`replicas media gif\` yet (\`replicas media gif --help\` fails). Use the same ffmpeg settings directly; keep \`-ss\` and \`-t\` before \`-i\` (palettegen waits for its input to end, so trimming after \`-i\` never finishes), and if the file is over 5 MiB, lower \`fps\` and the width and run it again:
|
|
25119
|
+
|
|
25120
|
+
\`\`\`bash
|
|
25121
|
+
ffmpeg -v error -y -ss 1 -t 6 -i /tmp/after.mp4 \\
|
|
25122
|
+
-vf "fps=12,scale='min(960,iw)':-1:flags=lanczos,split[a][b];[a]palettegen=stats_mode=diff[p];[b][p]paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle" \\
|
|
25123
|
+
-loop 0 /tmp/after.gif
|
|
25124
|
+
\`\`\`
|
|
25125
|
+
|
|
25126
|
+
ffmpeg is baked into the workspace image. If it's missing, install it with \`sudo apt-get install -y ffmpeg\`.
|
|
25127
|
+
|
|
25128
|
+
### Before and after
|
|
25129
|
+
|
|
25130
|
+
Record both with the same steps, window size, and crop. Say in one line what to watch for, then put the GIFs side by side in a table, or in labeled sections when they are wide:
|
|
25131
|
+
|
|
25132
|
+
\`\`\`markdown
|
|
25133
|
+
The menu should open on its trigger. Before, it jumps about 95px up in half the openings.
|
|
25134
|
+
|
|
25135
|
+
| Before | After |
|
|
25136
|
+
| --- | --- |
|
|
25137
|
+
|  |  |
|
|
25138
|
+
| [View in Replicas](<before-dashboard-url>) | [View in Replicas](<after-dashboard-url>) |
|
|
25139
|
+
\`\`\`
|
|
25140
|
+
|
|
25090
25141
|
## When to upload
|
|
25091
25142
|
|
|
25092
25143
|
Upload to Replicas in these cases \u2014 and **only** these cases:
|
|
@@ -25113,7 +25164,7 @@ If none of these apply, don't upload.
|
|
|
25113
25164
|
| Slack | \`files.getUploadURLExternal\` \u2192 raw-byte POST \u2192 \`files.completeUploadExternal\` | Uploaded file in the channel or thread |
|
|
25114
25165
|
| Linear | \`fileUpload\` mutation \u2192 presigned upload \u2192 issue/comment mutation | Returned \`assetUrl\` in Markdown |
|
|
25115
25166
|
| GitLab | Project \`/uploads\` endpoint with the original bytes | Returned GitLab Markdown |
|
|
25116
|
-
| GitHub | Printed public embed for an image or recording poster | Printed embed, linked to the recording when needed |
|
|
25167
|
+
| GitHub | Printed public embed for an image, GIF, or recording poster | Printed embed, linked to the recording when needed |
|
|
25117
25168
|
|
|
25118
25169
|
The dashboard link is the subtitle and jump-back path. It is never a substitute for the destination embed.
|
|
25119
25170
|
|
|
@@ -25318,7 +25369,7 @@ jq -n \\
|
|
|
25318
25369
|
}' | linear_graphql
|
|
25319
25370
|
\`\`\`
|
|
25320
25371
|
|
|
25321
|
-
For a recording, upload the MP4 with its own MIME type, then upload a poster frame (\`ffmpeg -i /tmp/demo.mp4 -frames:v 1 /tmp/demo-poster.png\`) the same way as \`image/png\` and link it: \`[](<recording-asset-url>)\`.
|
|
25372
|
+
To show motion, upload the GIF from \`replicas media gif\` this way as \`image/gif\` and embed its \`assetUrl\` like a screenshot. For a full recording, upload the MP4 with its own MIME type, then upload a poster frame (\`ffmpeg -i /tmp/demo.mp4 -frames:v 1 /tmp/demo-poster.png\`) the same way as \`image/png\` and link it: \`[](<recording-asset-url>)\`.
|
|
25322
25373
|
|
|
25323
25374
|
The same flow works for issue bodies (use \`issueCreate\` / \`issueUpdate\` with the same markdown body).
|
|
25324
25375
|
|
|
@@ -25343,10 +25394,10 @@ gh pr edit 456 --body-file /tmp/pr-body.md
|
|
|
25343
25394
|
gh pr comment 456 --body-file /tmp/comment.md
|
|
25344
25395
|
\`\`\`
|
|
25345
25396
|
|
|
25346
|
-
|
|
25397
|
+
GitHub does not play external videos inline, so show motion with a GIF (see *Make a GIF from a recording* above); its printed embed animates inline like any image. Videos stay private. When the full recording is also worth watching, upload the MP4 too and link the GIF to the recording's **View in Replicas** URL. When a still is enough, use a poster instead (\`ffmpeg -i /tmp/demo.mp4 -frames:v 1 /tmp/demo-poster.png\`), uploaded like any image:
|
|
25347
25398
|
|
|
25348
25399
|
\`\`\`markdown
|
|
25349
|
-
[](<recording-dashboard-url>)
|
|
25350
25401
|
\`\`\`
|
|
25351
25402
|
|
|
25352
25403
|
Public links are unauthenticated bearer capabilities. Revoke with \`replicas media revoke <media-id>\` **only** when the user asks or the media should intentionally stop rendering; never as routine post-task cleanup, since revoking breaks every embed already posted on the PR.
|
|
@@ -25378,13 +25429,15 @@ const context = await browser.newContext({
|
|
|
25378
25429
|
|
|
25379
25430
|
For \`ffmpeg\` screen captures, pass \`-r 30\` (or \`-r 60\`) to set the frame rate.
|
|
25380
25431
|
|
|
25432
|
+
Start recording just before the interaction and stop right after it, so the GIF made from it stays short.
|
|
25433
|
+
|
|
25381
25434
|
## Supported formats
|
|
25382
25435
|
|
|
25383
25436
|
Auto-detected from the filename extension:
|
|
25384
25437
|
|
|
25385
25438
|
| Extension | Kind |
|
|
25386
25439
|
|---|---|
|
|
25387
|
-
| \`png\`, \`jpg\`, \`jpeg\`, \`webp\` | image |
|
|
25440
|
+
| \`png\`, \`jpg\`, \`jpeg\`, \`webp\`, \`gif\` | image |
|
|
25388
25441
|
| \`mp4\`, \`webm\` | video |
|
|
25389
25442
|
| \`mp3\`, \`wav\` | audio |
|
|
25390
25443
|
| \`html\`, \`htm\` | html |
|
|
@@ -25407,7 +25460,7 @@ replicas media upload chart-a.svg chart-b.svg --name "Latency chart" --name "Err
|
|
|
25407
25460
|
var MEDIA_ABILITY = {
|
|
25408
25461
|
label: "Media",
|
|
25409
25462
|
description: "Deliver media to Replicas and destination workflows with inline uploads.",
|
|
25410
|
-
bullet: "- Producing or showing the user any media \u2014 screenshots, screen recordings, generated images or diagrams, audio clips, or HTML recap pages \u2014 including in your Replicas chat reply, PR descriptions/comments, and other external platforms. Paste the printed `` embeds in your chat reply, never only dashboard links, and upload the file itself to Slack, Linear, or GitLab",
|
|
25463
|
+
bullet: "- Producing or showing the user any media \u2014 screenshots, screen recordings, generated images or diagrams, audio clips, or HTML recap pages \u2014 including in your Replicas chat reply, PR descriptions/comments, and other external platforms. Paste the printed `` embeds in your chat reply, never only dashboard links, and upload the file itself to Slack, Linear, or GitLab. To show motion, turn the recording into a short GIF with `replicas media gif` instead of a grid of frames",
|
|
25411
25464
|
section: SECTION7,
|
|
25412
25465
|
referenceFile: { name: "MEDIA.md", content: REFERENCE7 }
|
|
25413
25466
|
};
|
|
@@ -26392,7 +26445,7 @@ function stripAttachmentNote(text3) {
|
|
|
26392
26445
|
}
|
|
26393
26446
|
return {
|
|
26394
26447
|
content,
|
|
26395
|
-
files: match ? [...match[1].matchAll(/^- (.+)$/gm)].map(([,
|
|
26448
|
+
files: match ? [...match[1].matchAll(/^- (.+)$/gm)].map(([, path8]) => path8) : [],
|
|
26396
26449
|
walkthroughs
|
|
26397
26450
|
};
|
|
26398
26451
|
}
|
|
@@ -27278,7 +27331,7 @@ function parseOpencodeEvents(events) {
|
|
|
27278
27331
|
upsertDisplayMessage(messages, {
|
|
27279
27332
|
id,
|
|
27280
27333
|
type: "file_change",
|
|
27281
|
-
changes: files.map((
|
|
27334
|
+
changes: files.map((path8) => ({ path: path8, kind: "update" })),
|
|
27282
27335
|
status: "completed",
|
|
27283
27336
|
timestamp
|
|
27284
27337
|
});
|
|
@@ -28593,7 +28646,7 @@ var headlessAgentRequestSchema = external_exports.object({
|
|
|
28593
28646
|
});
|
|
28594
28647
|
|
|
28595
28648
|
// ../shared/src/cli-version.ts
|
|
28596
|
-
var CLI_VERSION = "0.3.
|
|
28649
|
+
var CLI_VERSION = "0.3.74";
|
|
28597
28650
|
|
|
28598
28651
|
// ../shared/src/version.ts
|
|
28599
28652
|
function compareVersions(v1, v2) {
|
|
@@ -31074,8 +31127,8 @@ async function claudeAuthCommand(options = {}) {
|
|
|
31074
31127
|
var CLIENT_ID = "1031625952748946";
|
|
31075
31128
|
var AUTH_URL = "https://auth.meta.com";
|
|
31076
31129
|
var API_KEY_URL = "https://api.meta.ai/muse-code/key";
|
|
31077
|
-
async function post(
|
|
31078
|
-
return fetch(`${AUTH_URL}${
|
|
31130
|
+
async function post(path8, body) {
|
|
31131
|
+
return fetch(`${AUTH_URL}${path8}`, {
|
|
31079
31132
|
method: "POST",
|
|
31080
31133
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
31081
31134
|
body
|
|
@@ -31271,7 +31324,7 @@ async function credentialsGetCommand(service, options) {
|
|
|
31271
31324
|
});
|
|
31272
31325
|
}
|
|
31273
31326
|
async function credentialsSetCommand(service, options) {
|
|
31274
|
-
const
|
|
31327
|
+
const path8 = credentialsPath(service, options, true);
|
|
31275
31328
|
const { org: org2, models, ...fields } = options;
|
|
31276
31329
|
const secretField = service === "bedrock" ? "aws_secret_access_key" : "api_key";
|
|
31277
31330
|
const body = {
|
|
@@ -31279,7 +31332,7 @@ async function credentialsSetCommand(service, options) {
|
|
|
31279
31332
|
...models ? { models: models.split(",").map((model2) => model2.trim()).filter(Boolean) } : {},
|
|
31280
31333
|
[secretField]: await readSecret(service, secretField === "api_key" ? "API key" : "AWS secret access key")
|
|
31281
31334
|
};
|
|
31282
|
-
const response = await orgAuthenticatedFetch(
|
|
31335
|
+
const response = await orgAuthenticatedFetch(path8, { method: "POST", body });
|
|
31283
31336
|
output(response, () => console.log(import_chalk17.default.green(`Saved ${scopeLabel(options)} ${service} credentials.`)));
|
|
31284
31337
|
}
|
|
31285
31338
|
async function credentialsRemoveCommand(service, options) {
|
|
@@ -31364,10 +31417,9 @@ function printEnvironment(env) {
|
|
|
31364
31417
|
if (env.description) {
|
|
31365
31418
|
console.log(import_chalk19.default.gray(` Description: ${env.description}`));
|
|
31366
31419
|
}
|
|
31367
|
-
|
|
31368
|
-
|
|
31369
|
-
|
|
31370
|
-
console.log(import_chalk19.default.gray(` Repository Set: ${env.repository_set_id}`));
|
|
31420
|
+
const repositoryIds = env.repository_ids ?? [];
|
|
31421
|
+
if (repositoryIds.length > 0) {
|
|
31422
|
+
console.log(import_chalk19.default.gray(` Repositories: ${repositoryIds.join(", ")}`));
|
|
31371
31423
|
}
|
|
31372
31424
|
if (env.variable_count !== void 0) {
|
|
31373
31425
|
console.log(import_chalk19.default.gray(` Variables: ${env.variable_count}, Files: ${env.file_count ?? 0}, Skills: ${env.skill_count ?? 0}, MCPs: ${env.mcp_count ?? 0}`));
|
|
@@ -32088,7 +32140,7 @@ async function replicaCreateCommand(name, options) {
|
|
|
32088
32140
|
choices: environments.map((env) => ({
|
|
32089
32141
|
title: env.name,
|
|
32090
32142
|
value: env.id,
|
|
32091
|
-
description: env.is_global ? "global" : env.
|
|
32143
|
+
description: env.is_global ? "global" : `${env.repository_ids?.length ?? 0} repositories`
|
|
32092
32144
|
}))
|
|
32093
32145
|
});
|
|
32094
32146
|
const answer = response2.environment;
|
|
@@ -32564,7 +32616,7 @@ async function canvasPutCommand(id, filename, options) {
|
|
|
32564
32616
|
|
|
32565
32617
|
// src/commands/chat.ts
|
|
32566
32618
|
var import_chalk23 = __toESM(require("chalk"));
|
|
32567
|
-
var chatPath2 = (id, chatId,
|
|
32619
|
+
var chatPath2 = (id, chatId, path8 = "") => `/v1/replica/${id}/chats/${chatId}${path8}`;
|
|
32568
32620
|
function printQueue(queue) {
|
|
32569
32621
|
if (queue.length === 0) {
|
|
32570
32622
|
console.log("Queue is empty.");
|
|
@@ -32649,8 +32701,8 @@ async function chatQueueListCommand(id, chatId) {
|
|
|
32649
32701
|
printQueue(queue);
|
|
32650
32702
|
});
|
|
32651
32703
|
}
|
|
32652
|
-
async function mutateQueue(
|
|
32653
|
-
output(await orgAuthenticatedFetch(
|
|
32704
|
+
async function mutateQueue(path8, method, body) {
|
|
32705
|
+
output(await orgAuthenticatedFetch(path8, { method, body }), ({ queue }) => {
|
|
32654
32706
|
if (queue) printQueue(queue);
|
|
32655
32707
|
else console.log("Done.");
|
|
32656
32708
|
});
|
|
@@ -32663,7 +32715,7 @@ var chatQueueActionCommand = (action) => (id, chatId, messageId) => mutateQueue(
|
|
|
32663
32715
|
|
|
32664
32716
|
// src/commands/plugins.ts
|
|
32665
32717
|
var import_chalk24 = __toESM(require("chalk"));
|
|
32666
|
-
var pluginsPath = async ({ env },
|
|
32718
|
+
var pluginsPath = async ({ env }, path8) => env ? `/v1/environments/${await resolveEnvironmentId(env)}/plugins${path8}` : `/v1/plugins${path8}`;
|
|
32667
32719
|
async function pluginsListCommand(options) {
|
|
32668
32720
|
output(await orgAuthenticatedFetch(await pluginsPath(options, "/connections")), ({ plugins: plugins2, environment: environment2 }) => {
|
|
32669
32721
|
if (!options.all && environment2.length === 0) console.log("No plugins connected. Pass --all to list available plugins.");
|
|
@@ -33393,7 +33445,7 @@ async function automationCreateCommand(name, options) {
|
|
|
33393
33445
|
choices: selectableEnvs.map((env) => ({
|
|
33394
33446
|
title: env.name,
|
|
33395
33447
|
value: env.id,
|
|
33396
|
-
description: env.description ||
|
|
33448
|
+
description: env.description || `${env.repository_ids?.length ?? 0} repositories`
|
|
33397
33449
|
}))
|
|
33398
33450
|
});
|
|
33399
33451
|
if (!envResponse2.env) {
|
|
@@ -33718,10 +33770,10 @@ var import_chalk27 = __toESM(require("chalk"));
|
|
|
33718
33770
|
|
|
33719
33771
|
// src/lib/agent-api.ts
|
|
33720
33772
|
var ENGINE_PORT = process.env.REPLICAS_ENGINE_PORT || "3737";
|
|
33721
|
-
async function agentFetch(
|
|
33722
|
-
return (await agentRequest(
|
|
33773
|
+
async function agentFetch(path8, options) {
|
|
33774
|
+
return (await agentRequest(path8, options)).json();
|
|
33723
33775
|
}
|
|
33724
|
-
async function agentRequest(
|
|
33776
|
+
async function agentRequest(path8, options) {
|
|
33725
33777
|
const config3 = readAgentConfig();
|
|
33726
33778
|
if (!config3) {
|
|
33727
33779
|
throw new Error("Agent mode config not found");
|
|
@@ -33735,7 +33787,7 @@ async function agentRequest(path7, options) {
|
|
|
33735
33787
|
...options?.headers || {}
|
|
33736
33788
|
};
|
|
33737
33789
|
const body = options?.body === void 0 ? void 0 : isFormData ? options.body : JSON.stringify(options.body);
|
|
33738
|
-
const response = await fetch(`${MONOLITH_URL}${
|
|
33790
|
+
const response = await fetch(`${MONOLITH_URL}${path8}`, {
|
|
33739
33791
|
...options,
|
|
33740
33792
|
headers,
|
|
33741
33793
|
body
|
|
@@ -33746,7 +33798,7 @@ async function agentRequest(path7, options) {
|
|
|
33746
33798
|
}
|
|
33747
33799
|
return response;
|
|
33748
33800
|
}
|
|
33749
|
-
async function engineFetch(
|
|
33801
|
+
async function engineFetch(path8, options) {
|
|
33750
33802
|
const config3 = readAgentConfig();
|
|
33751
33803
|
if (!config3) {
|
|
33752
33804
|
throw new Error("Agent mode config not found");
|
|
@@ -33756,7 +33808,7 @@ async function engineFetch(path7, options) {
|
|
|
33756
33808
|
"Content-Type": "application/json",
|
|
33757
33809
|
...options?.headers || {}
|
|
33758
33810
|
};
|
|
33759
|
-
const response = await fetch(`http://localhost:${ENGINE_PORT}${
|
|
33811
|
+
const response = await fetch(`http://localhost:${ENGINE_PORT}${path8}`, {
|
|
33760
33812
|
...options,
|
|
33761
33813
|
headers,
|
|
33762
33814
|
body: options?.body !== void 0 ? JSON.stringify(options.body) : void 0
|
|
@@ -34029,6 +34081,87 @@ async function mediaUrlCommand(mediaId) {
|
|
|
34029
34081
|
output(response, ({ url: url2 }) => console.log(url2));
|
|
34030
34082
|
}
|
|
34031
34083
|
|
|
34084
|
+
// src/commands/media-gif.ts
|
|
34085
|
+
var import_child_process4 = require("child_process");
|
|
34086
|
+
var import_fs8 = __toESM(require("fs"));
|
|
34087
|
+
var import_path7 = __toESM(require("path"));
|
|
34088
|
+
var import_util3 = require("util");
|
|
34089
|
+
var GIF_MAX_BYTES = 5 * 1024 * 1024;
|
|
34090
|
+
var GIF_ATTEMPTS = 4;
|
|
34091
|
+
var execFileAsync = (0, import_util3.promisify)(import_child_process4.execFile);
|
|
34092
|
+
function parseOption(value, fallback, flag, min, max) {
|
|
34093
|
+
const parsed = value === void 0 ? fallback : Number(value);
|
|
34094
|
+
if (!Number.isFinite(parsed) || parsed < min || parsed > max) {
|
|
34095
|
+
throw new Error(`${flag} must be between ${min} and ${max}, got '${value}'`);
|
|
34096
|
+
}
|
|
34097
|
+
return parsed;
|
|
34098
|
+
}
|
|
34099
|
+
function gifFilter({ fps, width, crop }) {
|
|
34100
|
+
return [
|
|
34101
|
+
crop && `crop=${crop}`,
|
|
34102
|
+
`fps=${fps}`,
|
|
34103
|
+
`scale='min(${width},iw)':-1:flags=lanczos`,
|
|
34104
|
+
// stats_mode=diff spends the palette on what moves, and diff_mode=rectangle only re-encodes changed areas.
|
|
34105
|
+
"split[a][b];[a]palettegen=stats_mode=diff[p];[b][p]paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle"
|
|
34106
|
+
].filter(Boolean).join(",");
|
|
34107
|
+
}
|
|
34108
|
+
async function mediaGifCommand(input, options) {
|
|
34109
|
+
const source = import_path7.default.resolve(input);
|
|
34110
|
+
if (!import_fs8.default.existsSync(source) || !import_fs8.default.statSync(source).isFile()) throw new Error(`File not found: ${source}`);
|
|
34111
|
+
const target = import_path7.default.resolve(options.output ?? `${source.replace(/\.[^./]+$/, "")}.gif`);
|
|
34112
|
+
if (import_path7.default.extname(target).toLowerCase() !== ".gif") throw new Error("--output must end in .gif");
|
|
34113
|
+
if (target === source) throw new Error("--output must differ from the input file");
|
|
34114
|
+
if (options.crop && !/^\d+:\d+:\d+:\d+$/.test(options.crop)) {
|
|
34115
|
+
throw new Error(`--crop must be width:height:x:y in pixels of the recording, got '${options.crop}'`);
|
|
34116
|
+
}
|
|
34117
|
+
const start = parseOption(options.start, 0, "--start", 0, 24 * 60 * 60);
|
|
34118
|
+
const duration3 = parseOption(options.duration, 10, "--duration", 1, 30);
|
|
34119
|
+
const maxWidth = parseOption(options.width, 960, "--width", 200, 1280);
|
|
34120
|
+
const maxFps = parseOption(options.fps, 12, "--fps", 5, 20);
|
|
34121
|
+
const temp = import_path7.default.join(import_path7.default.dirname(target), `.${import_path7.default.basename(target, ".gif")}.${process.pid}.tmp.gif`);
|
|
34122
|
+
let fps = maxFps;
|
|
34123
|
+
let width = maxWidth;
|
|
34124
|
+
try {
|
|
34125
|
+
for (let attempt = 0; attempt < GIF_ATTEMPTS; attempt++) {
|
|
34126
|
+
fps = Math.max(5, Math.round(maxFps * 0.8 ** attempt));
|
|
34127
|
+
width = Math.round(maxWidth * 0.8 ** attempt);
|
|
34128
|
+
await execFileAsync("ffmpeg", [
|
|
34129
|
+
"-v",
|
|
34130
|
+
"error",
|
|
34131
|
+
"-y",
|
|
34132
|
+
"-ss",
|
|
34133
|
+
String(start),
|
|
34134
|
+
"-t",
|
|
34135
|
+
String(duration3),
|
|
34136
|
+
"-i",
|
|
34137
|
+
source,
|
|
34138
|
+
"-vf",
|
|
34139
|
+
gifFilter({ fps, width, crop: options.crop }),
|
|
34140
|
+
"-loop",
|
|
34141
|
+
"0",
|
|
34142
|
+
temp
|
|
34143
|
+
], { timeout: 18e4 }).catch((error51) => {
|
|
34144
|
+
if (error51.code === "ENOENT") throw new Error("ffmpeg is not installed. Install it with `sudo apt-get install -y ffmpeg`.");
|
|
34145
|
+
throw new Error(`ffmpeg failed: ${error51.stderr?.trim() || error51.message}`);
|
|
34146
|
+
});
|
|
34147
|
+
const size = import_fs8.default.statSync(temp).size;
|
|
34148
|
+
if (size <= GIF_MAX_BYTES) {
|
|
34149
|
+
import_fs8.default.renameSync(temp, target);
|
|
34150
|
+
output({ path: target, size, fps, maxWidth: width, start, duration: duration3 }, () => {
|
|
34151
|
+
console.log(`GIF: ${target} (${(size / 1024 / 1024).toFixed(1)} MiB, ${fps} fps, up to ${width}px wide, ${duration3}s from ${start}s, loops)`);
|
|
34152
|
+
console.log(`Next: replicas media upload ${target} --name "<what it shows>", then paste the printed  line in your reply and the PR.`);
|
|
34153
|
+
});
|
|
34154
|
+
return;
|
|
34155
|
+
}
|
|
34156
|
+
}
|
|
34157
|
+
} finally {
|
|
34158
|
+
import_fs8.default.rmSync(temp, { force: true });
|
|
34159
|
+
}
|
|
34160
|
+
throw new Error(
|
|
34161
|
+
`The GIF is still over GitHub's 5 MiB limit at ${fps} fps and ${width}px wide. Show less: a shorter --duration with --start at the interaction, or --crop to the area that changes.`
|
|
34162
|
+
);
|
|
34163
|
+
}
|
|
34164
|
+
|
|
34032
34165
|
// src/commands/history.ts
|
|
34033
34166
|
var import_node_fs2 = require("fs");
|
|
34034
34167
|
var import_node_path2 = require("path");
|
|
@@ -34557,6 +34690,7 @@ if (isAgentMode()) {
|
|
|
34557
34690
|
service.command("stop <name>").description("Stop a service and its whole process group").action(run(serviceStopCommand));
|
|
34558
34691
|
service.command("list").description("List registered services and whether they are running").action(run(serviceListCommand));
|
|
34559
34692
|
service.command("logs <name>").description("Print the last lines of a service log").option("-n, --lines <n>", "Number of lines to print (default 50)").action(run(serviceLogsCommand));
|
|
34693
|
+
media.command("gif <recording>").description("Turn a screen recording into a short looping GIF under GitHub's 5 MiB image limit, lowering fps and width until it fits").option("-o, --output <path>", "Output .gif path (default: the recording path with .gif)").option("--start <seconds>", "Where the GIF starts in the recording (default 0)").option("--duration <seconds>", "Length in seconds, 1-30 (default 10)").option("--width <px>", "Maximum width, 200-1280 (default 960)").option("--fps <n>", "Maximum frame rate, 5-20 (default 12)").option("--crop <w:h:x:y>", "Crop to the region that changes, in recording pixels, before scaling").action(run(mediaGifCommand));
|
|
34560
34694
|
media.command("upload <files...>").description("Upload one or more image, video, audio, or HTML files. Multiple files are uploaded concurrently.").option("-k, --kind <kind>", "Media kind: image, video, audio, or html (inferred from extension if omitted)").option("-s, --session-id <id>", "Session ID to associate the asset with").option(
|
|
34561
34695
|
"-n, --name <name>",
|
|
34562
34696
|
"Required human-facing display name shown in the dashboard. Pass one --name per file, in order.",
|